Quick Access to Formatted Date & Time

WJG (11/02/06) Just one of those handy code snippets that can be appended to a bag of support procs.

 #---------------
 # lazy way to get preformated time and date
 #---------------
 proc date { {i date} } {
  switch -- $i {
    d&t   { set f "%c" }
    year  { set f "%Y" }
    week  { set f "%W" }
    day   { set f "%A" }
    month { set f "%B" }
    time  { set f "%H:%M:%S" }
    date  { set f "%d/%m/%y" }
    date4 { set f "%Y-%m-%d" }
    D4T24 { set f "%Y-%m-%d %T" }
  }
  return [clock format [clock seconds] -format "$f"]
 }

 # Test:
 catch {console show}
 puts [ date ]
 puts [ date D4T24 ]

HJG added "date4" (4-digit year), "D4T24" (4-digit year, 24h-time) and Testsuite


JED (12/02/06) I also have a couple of suggestions for you.

While playing with your proc in an interactive tclsh, once I forgot to source the script I placed it in, and expecting an error, I was reminded that tclsh in interactive mode will pass all unknown commands through to the shell. This ran the unix date command, and while looking at its output/format I noticed there is no equiv in your code. I'm not sure if it would even be wanted, but thinking it may be handy to have, I changed things around to make this format the default when no argument is given. I couldn't come up with a decent name for the format however, so any and all suggestions for that part are most welcome.

For reference, this was the format from the Linux GNU tools date command, version 5.2.1, on Debian. While I suspect the GNU date output to be the same on any Linux system and probably BSD as well, it's possible Solaris and others will differ.

I started out adding one other format to the switch, called unixtime. This format is the number of seconds since 00:00:00 1970-01-01 UTC, used commonly for date/time storage as well as to make determining elapsed time easier. On Linux atleast, this is the default output for the clock seconds command as well.

The changed version is:

 proc date { {i ""} } {
  switch -- $i {
    d&t      { set f "%c" }
    year     { set f "%Y" }
    week     { set f "%W" }
    day      { set f "%A" }
    month    { set f "%B" }
    time     { set f "%H:%M:%S" }
    date     { set f "%d/%m/%y" }
    date4    { set f "%Y-%m-%d" }
    D4T24    { set f "%Y-%m-%d %T" }
    unixtime { set f "%s" }
    rfc1123  { set olang $env(LANG)
               set env(LANG) C
               set f "%a, %d %b %Y %T %Z"
             }
    default  { set f "%a %b %e %H:%M:%S %Z %Y" }
  }
  return [clock format [clock seconds] -format "$f"]
  if {[info exists olang]} {set env(LANG) $olang}
 }

Comparing the output we get:

 % clock format [clock seconds] -format "%a %b %e %H:%M:%S %Z %Y"
 Sun Feb 12 11:21:15 EST 2006
 % date
 Sun Feb 12 11:21:18 EST 2006

And even testing for the space/padding allignment for %e, we see:

 % clock format [expr [clock seconds] - 864000] -format "%a %b %e %H:%M:%S %Z %Y"
 Thu Feb  2 11:22:17 EST 2006
 % date -d "10 days ago"
 Thu Feb  2 11:22:22 EST 2006

I hope these changes are helpful to others as well.

US Added RFC 1123 format, which is used in http and mail headers. If you are in a LANG=C environment (I'm not) you may drop all lines dealing with the environment.


RS has this in his toolbox (only one format, but good for many purposes):

 proc date {{x ""}} {
     if {$x eq ""} {set x [clock seconds]}
     clock format $x -format %Y-%m-%d,%H:%M:%S
 }

SMH Along the same lines:

 proc date_format {args} {
   if {[lindex $args 0] eq "now"} {lset args 0 [clock seconds]}
   set p [lsearch $args -format]
   if { [incr p] > 0 } {
     set fmt [string map  {% %%
       yyyy %Y yy %y monthname %B mmm %b mm %m 
       dayinweek %w dayofyear %j dayname %A day %a cc %C 
       isoweek %V week %W  dd %d 
       localdate date %D %x LOCALTIME %x TZ %Z tz %z TIMEZONE %Z AM/PM %p AM %p PM %p 
       HH %H MM %M SS %S datetime %c TIME %x d %e } [lindex $args $p]]
     lset args $p $fmt 
   } 
   eval [concat clock format $args]
 }

 # Dates in lower case and times in upper case (otherwise MM is ambiguous)

 puts [date_format now -format "dd-mm-yy HH:MM:SS (TZ)"]
 puts [date_format now -format "dayname mmm dd, yyyy HH:MM PM"]
 puts [date_format now -format "ccyymmddTHHMMSS" -gmt true]
 15-02-06 23:45:37 (W. Europe Standard Time)
 Wednesday Feb 15, 2006 23:45 PM
 20060215T224537

I couldn't see an easy way to get a time difference, GMT+01:00 instead of the time zone name.