c#daylight savings重复小时转换为UTC

时间:2011-06-02 12:41:15

标签: c# time dst

我正在使用TimeZoneInfo在客户端wallclock'Eastern Time'和UTC之间进行转换。我的问题是在秋季DST更改期间发生的“重复”小时。

在从UTC转换为东部期间:
2010-11-07 06:00 UTC - >给出2010-11-07T 01 :00:00-03:30
2010-11-07 07:00 UTC - >给出2010-11-07T 01 :00:00-03:30
我怎么知道哪个是第一个小时,哪个是第二个小时? DateTime.IsDaylightSavingTime()在两个小时都返回false,但是第一个小时它不应该返回true吗?

同样,我如何存储 2010-11-07 01:00:00 -03:30?我的应用如何转换为UTC,因为它可能是2010-11-07 06 :00或2010-11-07 07 :00

对于那些需要代码的人,我骑自行车穿过一个带有UTC日期时间列的数据表,尝试使用'DupHr'列转换为东部第二个重复小时,但我总是在01:00时结束' DupHr'= 1.

    TimeZoneInfo est = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");

    DateTime EasternTime;
    DateTime DuplicateHour = new DateTime(2010, 11, 7, 1, 0, 0);  // hard coded for this example
    TimeZoneInfo.AdjustmentRule[] rules =  est.GetAdjustmentRules();

    foreach (DataRow row in dt.Rows)
    {
        row["DupHr"] = 0;  // by default not duplicate hour
        EasternTime = TimeZoneInfo.ConvertTimeFromUtc((DateTime)row[UTCColumnName], est);
        if (!EasternTime.IsDaylightSavingTime())
        {
            if (EasternTime.Equals(DuplicateHour ))
            {
                row["DupHr"] = 1;   // This is the second duplicate hour !
            }
        } else

            EasternTime.Add(rules[1].DaylightDelta);  // Add DST offset from rule #1

        row[newESTColumnName] = EasternTime;        
    }

谢谢!

解决方案

