Jump to content

Update system time based on NTP server time


CYCho
 Share

Recommended Posts

On 10/28/2019 at 5:20 AM, CYCho said:

@TheXman After several hours of googling, I came up with the following code for calculating fractions of NTP time in millisecs. Your review and comment will be appreciated.

$iMilliSecs = Int(Dec(Hex(BinaryMid($xResponse, 45, 4)), $NUMBER_64BIT)/2^32*1000)
$iMilliSecs = StringFormat("%03i", $iMilliSecs)

 

Very nice! :thumbsup: 

It looks almost exactly like the solution that I came up with.  The only difference between yours and mine is that I round the milliseconds.

$iSeconds  = Dec(Hex(BinaryMid($xResponse, 41, 4)), $NUMBER_64BIT) ; seconds since 1900-01-01 00:00:00
$iFraction = Dec(Hex(BinaryMid($xResponse, 45, 4)), $NUMBER_64BIT) ; picosec = 1 trillionth of a second (10^-12)
$iMsecs    = Round($iFraction / 2^32 * 1000)                       ; round to the nearest integer

My full script is below:

Spoiler
#include <Constants.au3>
#include <date.au3>


ntp_example()

Func ntp_example()
    Const $NTP_SERVER   = "time.windows.com"
    Const $MY_TZ_OFFSET = -5 ; Timezone offset in hours (

    Local $tBuffer
    Local $aSocket
    Local $xRequest = Binary(""), $xResponse = Binary("")
    Local $sTimestampLocal = "", $sTimestampUTC = ""
    Local $hTimeoutTimer
    Local $iSeconds = 0, $iFraction = 0, $iMillisecs = 0

    ; Create the NTP request using a 48 byte buffer
    $tBuffer = DllStructCreate("byte[48]")
    DllStructSetData($tBuffer, 1, 0x23) ; 00 100 011 = LI(0) / VN(4-NTPv4) / Mode(3-Client)

    ; Copy the buffer to a variable for sending
    $xRequest = DllStructGetData($tBuffer, 1)
    write_log_line("DEBUG: Binary request  = " & $xRequest)

    ; Send NTP request
    UDPStartup()
    If @error Then Exit MsgBox($MB_ICONERROR, "ERROR", "UDPStartup failed - @error = " & @error)
    OnAutoItExitRegister("udp_shutdown")

    $aSocket = UDPOpen(TCPNameToIP($NTP_SERVER), 123)
    If @error Then Exit MsgBox($MB_ICONERROR, "ERROR", "UDPOpen failed - @error = " & @error)

    UDPSend($aSocket, $xRequest)
    If @error Then Exit MsgBox($MB_ICONERROR, "ERROR", "UDPSend failed - @error = " & @error)

    ; Receive NTP response
    $hTimeoutTimer = TimerInit()
    Do
        If TimerDiff($hTimeoutTimer) > 2000 Then ExitLoop ; If no response within 2 seconds, then exit the loop

        $xResponse = UDPRecv($aSocket, DllStructGetSize($tBuffer), $UDP_DATA_BINARY)
        If @error Then Exit MsgBox($MB_ICONERROR, "ERROR", "UDPRecv failed - @error = " & @error)
    Until $xResponse <> Binary("")

    write_log_line("DEBUG: Binary response = " & Binary($xResponse))

    ; Close the socket
    UDPCloseSocket($aSocket)

    ; If the request timed out, exit with a message
    If $xResponse = Binary("") Then Exit MsgBox($MB_ICONERROR, "ERROR", "UDPRecv timed out")

    ; Parse & display timestamp values
    ; - Current time is calculated from the xmit timestamp in NTP response header
    ; - Xmit timestamp seconds is a big-endian, uint32, at binary position 41
    ; - Xmit timestamp fraction (picoseconds) is a big-endian, uint32, at binary position 45
    $iSeconds   = Dec(Hex(BinaryMid($xResponse, 41, 4)), $NUMBER_64BIT) ; seconds since 1900-01-01 00:00:00
    $iFraction  = Dec(Hex(BinaryMid($xResponse, 45, 4)), $NUMBER_64BIT) ; fractional portion
    $iMillisecs = Round($iFraction / 2^32 * 1000)                       ; round to nearest integer

    write_log_line()
    write_log_line(StringFormat("DEBUG: Xmit Timestamp Seconds  = 0x%s (%s)", Hex(BinaryMid($xResponse, 41, 4)), $iSeconds))
    write_log_line(StringFormat("DEBUG: Xmit Timestamp Fraction = 0x%s (%s picosecs) (%.12f decimal secs) (%i msecs)", _
        Hex(BinaryMid($xResponse, 45, 4)), $iFraction, $iFraction / 2^32, $iMillisecs))

    ; Display current UTC & Local time
    $sTimestampUTC   = StringReplace(_DateAdd("s", $iSeconds, "1900/01/01 00:00:00"), "/", "-") & StringFormat(".%03i", $iMillisecs)
    $sTimestampLocal = StringReplace(_DateAdd("s", $iSeconds + (3600 * $MY_TZ_OFFSET), "1900/01/01 00:00:00"), "/", "-") & StringFormat(".%03i", $iMillisecs)

    write_log_line()
    write_log_line("Date/Time (UTC)   = " & $sTimestampUTC)
    write_log_line("Date/Time (Local) = " & $sTimestampLocal)
EndFunc

Func udp_shutdown()
    UDPShutdown()
EndFunc

Func write_log_line($sMessage = "")
    Local $sNow = StringReplace(_NowCalc(), "/", "-")
    ConsoleWrite($sNow & ": " & $sMessage & @CRLF)
EndFunc

 

 

Edited by TheXman
Link to comment
Share on other sites

6 minutes ago, CYCho said:

@TheXman Thank you. I am glad that I did it. The last 2 days were an intensive course of learning for me and I enjoyed it. I appreciate your help.

 

You're welcome! :thumbsup:

Feel free to reach out to me directly if you ever run into any AutoIt obstacles in the future.  :bye:

Link to comment
Share on other sites

Using @TheXman's UDF to get time from NTP server, I completely revamped my original code as below. I don't know the real benefit of doing it, but the code now synchronizes computer time to millisec level. According to my experience, Google time server produced far less timed out errors than other servers. I didn't have to worry about timezone offset because Windows takes care of it.

;~ Many thanks to @TheXman for his kind guidance.
;~ https://www.autoitscript.com/forum/topic/200643-pulling-time-from-ntp-server/?do=findComment&comment=1439629

#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_AU3Check_Parameters=-w 3 -w 4 -w 5 -w 6 -d
#AutoIt3Wrapper_Outfile=NTP_Time_V4.exe
#AutoIt3Wrapper_Res_Fileversion=4.0
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****

#RequireAdmin
#include <Constants.au3>
#include <Date.au3>

Global $hTimeoutTimer = TimerInit()
While 1
    If Ping("www.google.com") > 0 Then ExitLoop
    If TimerDiff($hTimeoutTimer) > 120000 Then
        WriteLog(0, "System has no internet connection")
        Exit
    EndIf
    Sleep(50)
WEnd

Global $NTP_Server = 'time.google.com', $NTP_Time

NTP_GetTime()

System_SetTime()


Func System_SetTime()
    ; 2019/10/28 23:09:52.522
    ; 12345678901234567890123
    Local $m = StringMid($NTP_Time, 6, 2)
    Local $d = StringMid($NTP_Time, 9, 2)
    Local $y = StringMid($NTP_Time, 1, 4)
    Local $h = StringMid($NTP_Time, 12, 2)
    Local $mi = StringMid($NTP_Time, 15, 2)
    Local $s = StringMid($NTP_Time, 18, 2)
    Local $ms = StringMid($NTP_Time, 21, 3)
    ;~ Sets the new current time to the computer
    Local $tCurr = _Date_Time_EncodeSystemTime($m, $d, $y, $h, $mi, $s, $ms)
    Local $tTime = _Date_Time_GetSystemTime()
    _Date_Time_SetSystemTime(DllStructGetPtr($tCurr))

    Local $aTime = _Date_Time_SystemTimeToArray($tTime)
    WriteLog($aTime, "Update Time: " & $NTP_Time & " UTC")
EndFunc ;==>System_SetTime

Func NTP_GetTime()
    Local $tBuffer
    Local $aSocket
    Local $xRequest = Binary(""), $xResponse = Binary(""), $hTimeoutTimer, $hEchoTimer, $iDelay
    Local $iSeconds= 0, $iFractions = 0, $iMsecs = 0

    ; Create the NTP request using a 48 byte buffer
    $tBuffer = DllStructCreate("byte[48]")
    DllStructSetData($tBuffer, 1, 0x23) ; 00 100 011 = LI(0) / VN(4-NTPv4) / Mode(3-Client)

    ; Copy the buffer to a variable for sending
    $xRequest = DllStructGetData($tBuffer, 1)

    ; Send NTP request
    UDPStartup()
    If @error Then
        WriteLog(0, "UDPStartup failed - @error = " & @error)
        Exit
    EndIf
    OnAutoItExitRegister("udp_shutdown")

    $aSocket = UDPOpen(TCPNameToIP($NTP_Server), 123)
    If @error Then
        WriteLog(0, "UDPOpen failed - @error = " & @error)
        Exit
    EndIf
    Sleep(50)

    $hTimeoutTimer = TimerInit()
    While 1
        $hEchoTimer = TimerInit()
        UDPSend($aSocket, $xRequest)
        If @error Then
            WriteLog(0, "UDPSend failed - @error = " & @error)
            Exit
        EndIf

        Do
            $xResponse = UDPRecv($aSocket, DllStructGetSize($tBuffer), $UDP_DATA_BINARY)
            If @error Then
                WriteLog(0, "UDPRecv failed - @error = " & @error)
                Exit
            EndIf
        Until $xResponse <> Binary("")
        $iDelay = Round(TimerDiff($hEchoTimer)/2)
        If $iDelay < 100 Then
            ExitLoop
        EndIf
        If TimerDiff($hTimeoutTimer) > 120000 Then ; If no response within 2 seconds, then exit
            WriteLog(0, "UDPRecv timed out")
            Exit
        EndIf
        Sleep(100)
    WEnd

    ; Close the socket
    UDPCloseSocket($aSocket)

    ; Parse timestamp values
    ; - Current time is calculated from the xmit timestamp in NTP response header
    ; - Xmit timestamp seconds is a big-endian, uint32, at binary position 41
    ; - Xmit timestamp fraction is a big-endian, uint32, at binary position 45
    $iSeconds = Dec(Hex(BinaryMid($xResponse, 41, 4)), $NUMBER_64BIT) ; seconds since 1900-01-01 00:00:00
    $iFractions = Dec(Hex(BinaryMid($xResponse, 45, 4)), $NUMBER_64BIT) ; the maximum value is 0xFFFFFFFF, which represents 1 second
    $iMsecs = Round($iFractions / 2^32 * 1000) + $iDelay ; It normally takes about 50 milsecs to get NTP time
    If $iMsecs >= 1000 Then
        $iSeconds += 1
        $iMsecs -= 1000
    EndIf

    ; Current NTP time
    $NTP_Time = _DateAdd("s", $iSeconds, "1900/01/01 00:00:00") & StringFormat(".%03i", $iMsecs)
EndFunc   ;==>NTP_GetTime

Func udp_shutdown()
    UDPShutdown()
EndFunc   ;==>udp_shutdown

Func WriteLog($pTime, $sMessage)
    Local $fn, $sTime
    If $pTime = 0 Then
        $fn = FileOpen(@ScriptDir & "\TimeSync Failed.log", 2)
        $sTime = _NowCalc()
    Else
        $fn = FileOpen(@ScriptDir & "\TimeSync.log", 2)
        FileDelete(@ScriptDir & "\TimeSync Failed.log")
        $sTime = StringFormat("System Time: %04d/%02d/%02d %02d:%02d:%02d.%03d UTC", $pTime[2], $pTime[0], $pTime[1], $pTime[3], $pTime[4], $pTime[5], $pTime[6])
    EndIf
    FileWrite($fn, $sTime & @CRLF & $sMessage)
    FileClose($fn)
EndFunc   ;==>WriteLog

 

Edited by CYCho
Link to comment
Share on other sites

All of the variables that you have defined that are not inside of a function are global in scope, even if you define them as Local.  So all of the Local vars at the top of your script should actually be defined as Global. 

Change your au3 parameters to the following and you will see the warnings:

#AutoIt3Wrapper_AU3Check_Parameters=-w 3 -w 4 -w 5 -w 6 -d

 

Edited by TheXman
Link to comment
Share on other sites

The compiled version of this code(NTP_Time_V4.exe attached to the 1st post of this topic) was cleared by Microsoft Windows Defender from false detection as of Definition 1.305.2722.0. I attached the file to the first post of this topic.

Edited by CYCho
Link to comment
Share on other sites

  • 2 weeks later...

Did you look here:

?

 

Signature beginning:
Please remember: "AutoIt"..... *  Wondering who uses AutoIt and what it can be used for ? * Forum Rules *
ADO.au3 UDF * POP3.au3 UDF * XML.au3 UDF * IE on Windows 11 * How to ask ChatGPT for AutoIt Codefor other useful stuff click the following button:

Spoiler

Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind. 

My contribution (my own projects): * Debenu Quick PDF Library - UDF * Debenu PDF Viewer SDK - UDF * Acrobat Reader - ActiveX Viewer * UDF for PDFCreator v1.x.x * XZip - UDF * AppCompatFlags UDF * CrowdinAPI UDF * _WinMergeCompare2Files() * _JavaExceptionAdd() * _IsBeta() * Writing DPI Awareness App - workaround * _AutoIt_RequiredVersion() * Chilkatsoft.au3 UDF * TeamViewer.au3 UDF * JavaManagement UDF * VIES over SOAP * WinSCP UDF * GHAPI UDF - modest begining - comunication with GitHub REST APIErrorLog.au3 UDF - A logging Library * Include Dependency Tree (Tool for analyzing script relations) * Show_Macro_Values.au3 *

 

My contribution to others projects or UDF based on  others projects: * _sql.au3 UDF  * POP3.au3 UDF *  RTF Printer - UDF * XML.au3 UDF * ADO.au3 UDF SMTP Mailer UDF * Dual Monitor resolution detection * * 2GUI on Dual Monitor System * _SciLexer.au3 UDF * SciTE - Lexer for console pane

Useful links: * Forum Rules * Forum etiquette *  Forum Information and FAQs * How to post code on the forum * AutoIt Online Documentation * AutoIt Online Beta Documentation * SciTE4AutoIt3 getting started * Convert text blocks to AutoIt code * Games made in Autoit * Programming related sites * Polish AutoIt Tutorial * DllCall Code Generator * 

Wiki: Expand your knowledge - AutoIt Wiki * Collection of User Defined Functions * How to use HelpFile * Good coding practices in AutoIt * 

OpenOffice/LibreOffice/XLS Related: WriterDemo.au3 * XLS/MDB from scratch with ADOX

IE Related:  * How to use IE.au3  UDF with  AutoIt v3.3.14.x * Why isn't Autoit able to click a Javascript Dialog? * Clicking javascript button with no ID * IE document >> save as MHT file * IETab Switcher (by LarsJ ) * HTML Entities * _IEquerySelectorAll() (by uncommon) * IE in TaskSchedulerIE Embedded Control Versioning (use IE9+ and HTML5 in a GUI) * PDF Related:How to get reference to PDF object embeded in IE * IE on Windows 11

I encourage you to read: * Global Vars * Best Coding Practices * Please explain code used in Help file for several File functions * OOP-like approach in AutoIt * UDF-Spec Questions *  EXAMPLE: How To Catch ConsoleWrite() output to a file or to CMD *

I also encourage you to check awesome @trancexx code:  * Create COM objects from modules without any demand on user to register anything. * Another COM object registering stuffOnHungApp handlerAvoid "AutoIt Error" message box in unknown errors  * HTML editor

winhttp.au3 related : * https://www.autoitscript.com/forum/topic/206771-winhttpau3-download-problem-youre-speaking-plain-http-to-an-ssl-enabled-server-port/

"Homo sum; humani nil a me alienum puto" - Publius Terentius Afer
"Program are meant to be read by humans and only incidentally for computers and execute" - Donald Knuth, "The Art of Computer Programming"
:naughty:  :ranting:, be  :) and       \\//_.

