dbohdan 2017-08-23: now is a little date and time calculator utility for the command line. It leverages Tcl's clock add for date arithmetic.
Download with wiki-reaper: wiki-reaper -x 48963 1 | tee now.tcl
$ now Wed Aug 23 19:46:15 DST 2017 $ now -3491 days Fri Feb 01 19:46:37 STD 2008 $ now -timezone :UTC -9 years -6 months -22 days +5 hours 5 minutes Fri Feb 01 22:54:59 UTC 2008
#! /usr/bin/env tclsh
# now - a command-line interface to Tcl clock arithmetic.
# Copyright (c) 2017-2018, 2021, 2024 D. Bohdan.
# License: MIT.
package require Tcl 8.6 9
variable version 1.1.0
proc usage channel {
puts $channel [format \
{usage: %s [-h] [-v] [-format fmt] [-gmt 0/1] [-locale loc]\
[-timezone tz] [count unit ...]} \
[file tail [info script]] \
]
}
# Parse the command line options. Give an informative message on error.
proc parse opts {
set formatOpts {}
while {
[llength $opts] > 0
&& ![string is integer -strict [lindex $opts 0]]
} {
set opts [lassign $opts k v]
switch -exact -- $k {
-h -
-help -
--help { return -code 1 -errorcode {PARSE USAGE} }
-v -
-version -
--version { return -code 1 -errorcode {PARSE VERSION} }
-format -
-gmt -
-locale -
-timezone { lappend formatOpts $k $v }
default {
return -code 1 -errorcode {PARSE UNKNOWN_OPTION} \
"unknown option \"$k\""
}
}
}
set delta {}
foreach {count unit} $opts {
set units {
y year
m month
d day
h hour
min minute
s second
}
if {![string is integer -strict $count]} {
return -code 1 "expected integer count, but got \"$count\""
}
set unit [string tolower $unit]
# Strip "s" at the end, but only if $unit isn't just "s".
regexp ^(.+?)s?$ $unit _ unit
# Expand abbreviations.
if {[dict exists $units $unit]} {
set unit [dict get $units $unit]
}
if {$unit eq {}} {
error "no unit given for count $count"
} elseif {$unit ni [dict values $units]} {
error [format \
{unknown unit "%s", must be "year" ("y"),\
"month" ("m"), "day" ("d"), "hour" ("h"),\
"minute" ("min"), or "second" ("s") with an optional\
suffix "-s"} \
$unit \
]
}
lappend delta $count $unit
}
return [list $formatOpts $delta]
}
# Output the date and time.
try {
lassign [parse $argv] formatOpts delta
puts [clock format [clock add [clock seconds] {*}$delta] {*}$formatOpts]
} on error {res errOpts} {
set ec [dict get $errOpts -errorcode]
if {$ec eq {PARSE USAGE}} {
usage stdout
exit 0
} elseif {$ec eq {PARSE VERSION}} {
puts $version
exit 0
} else {
if {$ec eq {PARSE UNKNOWN_OPTION}} {
usage stderr
}
puts stderr "error: $res"
exit 2
}
}