Version 15 of Date and Time Issues

Updated 2002-10-27 10:23:18

I started this page to ask and answer simple questions about the clock function.


A common question is How do I format the current time into some specific format (such as hh:mm:ss)?

Try

 clock format [clock seconds] -format %T

or

 clock format [clock seconds] -format %X

or if you need something more formatted, try

 clock format [clock seconds] -format {%H hours %M minutes and %S seconds}

Question: Does anyone have a pointer to a Tcl/Tk countdown clock - given a particular date/time, the number of years/months/weeks/days/hours/minutes/seconds until it is reached ticks away? Would be used for deadlines, retirement days, etc.

See Years, months, days, etc. between two dates for a partial solution.


Here's a common question that I have answered more than once: "How do I calculate elapsed time?"


First, set your "granularity". Here I go for hours.

 % set secondsPerHour 3600.00
 3600.00

Then, use something like this:

 % set elapsedTime [expr {([clock scan "2:15 PM"] - [clock scan "11:00 AM"]) / $secondsPerHour}]
 3.25

I'm sure there are other questions concerning the exceedingly complex and useful clock function.....

DKF - I corrected a minor formatting problem...


How does one easily calculate changes in time over time zones? I.e. How do I find out how many hours have elapsed between 1:00 AM CDT and 1:00 AM GMT?

DKF - Use [clock scan] to convert them both into standard format (i.e. seconds from beginning of epoch.) Then it is trivial to work out the time difference between them...

 % set cdt [clock scan "1:00 AM CDT"]
 969343200
 % set gmt [clock scan "1:00 AM GMT"]
 969325200
 % expr ($cdt-$gmt)/3600.0; # in hours...
 5.0

LV - One pretty common problem/question with dates and times occurs when someone gets a date or time in a format in which the value has a leading zero, then attempts to use that. For 8 and 9 am (and pm) as well as for the 8th and 9th of the month, one has a 08 or 09 as a value, resulting in Tcl generating the error msg:

  "08" is an invalid octal number
 while evaluating {set b [expr $a + 1]}

or whatever.

DKF - The correct way to deal with this is to use [scan %d] to convert the digit string into a number:

 scan $a %d aNum
 set b [expr {$a+1}]

LV - another question I've seen people ask is about getting the output they produce relating to dates and times to show a leading 0, since Tcl's treatment of numbers generally drops leading zeros for the reason just mentioned (octal number treatment).

DKF - And the natural complement of [scan] is [format] which can do precise this with minimal fuss:

 puts [format %04d 123]

RS - ... and [clock format] can do the typical application, zero-padded two-digit hours, minutes, seconds etc, with even less fuss:

 clock format [clock seconds] -format %y%m%d-%H%M%S
 001004-091226

LV - another question I see a lot - how to take a user provided date and compare it to the current date, or to calculate a future/past date to it.

KBK -

    # Compare two dates

    set date1 [clock scan {03/09/2001}]
    set date2 [clock scan {02/08/2001}]
    if { [expr { $date1 < $date2 }] } {
        puts "$date1 is earlier"
    }

    # Calculate a date relative to another date

    % set t [clock scan {03/09/2001}]
    984114000
    % set u [clock scan {+3 days} -base $t]
    984373200
    % clock format $u
    Mon Mar 12 00:00:00 Eastern Standard Time 2001
    % set u [clock scan {+3 weeks} -base $t]
    985928400
    % clock format $u
    Fri Mar 30 00:00:00 Eastern Standard Time 2001
    % set u [clock scan {+3 months} -base $t]
    992059200
    % clock format $u
    Sat Jun 09 00:00:00 Eastern Daylight Time 2001

See also Date Calculations.


