Tk Dual Zone Clock is a minimal dual zone clock written for practice by a novice. Improvements are welcome!
See Also edit
- Worldtime-clock
- Date and Time Issues
- similar issues are treated
- Script initialization - my own personal skeleton
Change Log edit
PYK 2013-09-30: significant rewrite. Code now uses knowledge of
clock.tcl internals to derive a list of timezone names. dualclock is now a widget that can be instantiated multiple times
Description edit
Anyone who wants to use this code in any manner whatsoever, is welcome to it. Most of the code for the clocks was found doing a search on
comp.lang.tcl. I just changed the format a little.
It is easily possible to use other time zones, but I wish I could figure out a way to do this using time zone mnemonics and/or military time zones. Any suggestions?
soDKF 2000-06-12: Up to (and including) 8.3 at least, you'd need to perform the timezone adjustment yourself. However, you can use [clock scan] (on most platforms at least) to help you get the offset:
proc getClockOffset {timezone} {
# Do it this way to avoid UNIXism assumption...
set epoch [clock format 0 -format "%b %d %Z %H:%M:%S %Y" -timezone :UTC]
regsub GMT $epoch $timezone datestring
return [expr {-[clock scan $datestring]}]
}
This should help you convert timezones (including the military designations, IIRC) into offsets so you can format the date correctly. The only awkward bit is getting a list of timezones that the code supports, and I'm afraid that you might need to delve into the source code for that (there are some interesting clashes in there!)
(Note that I specify the format because on some platforms the usual output of [clock format] can't be understood by [clock scan], and the format is needed to avoid hard-coding in the assumption that the epoch begins with 1970, as this might not hold on all platforms...)
Your task, should you choose to accept it, is to combine this code into the preceding code to create a more internationally-aware application...
#! /bin/env tclsh
package require Tk
namespace eval dualclock {
namespace export create
namespace ensemble create
proc create {{w {}}} {
variable state
variable timezones
if {$w == {.}} {
set parent {}
}
namespace eval [set id [info cmdcount]] {}
foreach varname {local_tz other_tz local_time other_date updaterunning} {
variable ${id}::$varname
}
set updaterunning 0
set ${id}::w $w
set now [clock scan now]
#synchronize with the system clock so that the [after] fires task approximately on the second
while {[clock scan now] eq $now} {}
after idle [list after 0 [list [namespace current]::update_time $id]]
set column -1
foreach clock {local other} {
entry $w.${clock}_date -state readonly \
-textvariable [namespace current]::${id}::${clock}_date
entry $w.${clock}_time -state readonly \
-textvariable [namespace current]::${id}::${clock}_time
::ttk::combobox $w.${clock}_tz -state readonly -values [dict keys $timezones] \
-textvariable [namespace current]::${id}::${clock}_tz
set ${clock}_tz [clock format 0 -format %Z]
bind $w.${clock}_tz <<ComboboxSelected>> [list [namespace current]::update_time $id]
$w.${clock}_date configure -width -1 -justify center
$w.${clock}_time configure -width -1 -justify center
incr column
grid $w.${clock}_date -row 1 -column $column -columnspan 1
grid $w.${clock}_time -row 2 -column $column -columnspan 1
grid $w.${clock}_tz -row 0 -column $column -columnspan 1
}
}
proc update_time {id args} {
variable tzoffsets
foreach varname {local_date local_time local_tz other_date other_time other_tz w updaterunning} {
variable ${id}::$varname
}
if {$updaterunning} return
set updaterunning 1
set now [clock scan now]
foreach clock {local other} {
set ${clock}_date [clock format $now -timezone [set ${clock}_tz] -format {%A %B %d, %Y}]
set ${clock}_time [clock format $now -timezone [set ${clock}_tz] -format {%I:%M:%S %p}]
}
set updaterunning 0
after 1000 [list after idle [list [namespace current]::update_time $id]]
}
proc tzoffsets {varname} {
upvar $varname var
#this is only here to initialize the ::tcl::clock subsystem
clock format 0 -timezone :UTC
foreach searchdir [list {*}$::tcl::clock::ZoneinfoPaths $::tcl::clock::DataDir] {
set dirpaths [glob -nocomplain -type d -directory $searchdir *]
while {[llength $dirpaths]} {
set dirpaths [lassign $dirpaths dirpath]
lappend dirpaths {*}[glob -nocomplain -type d -directory $dirpath *]
foreach tzpath [glob -nocomplain -type f -directory $dirpath *] {
set tzpath [string range $tzpath [string length $searchdir]+1 end]
expr {[catch {
::tcl::clock::LoadTimeZoneFile $tzpath
}] && [catch {
::tcl::clock::LoadZoneinfoFile $tzpath
}]}
}
}
}
set var [lsort [array names ::tcl::clock::TZData]]
set var [lmap zonename $var {string range $zonename 1 end}]
foreach tz $var[set var {}] {
if {[catch {set offset [clock format 0 -timezone :$tz -format %z]} eres eopts]} {
} else {
dict set var $tz $offset
}
}
return $var
}
variable timezones
tzoffsets timezones
}
proc main {} {
tk appname {Dual Clock}
#wm withdraw .
set w .[info cmdcount]
frame $w
grid $w
dualclock create $w
}
main