Anticipating Errors :  "Any program that accepts data from a user must include code to validate that data before sending it to the data store. You cannot rely on the data store, ...., or even your programming language to notify you of problems. You must check every byte entered by your users, making sure that data is the correct type for its field and that required fields are not empty."

Signature last update: 2023-04-24

Link to comment
Share on other sites

@mLipok I compared the performance of 2 different approaches to get NTP server time.

Approach #1:

#include <Date.au3>
#include <StructureConstants.au3>
#include <WinAPIMisc.au3>

$tFT = _NTP_FT('pool.ntp.org')
For $i = 1 To 10
    $hTimer = TimerInit()
    $tFT = _NTP_FT('pool.ntp.org')
    ConsoleWrite(_Date_Time_FileTimeToStr($tFT) & " - " & TimerDiff($hTimer) & @CRLF)
Next

Func _NTP_FT($sServer, $fLocal = True)

    Local $tNTP = DllStructCreate('byte Header[4];byte RootDelay[4];byte RootDispersion[4];byte ReferenceIdentifier[4];byte ReferenceTimestamp[8];byte OriginateTimestamp[8];byte ReceiveTimestamp[8];byte TransmitTimestamp[8];byte KeyIdentifier[4];byte MessageDigest[16]')
    Local $tPacket = DllStructCreate('byte Packet[68]', DllStructGetPtr($tNTP))
    Local $bPacket = 0, $tFT, $tQW, $aSocket, $aResult

