Jump to content
Sign in to follow this  
orbs

TimeConvert UDF - convert UTC to/from local time, and/or reformat the string representation

Recommended Posts

orbs
A single function to convert UTC to/from local time, and/or change the time string representation format.
 
the function accepts a time string (in various formats), a conversion flag, existing input format, and desired output format. all parameters are optional.
 
Note #1: It is understood that core functionality of this UDF can be achieved by the built-in _Date_Time_* functions of the Date UDF - but these are too complex to be used, unless you are a programmer experienced with DLL structs and pointers.
 
Note #2: UTC conversion will return incorrect results for dates for which your system has no DST configured. for example, dates earlier than 1970, or dates in the not-too-near future, or years where your country changed it's DST settings for political reasons and it was not updated in retrospect by Microsoft.
 
UDF (v2.2):
#include-Once
#include 'TimeConvertConstants.au3'

; #INDEX# =======================================================================================================================
; Title .........: TimeConvert
; AutoIt Version : 3.3.10.2
; UDF Version ...: 2.2
; Status ........: Production
; Language ......: English
; Description ...: A single function to convert UTC to/from local time, and/or change the time string representation format.
;                  It is understood that core functionality of this UDF can be achieved by the built-in _Date_Time_* functions of
;                  the Date UDF - but these are too complex to be used, unless you are a programmer experienced with DLL structs
;                  and pointers.
; Dll ...........: kernel32.dll
; Author(s) .....: orbs
; ===============================================================================================================================

; #CURRENT# =====================================================================================================================
;_TimeConvert
; ===============================================================================================================================

