﻿# 釐清觀念：.NET 日期結構(DateTime) 與 時區轉換

昨晚為了將 AD 中的日期屬性讀出來費了好大一番功夫，由於 AD 中的 [Lockout-Time Attribute](http://msdn.microsoft.com/en-us/library/ms676843.aspx) 格式為長度 8 bytes 的長整數型別，時間單位以 100ns 為單位，日期從 UTC 時間的 1601/1/1 00:00:00 起算，然而將時間轉出來後卻突然被時區轉換的問題給搞亂了，因此也趁機將 [DateTime](http://msdn.microsoft.com/zh-tw/library/system.datetime.aspx) 研究了一番。

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/124cec1b084983ee85c2-image.png)

首先，我先透過 [Active Directory Explorer](http://technet.microsoft.com/en-us/sysinternals/bb963907.aspx) 查出該屬性的時間為 2010/4/20 上午 06:24:20 (如上圖)，但不管怎麼轉換時區都無法用**漂亮的方法**轉換成我本地的時區，有時還會差異到 16 小時之多，我當時搞混的地方在於當我建立 [DateTime](http://msdn.microsoft.com/zh-tw/library/system.datetime.aspx) 時在指定 [DateTime.Kind 屬性](http://msdn.microsoft.com/zh-tw/library/system.datetime.kind.aspx)後，輸出的結果是一模一樣的 ( 2010/4/19 下午 10:24:20 )，然後多轉換幾次之後頭腦就昏了。如下程式：

```
DateTime d1 = (new DateTime(1601,1,1,0,0,0, DateTimeKind.Local)).AddTicks(129161894600456800L);
```

```
DateTime d2 = (new DateTime(1601,1,1,0,0,0, DateTimeKind.Utc)).AddTicks(129161894600456800L);
```

可能是寫程式寫太晚，又多測了好幾個帳號，時間感就整個亂掉了，所以白花了好多時間查問題，到現在寫這篇文章時感覺好像在說廢話一樣，看文章的人也可能會覺得「不是本來就是這樣嗎？」，但是寫 Code 的當下基本上就是一整個腦袋打結。 :-p

上述程式若執行 d1.ToString() 輸出結果都會是：2010/4/19 下午 10:24:20

-   如果我們執行 d1.ToLocalTime() 輸出的結果會是 2010/4/19 下午 10:24:20
-   如果我們執行 d1.ToUniversalTime() 輸出的結果會是 2010/4/19 下午 02:24:20

這些時間都不是我們要的，我們再看看 d2 的輸出結果：

-   如果我們執行 d2.ToLocalTime() 輸出的結果會是 2010/4/20 上午 06:24:20 ( 正確答案 )
-   如果我們執行 d2.ToUniversalTime() 輸出的結果會是 2010/4/19 下午 10:24:20

最後，我們再來看看時區的變化狀況：

-   執行 .ToLocalTime() 會將目前的 DateTime 轉換為「本地時間」，當 d1 本身是 Local 的情況，本地時間當然與取得的時間一致，所以不會有變化。而 d2 本身已經宣告為 UTC 時間，所以當執行 .ToLocalTime() 時就會將目前的 DateTime 透過 **本地時間** 與 **UTC 時間** 的差距(Offset)重新運算 ( +0800 )，並回傳在本機當時的時間點，而這個時間就是我們要的時間了。
-   執行 .ToUniversalTime() 會將目前的 DateTime 轉換為「 UTC 時間」，當 d1 本身是 Local 的情況，在取得 UTC 時間時就會將目前的 DateTime 透過 **本地時間** 與 **UTC 時間** 的差距(Offset)重新運算 ( -0800 )，所以得到的時間就是詭異的 2010/4/19 下午 02:24:20 時間，等於跟我們現在的本地時間差了 16 小時之多（當時就是這裡卡關的）。

對於 .NET 對於時間的知識建議可參考 MSDN 上 [時間和時區](http://msdn.microsoft.com/zh-tw/library/bb384268.aspx) 的說明，相信可以學習並認識更多對於時間的觀念，其中 [在 DateTime、DateTimeOffset 和 TimeZoneInfo 之間選擇](http://msdn.microsoft.com/zh-tw/library/bb384267.aspx) 對於時區轉換的觀念也有很大的幫助。

**相關連結**

-   [時間和時區](http://msdn.microsoft.com/zh-tw/library/bb384268.aspx)

-   [在 DateTime、DateTimeOffset 和 TimeZoneInfo 之間選擇](http://msdn.microsoft.com/zh-tw/library/bb384267.aspx)

-   [DateTime 結構](http://msdn.microsoft.com/zh-tw/library/system.datetime.aspx)
-   [DateTime.Kind 屬性](http://msdn.microsoft.com/zh-tw/library/system.datetime.kind.aspx)
-   [Time Zone Converter - Time & Time Zone Conversion](http://www.timezoneconverter.com/cgi-bin/tzc.tzc)
