Dot-Net

DateTime - 奇怪的夏令時行為

  • March 1, 2012

我的本地時區是 (UTC+10:00) 堪培拉、墨爾本、悉尼

2012 年 3 月 31 日星期六 15:59 UTC = 2012 年 4 月 1 日星期日 02:59 +11:00

2012 年 3 月 31 日星期六 16:00 UTC = 2012 年 4 月 1 日星期日 02:00 +10:00

夏令時在 4 月的第一個星期日凌晨 3 點結束,時鐘回撥 1 小時。

給定以下程式碼….

DateTime dt1 = DateTime.Parse("31-Mar-2012 15:59", CultureInfo.CurrentCulture, DateTimeStyles.AssumeUniversal);

DateTime dt2 = DateTime.Parse("31-Mar-2012 15:59", CultureInfo.CurrentCulture, DateTimeStyles.AssumeUniversal).AddMinutes(1);
DateTime dt3 = DateTime.Parse("31-Mar-2012 16:00", CultureInfo.CurrentCulture, DateTimeStyles.AssumeUniversal);

Console.WriteLine("{0:yyyy-MMM-dd HH:mm:ss.ffff K}", dt1);
Console.WriteLine("{0:yyyy-MMM-dd HH:mm:ss.ffff K} ({1}) = {2:yyyy-MMM-dd HH:mm:ss.ffff K} ({3})", dt2, dt2.Kind, dt3, dt3.Kind);
Console.WriteLine("{0} : {1} : {2}", dt1.ToUniversalTime().Hour, dt2.ToUniversalTime().Hour, dt3.ToUniversalTime().Hour);

我得到以下輸出

2012 年 4 月 1 日 02:59:00.0000 +11:00

2012 年 4 月 1 日 03:00:00.0000 +10:00(本地)= 2012 年 4 月 1 日 02:00:00.0000 +10:00(本地)

15 : 17 : 16

在原始日期時間上增加 1 分鐘會使當地時間為凌晨 3 點,但也會將偏移量設置為 +10 小時。將 1 分鐘添加到 UTC 日期並正確解析將本地時間設置為凌晨 2 點,並帶有 +10 UTC 偏移量。

重複

DateTime dt1 = new DateTime(2012, 03, 31, 15, 59, 0, DateTimeKind.Utc);

DateTime dt2 = new DateTime(2012, 03, 31, 15, 59, 0, DateTimeKind.Utc).AddMinutes(1);
DateTime dt3 = new DateTime(2012, 03, 31, 16, 0, 0, DateTimeKind.Utc);

要麼

DateTime dt1 = DateTime.Parse("31-Mar-2012 15:59", CultureInfo.CurrentCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);

DateTime dt2 = DateTime.Parse("31-Mar-2012 15:59", CultureInfo.CurrentCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal).AddMinutes(1);
DateTime dt3 = DateTime.Parse("31-Mar-2012 16:00", CultureInfo.CurrentCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal); 

2012-Mar-31 15:59:00.0000 Z

2012-Mar-31 16:00:00.0000 Z (Utc) = 2012-Mar-31 16:00:00.0000 Z (Utc)

15:16:16

正如預期的那樣

再次重複

DateTime dt1 = new DateTime(2012, 03, 31, 15, 59, 0, DateTimeKind.Utc).ToLocalTime();

DateTime dt2 = new DateTime(2012, 03, 31, 15, 59, 0, DateTimeKind.Utc).ToLocalTime().AddMinutes(1);
DateTime dt3 = new DateTime(2012, 03, 31, 16, 0, 0, DateTimeKind.Utc).ToLocalTime();

給出原來的

2012 年 4 月 1 日 02:59:00.0000 +11:00

2012 年 4 月 1 日 03:00:00.0000 +10:00(本地)= 2012 年 4 月 1 日 02:00:00.0000 +10:00(本地)

15 : 17 : 16

誰能解釋一下?

不雅地,如果我使用 TimeZoneInfo 從 UTC 轉換為 AUS 東部標準時間,我會得到正確的時間,但我會失去 DateTime 實例中的偏移資訊,因為 DateTime.Kind == DateTimeKind.Unspecified

== 要突出顯示的其他場景

這只是簡單的時間跨度添加,從非模棱兩可的 UTC 日期開始,在夏令時結束前 1 分鐘。