;~  0x1B000000 = 00011011 00000000 00000000 00000000b (LI = 00b VN = 011b Mode = 011b Stratum = 00000000b Poll = 00000000b Precision = 00000000b)
    $tNTP.Header = Binary('0x1B000000')
    UDPStartup()
    If @error Then
        Return SetError(1, 0, 0)
    EndIf
    $aSocket = UDPOpen(TCPNameToIP($sServer), 123)
    If @error Then
        ; Nothing
    Else
        UDPSend($aSocket, $tPacket.Packet)
        If @error Then
            ; Nothing
        Else
            While 1
                $bPacket = UDPRecv($aSocket, 68, 1)
                If (@error) Or ($bPacket) Then
                    ExitLoop
                EndIf
                Sleep(100)
            WEnd
        EndIf
    EndIf
    UDPCloseSocket($aSocket)
    UDPShutdown()
    If Not $bPacket Then
        Return SetError(2, 0, 0)
    EndIf

    $tFT = DllStructCreate($tagFILETIME)
    If $fLocal Then
        $tQW = DllStructCreate('uint64 Timestamp')
    Else
        $tQW = DllStructCreate('uint64 Timestamp', DllStructGetPtr($tFT))
    EndIf
    $tPacket.Packet = $bPacket
    $tQW.Timestamp = _WinAPI_SwapDWord(DllStructGetData(DllStructCreate('uint', DllStructGetPtr($tNTP, 'TransmitTimestamp')), 1)) * 10000000 + 94354848000000000
    If $fLocal Then
        $aResult = DllCall('kernel32.dll', 'bool', 'FileTimeToLocalFileTime', 'struct*', $tQW, "struct*", $tFT)
        If (@error) Or (Not $aResult[0]) Then
            Return SetError(3, 0, 0)
        EndIf
    EndIf
    Return SetError(0, 0, $tFT)
