Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

[SAMPLE] Dealing with time zones (AHK_L)


  • Please log in to reply
1 reply to this topic
just me
  • Members
  • 1496 posts
  • Last active: Nov 03 2015 04:32 PM
  • Joined: 28 May 2011
Searching the forum for SystemTimeToTzSpecificLocalTime and TzSpecificLocalTimeToSystemTime I've got no answers, so I've written my own sample script:

#NoEnv
; ----------------------------------------------------------------------------------------------------------------------
RegTimeZones := GetTimeZones()
; ----------------------------------------------------------------------------------------------------------------------
Gui, Margin, 20, 20
Gui, Add, DateTime, w200 1 vLDT, yyyy-MM-dd HH:mm:ss
Gui, Add, Text, x+10 yp w300 hp 0x200 vLTX, *Local Time*
Gui, Add, Button, x+0 yp w90 hp gConvert1, Convert
Gui, Add, DateTime, xm y+5 w200 1 Readonly vCDT, yyyy-MM-dd HH:mm:ss
Gui, Add, Text, x+10 yp w300 hp 0x200 vCTX, *Local Time*
Gui, Add, Button, x+0 yp w90 hp gConvert2, Convert
Gui, Add, ListView, xm Grid -Hdr -Multi w600 r20 gSelect vLV hwndHLV, 1|2
LV_Add("", "*Local Time*")
For Key, Value In RegTimeZones
   LV_Add("", Key, Value[1])
Loop, 2
   LV_ModifyCol(A_Index, "AutoHdr")
Gui, Add, StatusBar
Gui, Show, , Timezones
Return
; ----------------------------------------------------------------------------------------------------------------------
GuiClose:
GuiEscape:
ExitApp
; ----------------------------------------------------------------------------------------------------------------------
Select:
   If (A_GuiEvent = "DoubleClick") {
      SB_SetText("")
      RowIndex := LV_GetNext(0)
      If !(RowIndex)
         Return
      LV_GetText(ZoneTo, RowIndex)
      If (ZoneTo == "*Local Time*")
         Return
      If !RegTimeZones.HasKey(ZoneTo)
         Return
      SB_SetText("RegTZI: " . RegTimeZones[ZoneTo][2])
   }
Return

; ----------------------------------------------------------------------------------------------------------------------
Convert1:
   RowIndex := LV_GetNext(0)
   If !(RowIndex)
      Return
   LV_GetText(ZoneTo, RowIndex)
   If (ZoneTo <> "*Local Time*")
      If !RegTimeZones.HasKey(ZoneTo)
         Return
   GuiControlGet, ZoneFrom, , LTX
   GuiControlGet, LocalTime, , LDT
   ZoneTime := ConvertTime(LocalTime, ZoneFrom, ZoneTo, RegTimeZones)
   GuiControl, , LDT, %ZoneTime%
   GuiControl, , LTX, %ZoneTo%
   LocalTime := ZoneTime
   ZoneFrom := ZoneTo
   GuiControlGet, ZoneTo, , CTX
   ZoneTime := ConvertTime(LocalTime, ZoneFrom, ZoneTo, RegTimeZones)
   GuiControl, , CDT, %ZoneTime%
   GuiControl, Focus, LV
Return
; ----------------------------------------------------------------------------------------------------------------------
Convert2:
   RowIndex := LV_GetNext(0)
   If !(RowIndex)
      Return
   LV_GetText(ZoneTo, RowIndex)
   If (ZoneTo <> "*Local Time*")
      If !RegTimeZones.HasKey(ZoneTo)
         Return
   GuiControlGet, ZoneFrom, , LTX
   GuiControlGet, LocalTime, , LDT
   ZoneTime := ConvertTime(LocalTime, ZoneFrom, ZoneTo, RegTimeZones)
   GuiControl, , CDT, %ZoneTime%
   GuiControl, , CTX, %ZoneTo%
   GuiControl, Focus, LV
