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

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

Share this post


Link to post
Share on other sites

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

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

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  

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...