EndFunc    ;==>_NTP_FT

The reault:

12/06/2019 22:29:06 - 50.5885
12/06/2019 22:29:06 - 48.0765
12/06/2019 22:29:06 - 52.2912
12/06/2019 22:29:06 - 46.8422
12/06/2019 22:29:06 - 42.2072
12/06/2019 22:29:07 - 44.1788
12/06/2019 22:29:07 - 43.5889
12/06/2019 22:29:07 - 42.9144
12/06/2019 22:29:07 - 45.8183

Approach #2

#include <Constants.au3>
#include <Date.au3>

Global $NTP_Server = 'pool.ntp.org', $NTP_Time

NTP_GetTime()
For $i = 1 To 10
    $tTimer = TimerInit()
    NTP_GetTime()
    ConsoleWrite($NTP_Time & " - " & TimerDiff($tTimer) & @CRLF)
Next


Func NTP_GetTime()
    Local $tBuffer
    Local $aSocket
    Local $xRequest = Binary(""), $xResponse = Binary(""), $hTimeoutTimer, $hEchoTimer
    Local $iSeconds= 0, $iFractions = 0, $iMsecs = 0

    ; Create the NTP request using a 48 byte buffer
    $tBuffer = DllStructCreate("byte[48]")
    DllStructSetData($tBuffer, 1, 0x23) ; 00 100 011 = LI(0) / VN(4-NTPv4) / Mode(3-Client)

    ; Copy the buffer to a variable for sending
    $xRequest = DllStructGetData($tBuffer, 1)

    ; Send NTP request
    UDPStartup()
    If @error Then
        ConsoleWrite("UDPStartup failed - @error = " & @error)
        Exit
    EndIf
    OnAutoItExitRegister("udp_shutdown")

    $aSocket = UDPOpen(TCPNameToIP($NTP_Server), 123)
    If @error Then
        ConsoleWrite("UDPOpen failed - @error = " & @error)
        Exit
    EndIf

    $hEchoTimer = TimerInit()
    UDPSend($aSocket, $xRequest)
    If @error Then
        ConsoleWrite("UDPSend failed - @error = " & @error)
        Exit
    EndIf

    Do
        $xResponse = UDPRecv($aSocket, DllStructGetSize($tBuffer), $UDP_DATA_BINARY)
        If @error Then
            ConsoleWrite("UDPRecv failed - @error = " & @error)
            Exit
        EndIf
    Until $xResponse <> Binary("")
    $iDelay = TimerDiff($hEchoTimer)
    ; Close the socket
    UDPCloseSocket($aSocket)

    ; Parse timestamp values
    ; - Current time is calculated from the xmit timestamp in NTP response header
    ; - Xmit timestamp seconds is a big-endian, uint32, at binary position 41
    ; - Xmit timestamp fraction is a big-endian, uint32, at binary position 45
    $iSeconds = Dec(Hex(BinaryMid($xResponse, 41, 4)), $NUMBER_64BIT) ; seconds since 1900-01-01 00:00:00
    $iFractions = Dec(Hex(BinaryMid($xResponse, 45, 4)), $NUMBER_64BIT) ; the maximum value is 0xFFFFFFFF, which represents 1 second
    $iMsecs = Round($iFractions / 2^32 * 1000) + Round($iDelay/2)
    If $iMsecs >= 1000 Then
        $iSeconds += 1
        $iMsecs -= 1000
    EndIf

    ; Current NTP time
    $NTP_Time = _DateAdd("s", $iSeconds, "1900/01/01 00:00:00")
    $NTP_Time = _DateAdd("h", 9, $NTP_Time) & StringFormat(".%03i", $iMsecs)