; #FUNCTION# ====================================================================================================================
; Name ..........: _TimeConvert
; Description ...: Converts UTC to/from local time, and/or changes the time string representation format.
; Syntax.........: _TimeConvert([$sTime = ''[, $iUTC_Convert = $__TIMECONVERT_CONVERT_NONE[, $sFormatInput = $__TIMECONVERT_FORMAT_SYSTEM[, $sFormatOutput = $__TIMECONVERT_FORMAT_SYSTEM]]]])
; Parameters ....: $sTime         - [optional] A string representation of the time to process.
;                  $iUTC_Convert  - [optional] Instructs the function to convert $sTime as follows:
;                    $__TIMECONVERT_CONVERT_NONE (0)          - (default) Do not convert
;                    $__TIMECONVERT_CONVERT_UTC_TO_LOCAL (1)  - Convert from UTC to local time
;                    $__TIMECONVERT_CONVERT_LOCAL_TO_UTC (-1) - Convert from local time to UTC
;                  $sFormatInput  - [optional] Specifies the format of $sTime as follows:
;                    $__TIMECONVERT_FORMAT_SYSTEM ("YYYYMMDDHHNNSS") - (default) 14-digits time stamp.
;                    $__TIMECONVERT_FORMAT_LOGICAL ("YYYY/MM/DD HH:NN:SS")
;                    $__TIMECONVERT_FORMAT_UK ("DD/MM/YYYY HH:NN:SS")
;                    $__TIMECONVERT_FORMAT_US ("MM/DD/YYYY HH:NN:SS")
;                    $__TIMECONVERT_FORMAT_LOGICAL_WIDE ("YYYY/MM/DD  HH:NN:SS")
;                    $__TIMECONVERT_FORMAT_UK_WIDE ("DD/MM/YYYY  HH:NN:SS")
;                    $__TIMECONVERT_FORMAT_US_WIDE ("MM/DD/YYYY  HH:NN:SS")
;                    $__TIMECONVERT_FORMAT_US_LITERAL_LONG ("MMMM DTH, YYYY, H:NN PM")
;                    $__TIMECONVERT_FORMAT_US_LITERAL_SHORT ("MMM-DD YYYY, H:NN PM")
;                  $sFormatOutput - [optional] Specifies the desired format of the return value. Use same values as $sFormatInput
; Return values .: Success - Returns the conversion result.
;                  Failure - Returns the partly-processed input and sets @error to 1.
; Author ........: orbs
; Modified ......:
; Remarks .......: - Constants are defined in the file "TimeConvertConstants.au3".
;                  - The predefined formats for $sFormatInput and $sFormatOutput are common but not exhaustive, and you can
;                    define your own custom formats as you see fit.
;                  - Note that WIDE values for $sFormatInput and $sFormatOutput have two spaces between date and time substrings.
;                    You can find the wide format commonly used by Excel.
;                  - All parameters are optional; if all are omitted, the return value is the current local time as a 14-digits
;                    time stamp ("YYYYMMDDHHNNSS").
; Related .......:
; Link ..........:
; Example .......: Yes
; ===============================================================================================================================
Func _TimeConvert($sTime = '', $iUTC_Convert = $__TIMECONVERT_CONVERT_NONE, $sFormatInput = $__TIMECONVERT_FORMAT_SYSTEM, $sFormatOutput = $__TIMECONVERT_FORMAT_SYSTEM)

    ; >>> bug workaround = for some reason, default values do not apply when script passes "Default" as parameter
    If $sTime = '' Then $sTime = @YEAR & @MON & @MDAY & @HOUR & @MIN & @SEC
    If $iUTC_Convert = Default Then $iUTC_Convert = $__TIMECONVERT_CONVERT_NONE
    If $sFormatInput = Default Then $sFormatInput = $__TIMECONVERT_FORMAT_SYSTEM
    If $sFormatOutput = Default Then $sFormatOutput = $__TIMECONVERT_FORMAT_SYSTEM
    ; >>> end of bug workaround

    ; sanitize input for default format
    If $sFormatInput = $__TIMECONVERT_FORMAT_SYSTEM And (StringLen($sTime) <> 14 Or Not StringIsDigit($sTime)) Then Return SetError(1, 0, $sTime)

    Local Const $tagSYSTEMTIME = 'struct;word Year;word Month;word Dow;word Day;word Hour;word Minute;word Second;word MSeconds;endstruct'
    Local $sYYYY, $sYY, $sMMMM, $sMMM, $sMM, $sDTH, $sDD, $sD, $sHH, $sH, $sPM, $sNN, $sSS
    Local $aMonths[12] = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
    Local $iMonth
    Local $iMonthNameMaxLength = 9 ; length of "September"
    Local $tSystemTime_BeforeConversion, $tSystemTime_AfterConversion
    If $sFormatInput <> $__TIMECONVERT_FORMAT_SYSTEM Then
        $sYYYY = StringMid($sTime, StringInStr($sFormatInput, 'YYYY', 1), 4)
        If $sYYYY = '' Then $sYYYY = @YEAR
        $sYY = StringRight($sYYYY, 2)
        $sMMMM = StringMid($sTime, StringInStr($sFormatInput, 'MMMM', 1), $iMonthNameMaxLength)
        If $sMMMM = '' Then ; no long month, maybe there is abbr month
            $sMMM = StringMid($sTime, StringInStr($sFormatInput, 'MMM', 1), 3)
            If $sMMM = '' Then ; no abbr month, maybe there is numeric month
                $sMM = StringMid($sTime, StringInStr($sFormatInput, 'MM', 1), 2)
            Else ; there is abbr month, process it
                For $iMonth = 0 To UBound($aMonths) - 1
                    If StringLeft($aMonths[$iMonth], 3) = $sMMM Then $sMM = StringFormat('%02i', $iMonth + 1)
                Next
            EndIf
        Else ; there is long month, process it
            For $iMonth = 0 To UBound($aMonths) - 1
                If $aMonths[$iMonth] = StringLeft($sMMMM, StringLen($aMonths[$iMonth])) Then $sMM = StringFormat('%02i', $iMonth)
            Next
        EndIf
        If $sMM = '' Then $sMM = @MON
        $sDD = StringMid($sTime, StringInStr($sFormatInput, 'DD', 1), 2)
        If $sDD = '' Then ; no DD, maybe there is DTH
            $sDTH = StringMid($sTime, StringInStr($sFormatInput, 'DTH', 1), 4)
            If $sDTH = '' Then ; no DTH, maybe there is D
                $sD = StringMid($sTime, StringInStr($sFormatInput, 'D', 1), 2)
                If StringIsDigit($sD) Then ; 2-digits day
                    $sDD = $sD
                ElseIf StringIsDigit(StringLeft($sD, 1)) Then ; 1-digit day
                    $sDD = '0' & StringLeft($sD, 1)
                EndIf
            Else ; DTH
                If StringIsDigit(StringMid($sDTH, 2, 1)) Then ; 2-digits day
                    $sDD = StringLeft($sDTH, 2)
                Else ; 1-digit day
                    $sDD = '0' & StringLeft($sDTH, 1)
                EndIf
            EndIf
        EndIf
        If Number($sDD) = 0 Then $sDD = @MDAY
        $sHH = StringMid($sTime, StringInStr($sFormatInput, 'HH', 1), 2)
        If $sHH = '' Then ; no HH, maybe there is H
            $sH = StringMid($sTime, StringInStr($sFormatInput, 'H', 1), 2)
            If StringIsDigit($sH) Then ; 2-digits hour
                $sHH = $sH
            ElseIf StringIsDigit(StringLeft($sH, 1)) Then ; 1-digit hour
                $sHH = '0' & StringLeft($sH, 1)
            Else
                $sHH = @HOUR
            EndIf
        EndIf
        If StringInStr($sFormatInput, 'PM', 1) And StringInStr($sTime, 'pm', 1) Then $sHH = StringFormat('%02i', Number($sHH) + 12)
        $sNN = StringMid($sTime, StringInStr($sFormatInput, 'NN', 1), 2)
        If $sNN = '' Then $sNN = @MIN
        $sSS = StringMid($sTime, StringInStr($sFormatInput, 'SS', 1), 2)
        If $sSS = '' Then $sSS = @SEC
        $sTime = $sYYYY & $sMM & $sDD & $sHH & $sNN & $sSS
    EndIf
    If Not (StringIsDigit($sTime) And StringLen($sTime) = 14) Then Return SetError(1, 0, $sTime)
    If $iUTC_Convert = $__TIMECONVERT_CONVERT_LOCAL_TO_UTC Or $iUTC_Convert = $__TIMECONVERT_CONVERT_UTC_TO_LOCAL Then
        $sYYYY = StringLeft($sTime, 4)
        $sMM = StringMid($sTime, 5, 2)
        $sDD = StringMid($sTime, 7, 2)
        $sHH = StringMid($sTime, 9, 2)
        $sNN = StringMid($sTime, 11, 2)
        $sSS = StringMid($sTime, 13, 2)
        $tSystemTime_BeforeConversion = DllStructCreate($tagSYSTEMTIME)
        DllStructSetData($tSystemTime_BeforeConversion, 'Month', $sMM)
        DllStructSetData($tSystemTime_BeforeConversion, 'Day', $sDD)
        DllStructSetData($tSystemTime_BeforeConversion, 'Year', $sYYYY)
        DllStructSetData($tSystemTime_BeforeConversion, 'Hour', $sHH)
        DllStructSetData($tSystemTime_BeforeConversion, 'Minute', $sNN)
        DllStructSetData($tSystemTime_BeforeConversion, 'Second', $sSS)
        $tSystemTime_AfterConversion = DllStructCreate($tagSYSTEMTIME)
        If $iUTC_Convert = $__TIMECONVERT_CONVERT_LOCAL_TO_UTC Then
            DllCall('kernel32.dll', 'bool', 'TzSpecificLocalTimeToSystemTime', 'ptr', 0, 'ptr', DllStructGetPtr($tSystemTime_BeforeConversion), 'struct*', $tSystemTime_AfterConversion)
        Else
            DllCall('kernel32.dll', 'bool', 'SystemTimeToTzSpecificLocalTime', 'ptr', 0, 'ptr', DllStructGetPtr($tSystemTime_BeforeConversion), 'struct*', $tSystemTime_AfterConversion)
        EndIf
        $sTime = StringFormat('%04d%02d%02d%02d%02d%02d', _
                DllStructGetData($tSystemTime_AfterConversion, 'Year'), _
                DllStructGetData($tSystemTime_AfterConversion, 'Month'), _
                DllStructGetData($tSystemTime_AfterConversion, 'Day'), _
                DllStructGetData($tSystemTime_AfterConversion, 'Hour'), _
                DllStructGetData($tSystemTime_AfterConversion, 'Minute'), _
                DllStructGetData($tSystemTime_AfterConversion, 'Second'))
    EndIf
    If $sFormatOutput <> $__TIMECONVERT_FORMAT_SYSTEM Then
        $sYYYY = StringLeft($sTime, 4)
        $sYY = StringRight($sYYYY, 2)
        $sMM = StringMid($sTime, 5, 2)
        $sMMMM = $aMonths[Number($sMM) - 1]
        $sMMM = StringLeft($sMMMM, 3)
        $sDD = StringMid($sTime, 7, 2)
        $sD = String(Number($sDD))
        Switch $sD
            Case '1'
                $sDTH = $sD & 'st'
            Case '2'
                $sDTH = $sD & 'nd'
            Case Else
                $sDTH = $sD & 'th'
        EndSwitch
        $sHH = StringMid($sTime, 9, 2)
        $sPM = 'am'
        If StringInStr($sFormatOutput, 'PM', 1) And Number($sHH) > 12 Then
            $sHH = StringFormat('%02i', Number($sHH) - 12)
            $sPM = 'pm'
        EndIf
        $sH = String(Number($sHH))
        $sNN = StringMid($sTime, 11, 2)
        $sSS = StringMid($sTime, 13, 2)
        $sTime = $sFormatOutput
        $sTime = StringReplace($sTime, 'YYYY', $sYYYY, 0, 1)
        $sTime = StringReplace($sTime, 'YY', $sYY, 0, 1)
        $sTime = StringReplace($sTime, 'DTH', $sDTH, 0, 1)
        $sTime = StringReplace($sTime, 'DD', $sDD, 0, 1)
        $sTime = StringReplace($sTime, 'D', $sD, 0, 1)
        $sTime = StringReplace($sTime, 'HH', $sHH, 0, 1)
        $sTime = StringReplace($sTime, 'H', $sH, 0, 1)
        $sTime = StringReplace($sTime, 'PM', $sPM, 0, 1)
        $sTime = StringReplace($sTime, 'NN', $sNN, 0, 1)
        $sTime = StringReplace($sTime, 'SS', $sSS, 0, 1)
        $sTime = StringReplace($sTime, 'MMMM', $sMMMM, 0, 1)
        $sTime = StringReplace($sTime, 'MMM', $sMMM, 0, 1)
        $sTime = StringReplace($sTime, 'MM', $sMM, 0, 1)
    EndIf
    Return $sTime
