DateTime - 奇怪的夏令時行為
我的本地時區是 (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); } }有關更多資訊,請參閱有關日曆算術的註釋。