Getting the current date and time

Tcl offers time package that can be used to query current time using either official servers for providing it or local servers within our network.

One of the reasons is that applications that operate over the network need to know and use the current time. For example, if multiple machines register events and/or data updates based on the time they occurred, if their system clocks are not synchronized, events might be reported out of order.

In majority of cases the system clock is synchronized so all applications use the correct time, but in some cases it might only be possible for the application to synchronize its time and handle it properly whenever sending a time.

The time package offers similar commands to dns and http ones. The query can be run using the time::gettime and time::getsntp commands. The first command queries the time using the Network Time Protocol (NTP) and second one uses the Simple Network Time Protocol (SNTP), which is a simplified version of NTP. The majority of servers on the Internet use SNTP.

Both commands take the time server as the first argument. Additional options can be specified before the time server. Both commands also return a token that can be used for invoking other commands to get information and/or finalize the query. By default it works in synchronous mode, which means that the commands will exit after the time is retrieved or a timeout occurs. For example:

package require time
set token [time::getsntp pool.ntp.org]

This will query the time from pool.ntp.org. This hostname is a pool of all publicly available time servers and is updated dynamically, it should always point to a valid time server on the Internet. These servers serve the SNTP protocol, which is why we're using time::getsntp command. Details about publicly available time servers and the project can be found on its home page at: http://www.pool.ntp.org/.

Next we should verify if an error has occurred. We can use the time::status command which returns status of the query. The status can be one of ok, error, timeout, or eof. For errors the actual error message can be retrieved using the time::error command. For example:

if {[time::status $token] != "ok"} {
puts "Error while retrieving time"
exit 1
}

The final step is to clean up our request. This can be done by invoking time::cleanup command, which takes token as its only argument. We can then show both the local and the remote time and print out both along with the difference between them. Getting the time from the request can be done with time::unixtime command, which accepts a token as an argument and returns a Unix timestamp, which is the same as the clock command it operates with. For example:

time::cleanup $token
set remoteclock [time::unixtime $token]
set localclock [clock seconds]
set diff [expr {$remoteclock-$localclock}]
puts "Local time: [clock format $localclock]"
puts "Remote time: [clock format $remoteclock]"
puts "Difference: $diff secons(s)"

It is also possible to use the time package in an asynchronous way. We can provide -command option and this command will be run whenever a query finishes and will have token appended as argument, similar to dns and http commands. For example:

time::getsntp -command onGetDone pool.ntp.org

This will cause the command to exit instantly and call the onGetDone command as soon as the query is completed. Our command can then use the token to parse the time, for example:

proc onGetDone {token} {
if {[time::status $token] != "ok"} {
puts "Error while retrieving time"
}
set time [clock format [time::unixtime $token]]
time::cleanup $token
puts "Remote time retrieved: $time"
}

This command will work similarly to the previous example—it will check the status of the query. If there was a problem, we print out an error message. If everything went okay, we will print out the current time and exit.

Note

An example of synchronizing the clock periodically is located in the main.tcl file in the 02time directory in the source code examples for this chapter.

As mentioned earlier, just retrieving the time might not be very useful for our application. Usually we want to make sure that all the time and date information we're using is based on the same time, retrieved periodically. We can create a procedure that periodically queries the time and stores the difference between the local clock and the remote server. Let's start with defining the namespace and creating the procedure:

package require time
namespace eval centraltime {}
proc centraltime::periodicUpdate {} {
variable centraltimediff
if {[catch {

We'll store the difference in the centraltimediff variable, which is referenced in the first line of the command. We'll then run the entire retrieval process in a catch to handle any errors. We can now proceed with retrieving information:

set token [time::getsntp pool.ntp.org]
if {[time::status $token] != "ok"} {
puts stderr "Error synchronizing time"
} else {
set remote [time::unixtime $token]
set localclock [clock seconds]
set centraltimediff [expr {$remote—$localclock}]
}

We're retrieving the current time over SNTP and if it succeeds, we store difference between the remote and local clock in our variable. We can then finalize our catch statement, clean up our request, and reschedule the next check for 10 minutes later:

} error]} {
puts stderr "Error while synchronizing time: $error"
}
catch {time::cleanup $token}
after 600000 centraltime::periodicUpdate
}

We now have a function that will try to query the time server, store the time difference if it succeeded, and reschedule the next check. We can also write a function that will return expected current time:

proc centraltime::getCorrectTime {} {
variable centraltimediff
set result [clock seconds]
if {[info exists centraltimediff]} {
incr result $centraltimediff
}
return $result
}

This command takes the current clock time, and if we know the last offset when comparing the local and remote time, it applies the difference. We can use this as replacement for the clock seconds command and get the time that we expect other systems we communicate with to have.

Note

An example of synchronizing the clock periodically is located in the periodicsync.tcl file in the 02time directory in the source code examples for this chapter.

More information about the time package as well as the remaining configuration options can be found in its documentation at the package's SourceForge project page: http://tcllib.sourceforge.net/doc/ntp_time.html.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.12.162.37