关于c#:如何使用ASP.NET中的时区?

How to work with time zones in ASP.NET?

我正在开发一个"在线提醒系统"项目(ASP.NET 2.0(C)/SQL Server 2005)

因为这是一个提醒服务,它将在特定日期向用户发送邮件。但问题是,用户不是来自特定国家,而是来自世界各地和不同时区。现在,当我注册时,我要求用户使用时区,就像安装时Windows要求我们使用时区一样。

但是我不知道用户是否选择了(+5.30)或什么时区,那么如何在我的ASP.NET应用程序中处理这个时区。如何根据时区工作。

请建议是否有更好的方法来处理这个应用程序中的时区??

谢谢


首先,要确保您的数据位于哪个时区。我建议确保您存储的任何日期时间都存储在UTC时间中(使用DateTime.ToUniversalTime()来获取它)。

当您要为用户存储提醒时,您将需要当前的UTC时间,添加或删除用户的时区差异,并将新时间转换回UTC;这是您要在数据库中存储的内容。

然后,当您要检查要发送的提醒时,您只需根据UTC时间在数据库中查找要发送的提醒;基本上,获取所有具有时间戳的提醒,该时间戳在DateTime.Now.ToUniversalTime()之前。

更新一些实施细节:您可以从TimeZoneInfo.GetSystemTimeZones()方法中获得时区列表;您可以使用这些列表为用户显示时区列表。如果从所选时区存储Id属性,则可以从中创建TimeZoneInfo类实例,并计算给定本地日期/时间值的UTC时间:

1
2
3
4
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById("<the time zone id>");
// May 7, 08:04:00
DateTime userDateTime = new DateTime(2009, 5, 7, 8, 4, 0);
DateTime utcDateTime = userDateTime.Subtract(tzi.BaseUtcOffset);


我建议在服务器端始终使用UTC(GMT)时间(代码隐藏、数据库等),并将时间从UTC转换为本地时间,仅用于显示目的。这意味着所有时间操作(包括在数据库中节省时间、执行计算等)都应该使用UTC完成。

问题是:您的代码隐藏如何知道客户机浏览器的时区?假设用户在表单中输入了一些日期/时间值(例如12/30/2009 14:30),并将其提交给服务器。假设用户提交了本地时间,服务器如何知道如何将该值转换为UTC?

应用程序可以要求用户指定时区(并将其保存在持久的cookie或数据库中),但它需要用户付出额外的努力,并且您的应用程序需要为此实现逻辑和屏幕。如果应用程序能自动确定客户端的时区,那就更好了。

我在javascript的getTimeZoneOffset函数的帮助下解决了这个问题,它是唯一一个可以告诉服务器客户端本地时间和GMT之间时间差的API。因为这是客户端API,所以我做了以下操作:在服务器端检查保存时间偏移值的自定义会话cookie,如果它s不可用,重新加载页面(仅在get调用期间,而不是post调用期间),添加一些javascript逻辑以生成时间偏移量并将其保存在cookie中。从客户端来看,这几乎是透明的(在会话期间,我会在GET上重新加载一个页面)。一旦我在cookie中有了偏移量,我就会根据时间转换的方向(UTC到本地时间,或本地时间到UTC)将其应用到时间管理功能中。

这听起来可能有点复杂,但在我编写助手函数之后,将这个功能集成到站点中只需要在页面加载(需要时间转换的页面)中进行一次调用,并在向浏览器发送和检索时间值时使用时间转换例程。下面是一个如何使用它的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
using My.Utilities.Web;
...

// Derive the form class from BaseForm instead of Page.
public class WebForm1: BaseForm
{
...
private void Page_Load(object sender, System.EventArgs e)
{
  // If we only want to load the page to generate the time
  // zone offset cookie, we do not need to do anything else.
  if (InitializeLocalTime())
    return;

  // Assume that txtStartDate is a TextBox control.
  if (!IsPostback)
  {
     // To display a date-time value, convert it from GMT (UTC)
     // to local time.
     DateTime startDate = GetStartDateFromDB(...);
     txtStartDate.Text  = FormatLocalDate(startDate);
     ...
  }
  else
  {
     // To save a date-time value, convert it from local
     // time to GMT (UTC).
     DateTime tempDate  = DateTime.Parse(txtStartDate.Text);
     DateTime startDate = ConvertLocalTimeToUtc(tempDate);
     SaveStartDateInDB(startDate, ...);
     ...
  }
}
...
}

如果您需要更详细的信息,请查看关于时间的信息:在ASP.NET应用程序文章中本地化时间(很抱歉,但我没有到发布者网站上文章的直接链接,因为ASP.NetPro仅限制对付费订户的访问;但是有到PDF副本的链接)。我希望我可以发布文章中的示例,但我不想侵犯版权;但是,这里有一个项目来构建一个具有所有必要功能和文档的助手库(忽略您不需要的东西)。

更新:这篇文章已经由新的发布者在网上发布了示例项目。


到目前为止,所有答案的问题在于,他们没有考虑到普拉尚特正在努力实现的目标。如果在夏令时更改前一天的系统用户的偏移量为+12,并为第二天设置了提醒,则应触发提醒时的偏移量将为+13。

这就是为什么您只能对正在发生的事情使用当前偏移量的原因。尽管我同意所有其他人的观点,但服务器端(可能仅用于显示的服务器端除外)应始终存储在UTC中。


如果您在Framework 2.0或更高版本上,您可能希望使用datetimeoffset结构而不是datetime。

datetimeoffset表示相对于UTC时间的时间点,因此在这种情况下应该更容易处理。


有两个步骤:

  • 使用javascript在客户端检测不同的时区:

    1
    2
    var dt = new Date();
    var diffInMinutes = -dt.getTimezoneOffset();
  • 然后在服务器端,C代码根据检测到的上述时区偏移量将服务器时间转换为客户端时间:

--------------------;

1
2
3
4
5
6
string queryStr = Request.QueryString["diffInMinutes"];
int diffInMinutes = 0;
if (Int32.TryParse(queryStr, out diffInMinutes))
{
    clientTime = serverTime.ToUniversalTime().AddMinutes(diffInMinutes);
}


问题是,与UTC的时差在一年中的不同时间会有所不同——每个时区都有自己的规则。(在开发会议室调度应用程序时,我学到了这一点。)

似乎有内置支持:http://msdn.microsoft.com/en-us/library/system.timezoneinfo.converttime.aspx

我自己也没试过,但它似乎保证了正确的转换,为夏令时节省了费用。

如果没有,这里有一个(昂贵的)商业工具我已经使用:http://www.worldtimeserver.com/time_zone_guide/


基本上,您需要做的就是将偏移量(小时+分钟)添加到用户输入的本地时间。加入偏移量基本上会给您一个以UTC(基本上是格林威治标准时间)时区为单位的日期时间。

通常最容易将所有时间标准化为UTC,这样应用程序逻辑就不必处理偏移量。

本页有几个好例子:http://msdn.microsoft.com/en-us/library/bb546099.aspx