DateTime dt1 = new DateTime(2012, 03, 31, 15, 59, 0, DateTimeKind.Utc);  
DateTime dt2 = new DateTime(2012, 03, 31, 15, 59, 0, DateTimeKind.Utc).ToLocalTime();  

Console.WriteLine("Original in UTC     : {0:yyyy-MMM-dd HH:mm:ss.ffff K}", dt1);  
Console.WriteLine("Original in Local   : {0:yyyy-MMM-dd HH:mm:ss.ffff K}", dt1.ToLocalTime());  
Console.WriteLine("+ 1 Minute in Local : {0:yyyy-MMM-dd HH:mm:ss.ffff K}", dt1.AddMinutes(1).ToLocalTime());  
Console.WriteLine("+ 1 Minute in UTC   : {0:yyyy-MMM-dd HH:mm:ss.ffff K}", dt1.AddMinutes(1));  
Console.WriteLine("=====================================================");
Console.WriteLine("Original in UTC     : {0:yyyy-MMM-dd HH:mm:ss.ffff K}", dt2.ToUniversalTime());  
Console.WriteLine("Original in Local   : {0:yyyy-MMM-dd HH:mm:ss.ffff K}", dt2);  
Console.WriteLine("+ 1 Minute in Local : {0:yyyy-MMM-dd HH:mm:ss.ffff K}", dt2.AddMinutes(1));  
Console.WriteLine("+ 1 Minute in UTC   : {0:yyyy-MMM-dd HH:mm:ss.ffff K}", dt2.AddMinutes(1).ToUniversalTime());  

UTC 原文:2012-Mar-31 15:59:00.0000 Z

本地原文:2012-Apr-01 02:59:00.0000 +11:00

  • 本地 1 分鐘:2012-Apr-01 02 :00:00.0000 + UTC 時間10:00

  • 1 分鐘:2012 年 3 月 31 日16 :00:00.0000 Z

=====================================================

UTC 原文:2012-Mar-31 15:59:00.0000 Z

本地原文:2012-Apr-01 02:59:00.0000 +11:00

  • 本地 1 分鐘:2012-Apr-01 03 :00:00.0000 + UTC 時間10:00

  • 1 分鐘:2012 年 3 月 31 日17 :00:00.0000 Z

我認為問題在於何時執行轉換。

您正在解析假設通用時間,但隨後隱式轉換為“本地”類型 - 值為 2:59:59。當您要求“本地”值添加一分鐘時,它只是在本地值上添加一分鐘,而不考慮時區。然後,當您列印偏移量時,系統會嘗試在當地時間凌晨 3 點計算出偏移量……這是 +10。

如此有效地你得到了:

  • 解析步驟 1:將字元串視為通用字元串(15:59 UTC)
  • 解析步驟 2:將結果轉換為本地(本地 2:59)
  • 補充:在本地時間,不應用時區值(本地 3:00)
  • 格式化步驟 1:請求偏移量,因此計算本地時間映射到的時間(17:00 UTC)
  • 格式化步驟 2:計算偏移量作為本地和通用之間的差異 (+10)

是的,這有點痛苦 -DateTime總的來說很痛苦,這是我寫Noda Time的主要原因,其中“區域中的日期/時間”與“本地日期/時間”(或“本地日期”或“本地時間”),很明顯您在任何時候都在使用哪個。

我不清楚你在這裡實際想要實現什麼 - 如果你能更具體一點,我可以向你展示你在野田時間會做什麼,儘管可能存在一些固有的歧義(從本地日期/時間轉換為“ zoned" 日期/時間可以有 0、1 或 2 個結果)。

編輯:如果目標只是記住時區和瞬間,在野田時間你想要ZonedDateTime,像這樣:

using System;
using NodaTime;

class Program
{
   static void Main(string[] args)
   {
       var zone = DateTimeZone.ForId("Australia/Melbourne");
       ZonedDateTime start = Instant.FromUtc(2012, 3, 31, 15, 59, 0)
                                    .InZone(zone);
       ZonedDateTime end = start + Duration.FromMinutes(1);

       Console.WriteLine("{0} ({1})", start.LocalDateTime, start.Offset);
       Console.WriteLine("{0} ({1})", end.LocalDateTime, end.Offset);
   }
}

有關更多資訊,請參閱有關日曆算術的註釋。

引用自:https://stackoverflow.com/questions/9525929