2017年7月19日

時區轉換失敗


今天碰到一個問題,程式要轉換時間的時候找不到時區,第三方程式丟過來的時區資訊是MET( Middle European Time ),找了方法除了寫程式去處理例外、用第三方元件,最可靠的應該是下面這個方法了。
下圖就是找不到時區時會丟出的錯誤:

圖一











要做的是自行新增登錄檔,他位於 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\這個資料夾裡面,到這個資料夾下就可以看到很多時區的資訊。

圖二




















點一個來看,有下面這些登錄值:
圖三






仿照他做一個新的,Display、Dlt和Std是描述,是字串值,直接編輯,沒問題。
再來三個MUI開頭的值,是用tzres.dll中的resource檔,後面的數字是resource的key值,目前沒辦法新增,但這個不影響轉換,只影響時區資訊的顯示,
例如:
圖四

在cmd中打上指令tzutil /l (列出本機上所有時區資訊),可以看到我新增的兩個時區VIncent time、Vincent Test Time中面的描述跟上面的Central Europe Standard Time一樣,就是因為MUI開頭的值,後面dll的字串值用的跟Central Europe Standard Time相同,好在他不影響轉換的計算,所以沒關係。

resource的key和value可以參考下面這個網站(這win10的,win7以前的要找自己另外找,不過大同小異啦,就是比win10少了一些而已)

真正會影響計算的值是TZI,他的值和資料結構如下:
圖五


typedef struct _REG_TZI_FORMAT
{
    LONG Bias;
    LONG StandardBias;
    LONG DaylightBias;
    SYSTEMTIME StandardDate;
    SYSTEMTIME DaylightDate;
} REG_TZI_FORMAT;
typedef struct _SYSTEMTIME {  
    WORD wYear;  
    WORD wMonth;  
    WORD wDayOfWeek;  
    WORD wDay;  
    WORD wHour;  
    WORD wMinute;  
    WORD wSecond;  
    WORD wMilliseconds;  
} SYSTEMTIME; 
WORD佔2Byte,SYSTEMTIME總共2*8 = 16Byte,
LONG佔4Byte,所以TZI_FORMAT佔了4*3 + 16*2 = 44 Byte符合上面值共44Byte
計笡可以看這個網頁,各欄位的詳細定義
TIME_ZONE_INFORMATION structure

看起來要計算很麻煩,但其實可以不用計算,因為大部份時區都有,所以直接找一個位於相同時區的,將他的TZI值照著寫進去就可以了。

上面這些東西最初是從這裡來的,也可以直接去看這個網頁
Exploring Windows Time Zones with System.TimeZoneInfo [Josh Free]

最後在圖二中,其實可以看到有些時區還有子資料夾[Dynamic DST],這個應該是記錄歷史的日光節約時間的,有變更都是windows update做的,我的目的只是要現在轉換成功,而且我做的這個,剛好沒有日光節約的間,有日光節約時間轉換也ok,(應該主要是參照TZI這個值來算,是不是歷史的會去套用到這個資料夾下的機碼我就沒有測試了),先不理他…。


沒有留言: