关于c#:. NET:考虑夏令时

.NET: Accounting for daylight savings

我有一个方法,它使用用户输入创建一个UTC DateTime,使用其地理位置的GMT偏移量:

1
2
3
4
5
6
7
8
9
10
11
12
public static DateTime LocalToUtc
    (int year, int month, int day, int hour, decimal gmtOffset) {

    // argument validation here

    var dateTime = new DateTime(year, month, day).AddHours(hour);
    var dateTimeOffset =
        new DateTimeOffset(dateTime, TimeSpan.FromHours(gmtOffset));

    return dateTimeOffset.UtcDateTime;

}

问题是,如果该功能在用户时区内节约了日光,那么它将关闭一小时。

因此,虽然我的个人格林威治标准时间偏移量是-8,但由于日光节约,当前时区偏移量是-7。

如何将上述功能更改为夏令时节省?难道我不需要从gmt偏移量中创建一些时区对象并得到它的时区偏移量吗?


在不知道实际时区的情况下是无法做到这一点的:几个时区具有相同的基础UTC偏移量,但夏令时的规则不同。例如,西欧标准时间和中非标准时间的偏移量都是+01:00,但前者支持DST,后者不支持,所以偏移量不足以决定DST是否适用……

您的方法应该使用一个TimeZoneInfo参数,而不是gmtOffset参数。这样,您只需使用TimeZoneInfo.ConvertTime方法转换日期,它将自动考虑DST。


datetime已经有了这样的方法:ToLocalTime()ToUniversalTime()。用那个有什么问题?

编辑:

基于作者希望从当前计算机时区以外的时区转换为UTC的评论,我建议您参阅此处的John Skeets答案

来自msdn文档:

1
2
3
4
5
6
7
8
string displayName ="(GMT+06:00) Antarctica/Mawson Time";
string standardName ="Mawson Time";
TimeSpan offset = new TimeSpan(06, 00, 00);
TimeZoneInfo mawson = TimeZoneInfo.CreateCustomTimeZone(standardName,
    offset, displayName, standardName);
Console.WriteLine("The current time is {0} {1}",
                  TimeZoneInfo.ConvertTime(DateTime.Now,
                       TimeZoneInfo.Local, mawson), mawson.StandardName);


因为听起来你在要求用户提供一个时间偏移量,而这个时间偏移量可能不一定在机器的本地时区内,所以本地机器时间不起作用。但是,使用TimeZoneInfo类,您应该能够构造一个实例来说明偏移量和DST状态,并从中使用内置方法。

编辑:至少在我的机器上,TimeZoneInfo.GetSystemTimeZones()似乎返回了所有有效的时区。这可以很容易地映射到下拉菜单以允许用户选择。


如果不想使用内置的UTC方法,应该使用TimeZone.GetUtcOffset方法。

http://msdn.microsoft.com/en-us/library/system.timezone.getutcoffset.aspx

它将为您提供到UTC的偏移量。您还可以使用内置方法从本地时间获取UTC时间。

http://msdn.microsoft.com/en-us/library/system.datetime.touniversaltime(v=vs.100).aspx