Dave Griffin - For server-based applications, you may want to format the time for a timezone other than the local server's time. This seems to do the trick well enough:

 #
 # Format a date, optionally adjusting the local timezone
 #    date    - Tcl clock value
 #    fmt     - Date formatting string
 #    gmt     - True: format for GMT; False: local time
 #    localTz - Local timezone setting (e.g., EST5EDT)
 #              (if empty, use server local timezone)
 #

 proc formatDateTz { date fmt gmt localTz} {
    global env

    set saveTz ""

    if {$localTz != ""} {
        catch { set saveTz $env(TZ) }
        set env(TZ) $localTz
    }

    set r [clock format $date -format $fmt -gmt $gmt]

    if {$localTz != ""} {
        if {$saveTz != ""} {
            set env(TZ) $saveTz
        } else {
            unset env(TZ)
        }
    }

    return $r
 }

Please note that I believe the setting of localTz (the env(TZ) variable) is system-dependent. If I'm wrong here, I'd love to know the syntax -- there seem to be several to choose from.


LV New Issue: how to handle dates farther in the future than 2038. Is there a plan for Tcl to handle these?

 $ clock scan {12/31/2039}

unable to convert date-time string "12/31/2039" while evaluating {clock scan {12/31/2039}}

Check out

 What: clock with extended year range
 Where: http://members.home.net/arthur.taylor/graph/clock2.tar.gz 
 Description: Extension adding halo_clock2 command, which has most if not
        all of Tcl's clock functionality, but using a double int instead of
        a long int .  This extends the years covered to BC.  Also adds
        a IsDaylightSavings feature.
 Updated: 03/2001
 Contact: mailto:[email protected] (Arthur Taylor)

Number of days in a given month: from A little date chooser

 proc numberofdays {month year} {
   if {$month==12} {set month 0; incr year}
   clock format [clock scan "[incr month]/1/$year  1 day ago"] \
        -format %d
 } ;# RS

 What: Critchlow's Tcl support routines
 Where: http://www.elf.org/tclsources.html 
 Description: Mr. Critchlow provides a variety of useful tcl routines at
        his site.  For instance, palette is a reworking of Eric Grosse's
        rainbow color palette generator from netlib.
        This allows you to generate a variety of color palettes
        in Tcl.
        There's also a collection of time and date computations written in Tcl,
        which solve the problem of converting Unix clock tics into
        calendar date along with several other date/time needs.
        An implementation of George Marsaglia's mother of all random number
        generators, written in Tcl is alson on the site.  This is a
        very long period pseudorandom number generator.
        Also a version of old-random.tcl without namespaces.
        A Tcl procedure for converting an XPM into an photo widget image.
 Updated: 04/1999
 Contact: mailto:[email protected]  (Roger E. Critchlow Jr.)

The above code deals with standard Tcl date range, but provides Julian to calendar date conversions (and vice versa), as well as day and time to date with fraction and vice versa conversions.


Dave Griffin - the clock format command has a %Z option which returns the zone name, but no easy way to get the current timezone offset. (The zone name can be horribly non-standard on Windows systems: "Eastern Standard Time" instead of EST). RFC2822 also demands that dates use numeric timezone offsets. The following returns a RFC2822 compatible timezone offset:

 proc RFC2822TimezoneOffset {} {
     set gmt [clock seconds]
     set local1 [clock format [clock seconds] -format "%Y%m%d %H:%M:%S"]
     set local [clock scan $local1 -gmt 1]
     set offset [expr $local - $gmt]
     if {$offset < 0} {
         return "-[clock format [expr abs($offset)] -format "%H%M" -gmt 1]"
     } else {
         return "+[clock format $offset -format "%H%M" -gmt 1]"
     }
 }

Donal Fellows wrote in the comp.lang.tcl newsgroup: To get the number of days in the *current* month:

  set startOfMonth [clock format [clock seconds] -format %m/01/%Y]
  set days [clock format [clock scan "+1 month -1 day" \
          -base [clock scan $startOfMonth] -format %d]

See also Reworking the clock command.


[what category is this page?]


yahalom emet tcl version: tcl8.4.1 when I do:

 set month [clock format [clock second] -format %b]

I am getting the month name in a local format why? How can I get it in english?

rmax: Starting with version 8.4 Tcl respects locale settings on Unix. So depending of the contents of the LANG, LC_TIME, or LC_ALL environment variables you get localiuzed day and month names. If you always want to have english names, you could

 set env(LC_TIME) POSIX

inside your application.