EndFunc   ;==>NTP_GetTime

Func udp_shutdown()
    UDPShutdown()
EndFunc   ;==>udp_shutdown

The result:

2019/12/06 22:51:24.255 - 5.5304
2019/12/06 22:51:24.260 - 4.3448
2019/12/06 22:51:24.264 - 3.9764
2019/12/06 22:51:24.268 - 4.0598
2019/12/06 22:51:24.272 - 3.9179
2019/12/06 22:51:24.277 - 5.038
2019/12/06 22:51:24.281 - 5.3846
2019/12/06 22:51:24.287 - 4.7938
2019/12/06 22:51:24.293 - 6.4303
2019/12/06 22:51:24.298 - 5.383

I don't understand what makes this large difference in terms of time taken for each iteration. For unknow reason, the frst iteration always produced an outlying result, so I left that out.

Edited by CYCho
Link to comment
Share on other sites

  • 2 weeks later...

In connection with this topic a need arose to compare two time strings in milliseconds. As _DateDiff function does not support millisecond data type, I came up with a UDF based on the original _DateDiff function.

#include <Date.au3>

$sDate1 = "2019/12/19 23:16:24"
$sDate2 = "2019/12/20 23:16:24.02"

ConsoleWrite("Difference in seconds: " & _DateDiffEx("s", $sDate1, $sDate2) & @CRLF)
ConsoleWrite("Difference in milliseconds: " & _DateDiffEx("ms", $sDate1, $sDate2) & @CRLF)


