goutils/cmd/utc/main.go

232 lines
6.2 KiB
Go
Raw Normal View History

2016-06-14 21:55:04 +00:00
package main
import (
"bufio"
"flag"
"fmt"
"io"
"os"
"time"
)
var (
format = "2006-01-02 15:04" // Format that will be used for times.
outFormat = format // Output format.
tz = "Local" // String descriptor for timezone.
fromLoc *time.Location = time.Local // Go time.Location for the named timezone.
toLoc *time.Location = time.UTC // Go time.Location for output timezone.
2016-06-14 21:55:04 +00:00
)
func usage(w io.Writer) {
fmt.Fprintf(w, `Usage: utc [-f format] [-h] [-o format] [-q] [-u] [-z zone] [time(s)...]
2016-06-14 21:55:04 +00:00
utc converts times to UTC. If no arguments are provided, prints the
current time in UTC. If the only time provided is "-", reads newline-
separated timestamps from standard input. If both the input and output
timezones are the same (e.g., the local time zone is UTC), a warning
message will be printed on standard error. This can be suppressed with
the -q option.
2016-06-14 21:55:04 +00:00
Flags:
-f format Go timestamp format for input times. See the Go docs
2016-06-14 21:55:04 +00:00
(e.g. https://golang.org/pkg/time/#pkg-constants)
for an explanation of this format.
Default value: %s
-h Print this help message.
-o format Go timestamp format for outputting times. Uses the
same format as the '-f' argument; it defaults to
the same value as the '-f' argument.
-q Suppress the timezone check warning message.
2016-06-14 21:55:04 +00:00
-u Timestamps are in UTC format and should be converted
to the timezone specified by the -z argument (which
defaults to '%s'). Note that this isn't particularly
useful with no arguments.
-z zone Text form of the time zone; this can be in short
time zone abbreviation (e.g. MST) or a location
(e.g. America/Los_Angeles). This has no effect when
printing the current time.
Default value: %s
Examples (note that the examples are done in the America/Los_Angeles /
PST8PDT time zone):
+ Getting the current time in UTC:
$ utc
2016-06-14 14:30 = 2016-06-14 21:30
+ Converting a local timestamp to UTC:
$ utc '2016-06-14 21:30'
2016-06-14 21:30 = 2016-06-15 04:30
+ Converting a local EST timestamp to UTC (on a machine set to
PST8PDT):
$ utc -z EST '2016-06-14 21:30'
2016-06-14 21:30 = 2016-06-15 02:30
+ Converting timestamps in the form '14-06-2016 3:04PM':
$ utc -f '02-01-2006 3:04PM' '14-06-2016 9:30PM'
14-06-2016 9:30PM = 15-06-2016 4:30AM
+ Converting timestamps from standard input:
$ printf "2016-06-14 14:42\n2016-06-13 11:01" | utc -
2016-06-14 14:42 = 2016-06-14 21:42
2016-06-13 11:01 = 2016-06-13 18:01
+ Converting a UTC timestamp to the local time zone:
$ utc -u '2016-06-14 21:30'
2016-06-14 21:30 = 2016-06-14 14:30
+ Converting a UTC timestamp to EST (on a machine set to
PST8PDT):
$ utc -u -z EST '2016-06-14 21:30'
2016-06-14 21:30 = 2016-06-14 16:30
+ Using a different output format:
$ utc -o '2006-01-02T15:03:04MST' '2016-06-14 21:30'
2016-06-14 21:30 = 2016-06-15T04:04:30UTC
+ Example of the warning message when running utc on a machine
where the local time zone is UTC:
$ utc
==================================================================
Note: both input and output timezone offsets are the same --- this
program may not do what you expect it to.
(Converting from UTC (offset +0000) to UTC (offset +0000).)
==================================================================
2016-06-14 23:44 = 2016-06-14 23:44
+ Example of the warning message when running utc on a machine
where the local time zone is GMT:
$ utc
==================================================================
Note: both input and output timezone offsets are the same --- this
program may not do what you expect it to.
(Converting from GMT (offset +0000) to UTC (offset +0000).)
==================================================================
2016-06-14 23:46 = 2016-06-14 23:46
2016-06-14 21:55:04 +00:00
`, format, tz, tz)
}
func getZone(loc *time.Location) (string, int) {
return time.Now().In(loc).Zone()
}
func checkZones(quiet bool) {
if quiet {
return
}
toZone, toOff := getZone(toLoc)
fromZone, fromOff := getZone(fromLoc)
if toOff == fromOff {
fmt.Fprintf(os.Stderr, `
==================================================================
Note: both input and output timezone offsets are the same --- this
program may not do what you expect it to.
(Converting from %s (offset %+05d) to %s (offset %+05d).)
==================================================================
`, fromZone, fromOff, toZone, toOff)
}
}
2016-06-14 21:55:04 +00:00
func init() {
var help, quiet, utc bool
2016-06-14 21:55:04 +00:00
flag.Usage = func() { usage(os.Stderr) }
flag.StringVar(&format, "f", format, "time format")
flag.BoolVar(&help, "h", false, "print usage information")
flag.StringVar(&outFormat, "o", outFormat, "output time format")
flag.BoolVar(&quiet, "q", false, "suppress zone check warning")
2016-06-14 21:55:04 +00:00
flag.BoolVar(&utc, "u", false, "timestamps are in UTC format")
flag.StringVar(&tz, "z", tz, "time zone to convert from; if blank, the local timezone is used")
flag.Parse()
if help {
if !utc {
checkZones(quiet)
}
2016-06-14 21:55:04 +00:00
usage(os.Stdout)
os.Exit(0)
}
if utc {
var err error
toLoc, err = time.LoadLocation(tz)
if err != nil {
fmt.Fprintf(os.Stderr, "Malformed timezone %s: %s\n", tz, err)
os.Exit(1)
}
fromLoc = time.UTC
} else {
var err error
fromLoc, err = time.LoadLocation(tz)
if err != nil {
fmt.Fprintf(os.Stderr, "Malformed timezone %s: %s\n", tz, err)
os.Exit(1)
}
if fromLoc == time.UTC {
}
2016-06-14 21:55:04 +00:00
toLoc = time.UTC
}
checkZones(quiet)
2016-06-14 21:55:04 +00:00
}
func showTime(t time.Time) {
fmt.Printf("%s = %s\n", t.Format(format), t.In(toLoc).Format(outFormat))
2016-06-14 21:55:04 +00:00
}
func dumpTimes(times []string) bool {
var errored bool
for _, t := range times {
u, err := time.ParseInLocation(format, t, fromLoc)
if err != nil {
errored = true
fmt.Fprintf(os.Stderr, "Malformed time %s: %s\n", t, err)
continue
}
showTime(u)
}
return errored
}
func main() {
var times []string
n := flag.NArg()
switch n {
case 0:
showTime(time.Now())
os.Exit(0)
case 1:
if flag.Arg(0) == "-" {
s := bufio.NewScanner(os.Stdin)
for s.Scan() {
times = append(times, s.Text())
}
} else {
times = flag.Args()
}
default:
times = flag.Args()
}
if dumpTimes(times) {
os.Exit(1)
}
}