time zones: get offset from UTC

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

time zones: get offset from UTC

13 Jan 2018, 21:25

- I was interested in a script to calculate the difference between the local time and UTC in hours/minutes/seconds.
- I have a script here that works, although I'd be interested in any more direct methods that use the Winapi.

Code: Select all

q:: ;get time difference between local/UTC time zones
vDate := A_Now
vDateUTC := A_NowUTC
Loop
{
	vDate2 := A_Now
	if (vDate = vDate2)
		break
	vDate := vDate2
	vDateUTC2 := A_NowUTC
	if (vDateUTC = vDateUTC2)
		break
	vDateUTC := vDateUTC2
}
vSec := DateDiff(vDate, vDateUTC, "Seconds")
vSign := (vSec >= 0) ? "+" : "-"
vTime := FormatTime(DateAdd(19990101, Abs(vSec), "Seconds"), "HH:mm:ss")
MsgBox, % vSign vTime
return

;from:
;commands as functions (AHK v2 functions for AHK v1) - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=37&t=29689

DateAdd(DateTime, Time, TimeUnits)
{
    EnvAdd DateTime, %Time%, %TimeUnits%
    return DateTime
}
DateDiff(DateTime1, DateTime2, TimeUnits)
{
    EnvSub DateTime1, %DateTime2%, %TimeUnits%
    return DateTime1
}
FormatTime(YYYYMMDDHH24MISS:="", Format:="")
{
    local OutputVar
    FormatTime OutputVar, %YYYYMMDDHH24MISS%, %Format%
    return OutputVar
}
Last edited by jeeswg on 14 Jan 2018, 05:12, edited 2 times in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: time zones: get offset from UTC

14 Jan 2018, 02:20

- Thanks BoBo. Hmm, I did some work on getting the current time zone, and information for it, mainly based on getting data from the registry, complicated by the fact that you have to write custom code to convert daylight-saving time information to 2 datestamps (a date range).
get DST (daylight-saving time) start/end dates/times in UTC - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=28355
- My script above seems simpler. Perhaps there's a different (third) approach that uses the Winapi.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
Masonjar13
Posts: 1555
Joined: 20 Jul 2014, 10:16
Location: Не Россия
Contact:

Re: time zones: get offset from UTC

14 Jan 2018, 04:10

I believe there is indeed. I've done some of the ground work, but I no longer have time to finish it, so feel free to work on it! If not, I'll try to finish it soon (I certainly have use for it).

I've never used _Struct (by HotKeyIt) before, so I was kind of winging it, likely needs to be edited. And, I just noticed, it looks like the main function (SystemTimeToTzSpecificLocalTime) was also used in that last link, so _Struct could be dropped and replaced with a copy & paste.

Code: Select all

gui,add,text,vgText w200
;gui,show
;setTimer,updateTime,10
return

updateTime:


;guiControl,,gText,% 
return

guiClose:
exitApp