EndFunc   ;==>_TimeConvert

 

constants:

#include-once

; #INDEX# =======================================================================================================================
; Title .........: TimeConvert_Constants
; AutoIt Version : 3.3.10.2
; Description ...: Constants for the TimeConvert UDF (v2.x)
; Author(s) .....: orbs
; ===============================================================================================================================

; #CONSTANTS# ===================================================================================================================
; UTC/local convertion instructions
Global Const $__TIMECONVERT_CONVERT_NONE = 0
Global Const $__TIMECONVERT_CONVERT_UTC_TO_LOCAL = 1
Global Const $__TIMECONVERT_CONVERT_LOCAL_TO_UTC = -1
; common string formats for time representation
Global Const $__TIMECONVERT_FORMAT_SYSTEM = 'YYYYMMDDHHNNSS'
Global Const $__TIMECONVERT_FORMAT_LOGICAL = 'YYYY/MM/DD HH:NN:SS'
Global Const $__TIMECONVERT_FORMAT_UK = 'DD/MM/YYYY HH:NN:SS'
Global Const $__TIMECONVERT_FORMAT_US = 'MM/DD/YYYY HH:NN:SS'
Global Const $__TIMECONVERT_FORMAT_LOGICAL_WIDE = 'YYYY/MM/DD  HH:NN:SS'
Global Const $__TIMECONVERT_FORMAT_UK_WIDE = 'DD/MM/YYYY  HH:NN:SS'
Global Const $__TIMECONVERT_FORMAT_US_WIDE = 'MM/DD/YYYY  HH:NN:SS'
Global Const $__TIMECONVERT_FORMAT_US_LITERAL_LONG = 'MMMM DTH, YYYY, H:NN PM'
Global Const $__TIMECONVERT_FORMAT_US_LITERAL_SHORT = 'MMM-DD YYYY, H:NN PM'
; ===============================================================================================================================

 

