From dfba096de9796981dca8d41a0b3cc66baffdae0e Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Wed, 13 May 2015 16:27:00 +0000 Subject: [PATCH] Parse input timestamps with standard RFC3339 Fix for #13175. This change allows user-input timestamps (e.g. to `docker events --since/--until` or `docker logs --since` to be parsed using standard RFC3339Nano layout in Go instead of the layout that parses all timestamps into fixed-length strings (currently buggy). User inputs need not to be complying to the internal format (`RFC3339NanoFixed`) anyway. Added test case for `events --since/--until` with all possible timestamp input formats. Signed-off-by: Ahmet Alp Balkan --- timeutils/utils.go | 13 ++++++++++--- timeutils/utils_test.go | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 timeutils/utils_test.go diff --git a/timeutils/utils.go b/timeutils/utils.go index c0c38fa..6af16a1 100644 --- a/timeutils/utils.go +++ b/timeutils/utils.go @@ -2,14 +2,21 @@ package timeutils import ( "strconv" + "strings" "time" ) // GetTimestamp tries to parse given string as RFC3339 time -// or Unix timestamp, if successful returns a Unix timestamp -// as string otherwise returns value back. +// or Unix timestamp (with seconds precision), if successful +//returns a Unix timestamp as string otherwise returns value back. func GetTimestamp(value string) string { - format := RFC3339NanoFixed + var format string + if strings.Contains(value, ".") { + format = time.RFC3339Nano + } else { + format = time.RFC3339 + } + loc := time.FixedZone(time.Now().Zone()) if len(value) < len(format) { format = format[:len(value)] diff --git a/timeutils/utils_test.go b/timeutils/utils_test.go new file mode 100644 index 0000000..1d724fb --- /dev/null +++ b/timeutils/utils_test.go @@ -0,0 +1,36 @@ +package timeutils + +import ( + "testing" +) + +func TestGetTimestamp(t *testing.T) { + cases := []struct{ in, expected string }{ + {"0", "-62167305600"}, // 0 gets parsed year 0 + + // Partial RFC3339 strings get parsed with second precision + {"2006-01-02T15:04:05.999999999+07:00", "1136189045"}, + {"2006-01-02T15:04:05.999999999Z", "1136214245"}, + {"2006-01-02T15:04:05.999999999", "1136214245"}, + {"2006-01-02T15:04:05", "1136214245"}, + {"2006-01-02T15:04", "1136214240"}, + {"2006-01-02T15", "1136214000"}, + {"2006-01-02T", "1136160000"}, + {"2006-01-02", "1136160000"}, + {"2006", "1136073600"}, + {"2015-05-13T20:39:09Z", "1431549549"}, + + // unix timestamps returned as is + {"1136073600", "1136073600"}, + + // String fallback + {"invalid", "invalid"}, + } + + for _, c := range cases { + o := GetTimestamp(c.in) + if o != c.expected { + t.Fatalf("wrong value for '%s'. expected:'%s' got:'%s'", c.in, c.expected, o) + } + } +}