getTimeZone(stdName,dstName:=""){
    local
    static systemTime:=new _Struct("WORD 0
                        ,WORD 0
                        ,WORD 0
                        ,WORD 0
                        ,WORD 0
                        ,WORD 0
                        ,WORD 0
                        ,WORD 0")
    ; clone systemTime
    ; set DST date to systemTime clone (StandardDate param)
    ; clone systemTime
    ; set DaylightDate param to clone
    ; clone systemTime
    ; pass clone to 3rd (out) param in SystemTimeToTzSpecificLocalTime call
    
    static timeZoneInfo:=new _Struct("Long 0
                        ,WChar """ . stdName . """
                        ,UPtr *systemTime[""]
                        ,Long 0
                        ,WChar """ . dstName . """
                        ,UPtr *systemTime[""]
                        ,Long 0")
    
    ; for SystemTimeToTzSpecificLocalTime param 2, use GetSystemTime/GetLocalTime
    dllCall("SystemTimeToTzSpecificLocalTime","UPtr",&,"UPtr",&,"UPtr",&)
    ; return systemTime info from passed clone struct
}

/* resources
https://msdn.microsoft.com/en-us/library/windows/desktop/ms724949(v=vs.85).aspx
https://msdn.microsoft.com/en-us/library/windows/desktop/ms725481(v=vs.85).aspx
https://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx
https://msdn.microsoft.com/en-us/library/windows/desktop/ms725473(v=vs.85).aspx
*/
If you're wondering, the GUI was meant to actively display the time, for testing.
OS: Windows 10 Pro | Editor: Notepad++
My Personal Function Library | Old Build - New Build
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: time zones: get offset from UTC

14 Jan 2018, 04:19

- Thanks Masonjar13.
- Based on this:
SystemTimeToTzSpecificLocalTime function (Windows)
https://msdn.microsoft.com/en-us/librar ... s.85).aspx
The SystemTimeToTzSpecificLocalTime function may calculate the local time incorrectly under the following conditions:
•The time zone uses a different UTC offset for the old and new years.
•The UTC time to be converted and the calculated local time are in different years.
I might be best off sticking with the current script.
- It does make sense though, to start with a time, and convert it, and then compare the two.
- [EDIT:] TzSpecificLocalTimeToSystemTime (local to UTC) doesn't list any possible errors, however if you get a local time, wait a bit, and convert to UTC time, the time zone might have changed in the meantime, and so it's not reliable. Whereas SystemTimeToTzSpecificLocalTime function (UTC to local), should be correct at the moment you run the function (but it has the potential errors mentioned above).
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
Masonjar13
Posts: 1555
Joined: 20 Jul 2014, 10:16
Location: Не Россия
Contact:

Re: time zones: get offset from UTC

14 Jan 2018, 04:57

While the first issue is negligible, the second may or may not be of concern.

Also, I just noticed I slightly misread your OP..

Code: Select all

/*
localNow:=a_now
utcNow:=a_nowUTC
difference:=localNow
difference+=-utcNow
*/
difference:=a_now,difference+=-a_nowUTC
msgbox % difference . "`n`n" . formatTime(difference,"HH:mm:ss")
exitApp

formatTime(dateStamp,format:=""){
    local out,sign
    if(subStr(dateStamp,1,1)="-") ; preserve sign
        dateStamp:=abs(dateStamp),sign:="-"
    while(strLen(dateStamp)<14) ; ensure proper length
        dateStamp:=0 . dateStamp
    formatTime,out,% dateStamp,% format
    return sign . out
}

Edit: shortened the start, added comments.
OS: Windows 10 Pro | Editor: Notepad++
My Personal Function Library | Old Build - New Build
User avatar
Masonjar13
Posts: 1555
Joined: 20 Jul 2014, 10:16
Location: Не Россия
Contact:

Re: time zones: get offset from UTC

15 Jan 2018, 00:11

While my previous code worked, it would only work if the days were the same (I don't understand why). The shorthands for EnvAdd and EnvSub also seem to be touchy with being on the same line as another variable expression (I suppose they technically count as a command?).

The following seems to work without any problems, but they could be lurking..

Code: Select all

msgbox % getUTCOffset(,"HH:mm:ss")
exitApp

getUTCOffset(timeStamp:="",format:="HH:mm"){
    timeStamp:=timeStamp?timeStamp:a_now
    timeStamp-=a_nowUTC,hours
    timeStamp:=timeStamp . 0000
    return formatTime(timeStamp,format)
}
formatTime(dateStamp,format:=""){
    local out,sign
    if(subStr(dateStamp,1,1)="-") ; preserve sign
        dateStamp:=abs(dateStamp),sign:="-"
    while(strLen(dateStamp)<14) ; ensure proper length
        dateStamp:=0 . dateStamp
    formatTime,out,% dateStamp,% format
    return sign . out
}
OS: Windows 10 Pro | Editor: Notepad++
My Personal Function Library | Old Build - New Build
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: time zones: get offset from UTC

17 Jan 2018, 05:07

- I tested SystemTimeToTzSpecificLocalTime. The problem is that in current my time zone, it will just say 0, so I would welcome anyone testing this script and the script in my original post.
- My original script is still better though. This script gets the UTC time, and time will elapse between getting that time and converting it to local time, during which time the time zone could change due to daylight-saving time, therefore, it would be better to retrieve the time multiple times (in this script also) as a check, as I do in my original script.
- People can say that certain edge cases are unlikely, but if I'm going to write a function, I'm going to at least make it as reliable as I can (based on the information I have available). I can understand a script not working correctly around the daylight-saving time changeover period (although potentially my original script can handle this), however, the dll function used here, actually warns about the beginning/end of the year period also, which breaks the principle of least astonishment.
- I tried to make my original script as reliable as possible, if anyone can spot any problems with it, do tell me. Thanks.

Code: Select all

q:: ;test SystemTimeToTzSpecificLocalTime
VarSetCapacity(SYSTEMTIME1, 16, 0)
VarSetCapacity(SYSTEMTIME2, 16, 0)
DllCall("kernel32\GetSystemTime", Ptr,&SYSTEMTIME1)
DllCall("kernel32\SystemTimeToTzSpecificLocalTime", Ptr,0, Ptr,&SYSTEMTIME1, Ptr,&SYSTEMTIME2)
vDateUTC := "", vDate := ""
Loop, 7
	if !(A_Index = 3)
		vDateUTC .= Format("{:02}", NumGet(&SYSTEMTIME1, A_Index*2-2, "UShort"))
		, vDate .= Format("{:02}", NumGet(&SYSTEMTIME2, A_Index*2-2, "UShort"))
vSec := DateDiff(vDate, vDateUTC, "Seconds")
vSign := (vSec >= 0) ? "+" : "-"
vTime := FormatTime(DateAdd(19990101, Abs(vSec), "Seconds"), "HH:mm:ss")
MsgBox, % vSign vTime
return

;from:
;commands as functions (AHK v2 functions for AHK v1) - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=37&t=29689

DateAdd(DateTime, Time, TimeUnits)
{
    EnvAdd DateTime, %Time%, %TimeUnits%
    return DateTime
}
DateDiff(DateTime1, DateTime2, TimeUnits)
{
    EnvSub DateTime1, %DateTime2%, %TimeUnits%
    return DateTime1
}
FormatTime(YYYYMMDDHH24MISS:="", Format:="")
{
    local OutputVar
    FormatTime OutputVar, %YYYYMMDDHH24MISS%, %Format%
    return OutputVar
}
==================================================

- @Masonjar13: Some time zones have offsets that are multiples of 15 minutes.
UTC offset - Wikipedia
https://en.wikipedia.org/wiki/UTC_offset
Every inhabited place in the world has a UTC offset that is a multiple of 15 minutes, and the majority of offsets (as well as all nautical time zones) are measured in whole hours.
- The problem with this line: difference:=a_now,difference+=-a_nowUTC

Code: Select all

q:: ;the problem with applying standard subtraction to datestamps
vDate1 := 19990115000000
vDate2 := 19990114230000
MsgBox, % vDate1-vDate2 ;770000 ;77 hours
MsgBox, % vDate2-vDate1 ;-770000 ;-77 hours

;MsgBox, % DateDiff(vDate1, vDate2, "Hours") ;1
;MsgBox, % DateDiff(vDate2, vDate1, "Hours") ;-1

vDate1 := 19990115000000
vDate2 := 19990115010000
MsgBox, % vDate1-vDate2 ;-10000 ;-1 hour
MsgBox, % vDate2-vDate1 ;10000 ;1 hour

;MsgBox, % DateDiff(vDate1, vDate2, "Hours") ;-1
;MsgBox, % DateDiff(vDate2, vDate1, "Hours") ;1
return
Last edited by jeeswg on 17 Jan 2018, 05:19, edited 1 time in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
just me
Posts: 9458
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: time zones: get offset from UTC

17 Jan 2018, 05:17

I think your original script is reliable if you want to get the offset for the current local time. Calling the Win-API will cause useless overhead in this case.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: time zones: get offset from UTC

17 Jan 2018, 05:42

- A script using the approach mentioned in the 'get DST' link above.
- Although my original script is simpler and with fewer dependencies.

Code: Select all

;[get JEE_TimeZoneGetInfo function from:]
;get DST (daylight-saving time) start/end dates/times in UTC - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=5&t=28355&p=162191#p162191

q:: ;get UTC offset by using the registry
vDate := A_NowUTC
;vDate := A_YYYY "0701000000"
vYear := SubStr(vDate, 1, 4)
RegRead, vTimeZoneKeyName, HKLM\SYSTEM\CurrentControlSet\Control\TimeZoneInformation, TimeZoneKeyName
;MsgBox, % vTimeZoneKeyName
oArray := JEE_TimeZoneGetInfo(vTimeZoneKeyName, vYear)
;MsgBox, % oArray.date1 "`r`n" oArray.date2
vTemp := ((vDate < oArray.date1) || (vDate >= oArray.date2)) ? 1 : 2
vMin := -oArray["offset" vTemp]
;MsgBox, % vMin
vSign := (vMin >= 0) ? "+" : "-"
vTime := FormatTime(DateAdd(19990101, Abs(vMin), "Minutes"), "HH:mm:ss")
MsgBox, % vSign vTime
return

;from:
;commands as functions (AHK v2 functions for AHK v1) - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=37&t=29689

DateAdd(DateTime, Time, TimeUnits)
{
    EnvAdd DateTime, %Time%, %TimeUnits%
    return DateTime
}
DateDiff(DateTime1, DateTime2, TimeUnits)
{
    EnvSub DateTime1, %DateTime2%, %TimeUnits%
    return DateTime1
}
FormatTime(YYYYMMDDHH24MISS:="", Format:="")
{
    local OutputVar
    FormatTime OutputVar, %YYYYMMDDHH24MISS%, %Format%
    return OutputVar
}
- Thanks just me.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
Masonjar13
Posts: 1555
Joined: 20 Jul 2014, 10:16
Location: Не Россия
Contact:

Re: time zones: get offset from UTC

17 Jan 2018, 20:40

I didn't intentionally use direct subtraction, rather, I made the mistake of thinking += and -= would immediately assume dates for a moment.

For what it's worth, I reworked mine to give accurate minutes (probably.. I can't test, since mine has only hours).

Code: Select all

msgbox % getUTCOffset(,"HH:mm:ss")
exitApp

getUTCOffset(timeStamp:="",format:="HH:mm"){
    timeStamp:=timeStamp?timeStamp:a_now,utcStamp:=a_nowUTC
    stamph:=stampm:=timeStamp
    stamph-=utcStamp,hours
    stampm-=utcStamp,minutes
    stampm:=abs(stampm)
    if(strLen(stamph)<3&&subStr(stamph,1,1)="-")
        stamph:="-" . 0 . abs(stamph)
    else if(strLen(stamph)<2)
        stamph:=0 . abs(stamph)
    while(stampm>59)
        stampm-=60
    timeStamp:=stamph . (strLen(stampm)<2?0 . stampm:stampm) . 00
    return formatTime(timeStamp,format)
}
formatTime(dateStamp,format:=""){
    local out,sign
    if(subStr(dateStamp,1,1)="-") ; preserve sign
        dateStamp:=abs(dateStamp),sign:="-"
    while(strLen(dateStamp)<14) ; ensure proper length
        dateStamp:=0 . dateStamp
    formatTime,out,% dateStamp,% format
    return sign . out
}
OS: Windows 10 Pro | Editor: Notepad++
My Personal Function Library | Old Build - New Build

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: jeves, mikeyww and 293 guests