Return
; ----------------------------------------------------------------------------------------------------------------------
GetTimeZones() {
   ; Get the "Time Zones" entries from registry
   RegRoot := "HKEY_LOCAL_MACHINE"
   RegKey  := "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones"
   RegTimeZones := {}
   Loop, %RegRoot%, %RegKey%, 2
   {
      RegRead, DSP, %RegRoot%, %RegKey%\%A_LoopRegName%, Display
      RegRead, TZI, %RegRoot%, %RegKey%\%A_LoopRegName%, TZI
      RegTimeZones[A_LoopRegName] := [DSP, TZI]
   }
   Return RegTimeZones
}
; ----------------------------------------------------------------------------------------------------------------------
ConvertTime(TimeStamp, TimeZoneFrom, TimeZoneTo, ByRef TimeZones) {
   TimeStamp += 0, S
   VarSetCapacity(LOCTIME, 16, 0)    ; SYSTEMTIME (local)
   VarSetCapacity(SYSTIME, 16, 0)    ; SYSTEMTIME (system\UTC)
   NumPut(SubStr(TimeStamp,  1, 4), LOCTIME,  0, "UShort")
   NumPut(SubStr(TimeStamp,  5, 2), LOCTIME,  2, "UShort")
   NumPut(SubStr(TimeStamp,  7, 2), LOCTIME,  6, "UShort")
   NumPut(SubStr(TimeStamp,  9, 2), LOCTIME,  8, "UShort")
   NumPut(SubStr(TimeStamp, 11, 2), LOCTIME, 10, "UShort")
   NumPut(SubStr(TimeStamp, 13, 2), LOCTIME, 12, "UShort")
   PTZIF := 0
   PTZIT := 0
   If (TimeZoneFrom <> "*Local Time*") {
      TZIF := ""
      TZI2TIMEZONEINFORMATION(TimeZones[TimeZoneFrom][2], TZIF)
      PTZIF := &TZIF
   }
   If (TimeZoneTo <> "*Local Time*") {
      TZIT := ""
      TZI2TIMEZONEINFORMATION(TimeZones[TimeZoneTo][2], TZIT)
      PTZIT := &TZIT
   }
   DllCall("Kernel32\TzSpecificLocalTimeToSystemTime", "Ptr", PTZIF, "Ptr", &LOCTIME, "Ptr", &SYSTIME)
   DllCall("Kernel32\SystemTimeToTzSpecificLocalTime", "Ptr", PTZIT, "Ptr", &SYSTIME, "Ptr", &LOCTIME)
   Year  := SubStr("000" . NumGet(LOCTIME, 0, "Short"), -3)
   Month := SubStr("0" . NumGet(LOCTIME, 2, "Short"), -1)
   Day   := SubStr("0" . NumGet(LOCTIME, 6, "Short"), -1)
   Hour  := SubStr("0" . NumGet(LOCTIME, 8, "Short"), -1)
   Min   := SubStr("0" . NumGet(LOCTIME, 10, "Short"), -1)
   Sec   := SubStr("0" . NumGet(LOCTIME, 12, "Short"), -1)
   Return Year . Month . Day . Hour . Min . Sec
}
; ----------------------------------------------------------------------------------------------------------------------
TZI2TIMEZONEINFORMATION(TZI, ByRef TIMEZONEINFORMATION) {
   ; Convert registry TZI values into TIMEZONEINFORMATION struct
   Bias := 0      ; Bias
   StdD := 68     ; StandardDate
   StdB := 84     ; StandardBias
   DltD := 152    ; DaylightDate
   DltB := 168    ; DaylightBias
   VarSetCapacity(TIMEZONEINFORMATION, 172, 0)
   IR := 1
   IT := Bias     ; Bias ------------------------------------------------
   Loop, 4 {
      NumPut("0x" . SubStr(TZI, IR, 2), TIMEZONEINFORMATION, IT, "UChar")
      IR += 2
      IT++
   }
   IT := StdB     ; StandardBias ----------------------------------------
   Loop, 4 {
      NumPut("0x" . SubStr(TZI, IR, 2), TIMEZONEINFORMATION, IT, "UChar")
      IR += 2
      IT++
   }
   IT := DltB     ; DaylightBias ----------------------------------------
   Loop, 4 {
      NumPut("0x" . SubStr(TZI, IR, 2), TIMEZONEINFORMATION, IT, "UChar")
      IR += 2
      IT++
   }
   IT := StdD     ; StandardDate ----------------------------------------
   Loop, 16 {
      NumPut("0x" . SubStr(TZI, IR, 2), TIMEZONEINFORMATION, IT, "UChar")
      IR += 2
      IT++
   }
   IT := DltD     ; DaylightDate ----------------------------------------
   Loop, 16 {
      NumPut("0x" . SubStr(TZI, IR, 2), TIMEZONEINFORMATION, IT, "UChar")
      IR += 2
      IT++
   }
}
MS made some changes for the registry entries as well as the time functions in Win Vista and 7. The script does not make use of these changes. It seems to work properly with XP and Vista using AHK 1.1 U 32.