example script:

#AutoIt3Wrapper_Au3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7
#include 'TimeConvert.au3'
Global $sTimeStamp_Local = _TimeConvert()
Global $sTimeStamp_Random = Random(1970, 2038, 1) & StringFormat('%02i', Random(1, 12, 1)) & StringFormat('%02i', Random(1, 28, 1)) & StringFormat('%02i', Random(0, 23, 1)) & StringFormat('%02i', Random(0, 59, 1)) & StringFormat('%02i', Random(0, 59, 1))
MsgBox(0, 'TimeConvert UDF demo', _
        'Local Time :' & @TAB & $sTimeStamp_Local & @CRLF & _
        'UTC Description :' & @TAB & _TimeConvert($sTimeStamp_Local, $__TIMECONVERT_CONVERT_LOCAL_TO_UTC, Default, $__TIMECONVERT_FORMAT_US_LITERAL_LONG) & @CRLF & _
        @CRLF & _
        'Random Time :' & @TAB & $sTimeStamp_Random & @CRLF & _
        'UTC, UK-style :' & @TAB & _TimeConvert($sTimeStamp_Random, $__TIMECONVERT_CONVERT_LOCAL_TO_UTC, Default, $__TIMECONVERT_FORMAT_UK))

 

Edited by orbs
  • Like 2
  • Thanks 1