重要的是要知道重复小时的“模棱两可”。小时必须是唯一的(第一和第二)。考虑一个收费站货币柜台应用程序,它必须全天候运行并累计每小时的收集。每小时收集的钱必须是可识别的。第一小时1:00至1:59与第二小时1:00至1:59小时不同。 isSecondHour 以下的例程仅在传递时间为秋季DST更改的小时时才返回true。用户界面可以适当地显示该标志。

 // Get the DST rule for the year and zone  (rules may change from year to year as in 2004)
    public static TimeZoneInfo.AdjustmentRule GetDSTrule(int Year, TimeZoneInfo zone)
    {
        TimeZoneInfo.AdjustmentRule[] rules = zone.GetAdjustmentRules();

        foreach (TimeZoneInfo.AdjustmentRule rul in rules)
        {
            if (rul.DateStart < new DateTime(Year, 1, 1) && rul.DateEnd > new DateTime(Year, 1, 1))
            {
                return rul;
            }
        }
        return null;
    }

    // Determine if 'localtime' is in the second duplicate DST hour.
    public static Boolean isSecondHour(TimeZoneInfo localzone, DateTime localtime, DateTime UTCtime)
    {

        if (localzone.IsAmbiguousTime(localtime))
        {
            TimeZoneInfo.AdjustmentRule rul = GetDSTrule(localtime.Year, localzone);
            return UTCtime.Add(localzone.GetUtcOffset(localtime)) == localtime;
        }
        else
            return false;
    }


    static void Main(string[] args)
    {
        var est = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");

        var times = new DateTime[] {
        new DateTime (2010, 11, 7, 3,  0, 0, DateTimeKind.Unspecified),
        new DateTime (2010, 11, 7, 4,  0, 0, DateTimeKind.Unspecified),
        new DateTime (2010, 11, 7, 5,  0, 0, DateTimeKind.Unspecified),
        new DateTime (2010, 11, 7, 5,  30, 0, DateTimeKind.Unspecified),
        new DateTime (2010, 11, 7, 6,  0, 0, DateTimeKind.Unspecified),
        new DateTime (2010, 11, 7, 6,  30, 0, DateTimeKind.Unspecified),
        new DateTime (2010, 11, 7, 7,  0, 0, DateTimeKind.Unspecified),
        new DateTime (2010, 11, 7, 8,  0, 0, DateTimeKind.Unspecified)

    };

    DateTime EasternTime;
    Console.WriteLine("UTC Time  |  Est Time   | IsDaylightSaving | IsAmbiguousTime | isSecondHour ");

    foreach (var utc in times)
    {
        // Get Eastern Time from UTC using standard convert routine.
        EasternTime = TimeZoneInfo.ConvertTimeFromUtc(utc, est);
        Console.WriteLine("{0:HH:mm}     |   {1:HH:mm}     | {2,11}      |      {3,5}      |      {4,5}", utc,EasternTime, est.IsDaylightSavingTime(EasternTime), est.IsAmbiguousTime(EasternTime),isSecondHour(est,EasternTime, utc));
     }

结果

UTC Time  |  Est Time   | IsDaylightSaving | IsAmbiguousTime | isSecondHour
03:00     |   23:00     |        True      |      False      |      False
04:00     |   00:00     |        True      |      False      |      False
05:00     |   01:00     |       False      |       True      |      False
05:30     |   01:30     |       False      |       True      |      False
06:00     |   01:00     |       False      |       True      |       True
06:30     |   01:30     |       False      |       True      |       True
07:00     |   02:00     |       False      |      False      |      False
08:00     |   03:00     |       False      |      False      |      False

2 个答案:

答案 0 :(得分:11)

答案 1 :(得分:0)

所以在讨论之后,我现在有两个例程,一个用于指示UTC时间是否是我的本地时区的'Duplicate'小时以及将 Eastern转换为UTC 的例程。检索数据时,客户端应用程序可以使用 isSecondHour '例程来适当地显示时间。同样,在将时间保存到服务器时,客户端必须提供 second_DST_hour 标志以及本地时间,以便将它们转换为UTC。

    // Determine if 'localtime' is in the second duplicate DST hour.
    public static Boolean isSecondHour(TimeZoneInfo localzone, DateTime localtime, DateTime UTCtime)
    {     
        if (localzone.IsAmbiguousTime(localtime))
        {
            // UTC time + UTC offset = second hour time (not first hour)
            return UTCtime.Add(localzone.GetUtcOffset(localtime)) == localtime;
        }
        else
            return false;
    }

    // Convert Local time to UTC, with 'SecondDST' indicating if hour is the second hour of autumn DST change.
    public static DateTime Convert_to_UTC(TimeZoneInfo localzone, DateTime localtime, Boolean SecondDST)
    {
        DateTime newUTC = TimeZoneInfo.ConvertTimeToUtc(localtime, localzone);
        if (localzone.IsAmbiguousTime(localtime) && !SecondDST)
        {
            TimeZoneInfo.AdjustmentRule rul = GetDSTrule(localtime.Year, localzone);
            return newUTC.Add(-rul.DaylightDelta);
        }
        else
            return newUTC;
     }


  // Get the DST rule for the year and zone  (rules may change from year to year as in 2004)
        public static TimeZoneInfo.AdjustmentRule GetDSTrule(int Year, TimeZoneInfo zone)
        {
            TimeZoneInfo.AdjustmentRule[] rules = zone.GetAdjustmentRules();
            foreach (TimeZoneInfo.AdjustmentRule rul in rules)
            {
                if (rul.DateStart < new DateTime(Year, 1, 1) && rul.DateEnd > new DateTime(Year, 1, 1))
                {
                    return rul;
                }
            }
            return null;
        }

然后使用这些:

       var est = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");

        var times = new DateTime[] {
        new DateTime (2010, 11, 7, 3,  0, 0, DateTimeKind.Unspecified),
        new DateTime (2010, 11, 7, 4,  0, 0, DateTimeKind.Unspecified),
        new DateTime (2010, 11, 7, 5,  0, 0, DateTimeKind.Unspecified),
        new DateTime (2010, 11, 7, 5,  30, 0, DateTimeKind.Unspecified),
        new DateTime (2010, 11, 7, 6,  0, 0, DateTimeKind.Unspecified),
        new DateTime (2010, 11, 7, 6,  30, 0, DateTimeKind.Unspecified),
        new DateTime (2010, 11, 7, 7,  0, 0, DateTimeKind.Unspecified),
        new DateTime (2010, 11, 7, 8,  0, 0, DateTimeKind.Unspecified)

    };
    // ------------------ UTC to Eastern  

    DateTime EasternTime;
    Console.WriteLine("UTC Time  |  Est Time   | IsDaylightSaving | IsAmbiguousTime | isSecondHour ");

    foreach (var utc in times)
    {
        // Get Eastern Time from UTC using standard convert routine.
        EasternTime = TimeZoneInfo.ConvertTimeFromUtc(utc, est);
        Console.WriteLine("{0:HH:mm}     |   {1:HH:mm}     | {2,11}      |      {3,5}      |      {4,5}", utc,EasternTime, est.IsDaylightSavingTime(EasternTime), est.IsAmbiguousTime(EasternTime),isSecondHour(est,EasternTime, utc));
     }

        // ------------------ Eastern  to UTC    
    DateTime testTime;
    Console.WriteLine("UTC Time  |  Est Time   | IsDaylightSaving | IsAmbiguousTime | isSecondHour ");
    EasternTime = new DateTime(2010, 11, 7, 1, 30, 0, DateTimeKind.Unspecified);

    // First Hour of DST
    testTime = Convert_to_UTC (est, EasternTime,false);
    Console.WriteLine("{0:HH:mm}     |   {1:HH:mm}     | {2,11}      |      {3,5}      |      {4,5}", testTime, EasternTime, est.IsDaylightSavingTime(EasternTime), est.IsAmbiguousTime(EasternTime), isSecondHour(est, EasternTime, testTime));

    // Second Hour of DST
    testTime = Convert_to_UTC(est, EasternTime, true);
    Console.WriteLine("{0:HH:mm}     |   {1:HH:mm}     | {2,11}      |      {3,5}      |      {4,5}", testTime, EasternTime, est.IsDaylightSavingTime(EasternTime), est.IsAmbiguousTime(EasternTime), isSecondHour(est, EasternTime, testTime));