iPhilip
  • Members
  • 138 posts
  • Last active: Sep 12 2015 06:27 PM
  • Joined: 03 Jun 2010

Thank  you! I used portions of it to put together the following functions to convert from Epoch time to local time (factoring in DST):

TZI2TIMEZONEINFORMATION("UTC")   ; This only has to be called once
FormatTime, Time, % GetLocalTime(1429303500)
MsgBox %Time%
Return

GetLocalTime(EpochTime) {
   global TZIS
   TimeStamp := 19700101000000
   TimeStamp += EpochTime, Seconds
   VarSetCapacity(LOCTIME,  16, 0)   ; SYSTEMTIME (local)
   VarSetCapacity(SYSTIME,  16, 0)   ; SYSTEMTIME (system\UTC)
   NumPut(SubStr(TimeStamp,  1, 4), LOCTIME,  0, "UShort")
   NumPut(SubStr(TimeStamp,  5, 2), LOCTIME,  2, "UShort")
   NumPut(SubStr(TimeStamp,  7, 2), LOCTIME,  6, "UShort")
   NumPut(SubStr(TimeStamp,  9, 2), LOCTIME,  8, "UShort")
   NumPut(SubStr(TimeStamp, 11, 2), LOCTIME, 10, "UShort")
   NumPut(SubStr(TimeStamp, 13, 2), LOCTIME, 12, "UShort")
   DllCall("Kernel32\TzSpecificLocalTimeToSystemTime", "Ptr", &TZIS, "Ptr", &LOCTIME, "Ptr", &SYSTIME)
   DllCall("Kernel32\SystemTimeToTzSpecificLocalTime", "Ptr",     0, "Ptr", &SYSTIME, "Ptr", &LOCTIME)
   Year  := SubStr("000" . NumGet(LOCTIME,  0, "Short"), -3)
   Month := SubStr("0"   . NumGet(LOCTIME,  2, "Short"), -1)
   Day   := SubStr("0"   . NumGet(LOCTIME,  6, "Short"), -1)
   Hour  := SubStr("0"   . NumGet(LOCTIME,  8, "Short"), -1)
   Min   := SubStr("0"   . NumGet(LOCTIME, 10, "Short"), -1)
   Sec   := SubStr("0"   . NumGet(LOCTIME, 12, "Short"), -1)
   Return Year . Month . Day . Hour . Min . Sec
}

TZI2TIMEZONEINFORMATION(TZ) {
   global TZIS
   Bias := 0      ; Bias
   StdD := 68     ; StandardDate
   StdB := 84     ; StandardBias
   DltD := 152    ; DaylightDate
   DltB := 168    ; DaylightBias
   ; Read the time zone registry information
   RegRoot := "HKEY_LOCAL_MACHINE"
   RegKey  := "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\" TZ
   RegRead, TZI, %RegRoot%, %RegKey%, TZI
   ; Create TZIS struct
   VarSetCapacity(TZIS, 172, 0)
   IR := 1
   IT := Bias     ; Bias ---------------------------------
   Loop, 4 {
      NumPut("0x" . SubStr(TZI, IR, 2), TZIS, IT, "UChar")
      IR += 2
      IT++
   }
   IT := StdB     ; StandardBias -------------------------
   Loop, 4 {
      NumPut("0x" . SubStr(TZI, IR, 2), TZIS, IT, "UChar")
      IR += 2
      IT++
   }
   IT := DltB     ; DaylightBias -------------------------
   Loop, 4 {
      NumPut("0x" . SubStr(TZI, IR, 2), TZIS, IT, "UChar")
      IR += 2
      IT++
   }
   IT := StdD     ; StandardDate -------------------------
   Loop, 16 {
      NumPut("0x" . SubStr(TZI, IR, 2), TZIS, IT, "UChar")
      IR += 2
      IT++
   }
   IT := DltD     ; DaylightDate -------------------------
   Loop, 16 {
      NumPut("0x" . SubStr(TZI, IR, 2), TZIS, IT, "UChar")
      IR += 2
      IT++
   }
}

Windows 7 Pro (64 bit) - AutoHotkey v1.1+ (Unicode 32-bit)