Func _DateDiffEx($sType, $sStartDate, $sEndDate)
    Local $iDiff
    If $sType = "ms" Or $sType = "s" Then
        Local $sStartMS, $sEndMS, $iDiffSec
        If StringInStr($sStartDate, ".") Then
            $sStartMS = StringMid($sStartDate, StringInStr($sStartDate, "."), 5)*1000
            $sStartDate = StringLeft($sStartDate, StringInStr($sStartDate, ".")-1)
        EndIf
        If StringInStr($sEndDate, ".") Then
            $sEndMS = StringMid($sEndDate, StringInStr($sEndDate, "."), 5)*1000
            $sEndDate = StringLeft($sEndDate, StringInStr($sEndDate, ".")-1)
        EndIf
        $iDiffSec = _DateDiff("s", $sStartDate, $sEndDate)
        If @error Then Return SetError(@error, 0, 0)
        $iDiff = $iDiffSec*1000+Round($sEndMS-$sStartMS)
        If $sType = "s" Then
            $iDiff = StringFormat("%.3f", $iDiff/1000)
        EndIf
    Else
        If StringInStr($sStartDate, ".") Then
            $sStartDate = StringLeft($sStartDate, StringInStr($sStartDate, ".")-1)
        EndIf
        If StringInStr($sEndDate, ".") Then
            $sEndDate = StringLeft($sEndDate, StringInStr($sEndDate, ".")-1)
        EndIf
        $iDiff = _DateDiff($sType, $sStartDate, $sEndDate)
    EndIf
    Return SetError(@error, 0, $iDiff)
EndFunc

 

Edited by CYCho
Link to comment
Share on other sites

  • 2 months later...

With this code running in my desktop, I found that my computer needed an average upward adjustment of 1.8 seconds a day. Even though I can schedule this code to run as often as possible to forcefully adjust the system time at short intervals, I was wondering if there was a way to let the system clock run a little bit faster to keep better time by itself. And I found _Date_Time_SetSystemTimeAdjustment() function and included the following lines at the end of the code. The result is very satisfactory: it now lags less than a quarter of a second a day.

$aInfo = _Date_Time_GetSystemTimeAdjustment()
$iAdjustment = $aInfo[1] + 3    ; 156250 + 3 : The increment of 1 in $iAdjustment value represents 0.55296 second a day.
_Date_Time_SetSystemTimeAdjustment($iAdjustment, False)

 

Edited by CYCho
Link to comment
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
 Share

×
×
  • Create New...