Share this post


Link to post
Share on other sites
orbs

released v2.0 - updated in first post:

Note: backward compatibility with v1.x is not maintained!

if you are using it only to convert local to/from UTC, than no change. if you use custom formats, then you need to change MN (the "minute" indicator) to NN.

change log - v2.0 :

added components indicators:
    YY    => last two digits of the year
    MMM    => month 3-letters appreviation
    MMMM    => month full name
    D    => allows single digit for day
    DTH    => adds day suffix "st","nd","th" to "D"
    H    => allows single digit for hour
    PM    => converts HH from 24h to 12h and adds "am" or "pm"
added prefixed formats:
    ...US_LITERAL_LONG
    ...US_LITERAL_SHORT
modified:
    MN to NN
    components indicators must be uppercase
bugfix:
    handle poorly formatted input
    default values do not apply
    a component must have default value
 

Share this post


Link to post
Share on other sites
orbs

released v2.2 - updated in first post:

bugfix: when hour ("HH") is specifically given as "00", it is treated as current hour (@HOUR)

 

previous changes of unreleased version 2.1:

sanitize input for default format
update function header with new formats of v2.0
 

Share this post


Link to post
Share on other sites
Tankbuster

Nice, thx for sharing. I like especially the extra constant file. Easy to adjust/enhance without touching the UDF itself.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×