From 76d6a101b252d0e99abc656dcdfa9ffc2dde7d78 Mon Sep 17 00:00:00 2001 From: mpl Date: Tue, 12 Feb 2013 22:34:01 +0100 Subject: [PATCH] types: make Time3339 work for Go 1 too Fixes http://code.google.com/p/camlistore/issues/detail?id=109 Change-Id: I4c30a77465e7774a0a867e95767f3e0ef1be7ec6 --- pkg/types/types.go | 37 +++++++++++++++++++++++++++++++++++++ pkg/types/types_test.go | 9 +++++++-- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/pkg/types/types.go b/pkg/types/types.go index 9c1fe6608..c7dfbff02 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -19,9 +19,18 @@ package types import ( "encoding/json" "fmt" + "regexp" + "runtime" + "strings" "time" ) +var ( + goVersion = runtime.Version() + isGo10 = goVersion == "go1" || strings.HasPrefix(runtime.Version(), "go1.0") + dotNumbers = regexp.MustCompile(`\.\d+`) +) + // Time3339 is a time.Time which encodes to and from JSON // as an RFC 3339 time in UTC. type Time3339 time.Time @@ -39,10 +48,38 @@ func (t Time3339) MarshalJSON() ([]byte, error) { return json.Marshal(t.String()) } +func parseForGo10(s string) (time.Time, error) { + var numbers string + noNanos := dotNumbers.ReplaceAllStringFunc(s, func(m string) string { + numbers = m + return "" + }) + t, err := time.Parse(time.RFC3339, noNanos) + if err != nil { + return t, fmt.Errorf("Failed to parse %q as an RFC 3339 time: %v", noNanos, err) + } + if numbers != "" { + nanos, err := time.ParseDuration(numbers + "s") + if err != nil { + return t, fmt.Errorf("Failed to parse %q as a duration: %v", numbers+"s", err) + } + t = t.Add(nanos) + } + return t, nil +} + func (t *Time3339) UnmarshalJSON(b []byte) error { if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' { return fmt.Errorf("types: failed to unmarshal non-string value %q as an RFC 3339 time") } + if isGo10 { + tgo10, err := parseForGo10(string(b[1 : len(b)-1])) + if err != nil { + return err + } + *t = Time3339(tgo10) + return nil + } tm, err := time.Parse(time.RFC3339Nano, string(b[1:len(b)-1])) if err != nil { return err diff --git a/pkg/types/types_test.go b/pkg/types/types_test.go index c7bd7b736..b33162a7a 100644 --- a/pkg/types/types_test.go +++ b/pkg/types/types_test.go @@ -55,12 +55,17 @@ func TestTime3339_empty(t *testing.T) { // {enc: "0000-00-00T00:00:00Z"}, Go bug files {enc: "1970-01-01T00:00:00Z", z: true}, {enc: "2001-02-03T04:05:06Z", z: false}, + {enc: "2001-02-03T04:05:06+06:00", z: false}, + {enc: "2001-02-03T04:05:06-06:00", z: false}, + {enc: "2001-02-03T04:05:06.123456789Z", z: false}, + {enc: "2001-02-03T04:05:06.123456789+06:00", z: false}, + {enc: "2001-02-03T04:05:06.123456789-06:00", z: false}, } for _, tt := range tests { var tm Time3339 - err := json.Unmarshal([]byte("\"" + tt.enc + "\""), &tm) + err := json.Unmarshal([]byte("\""+tt.enc+"\""), &tm) if tm.IsZero() != tt.z { - t.Logf("unmarshal %q = %v (%d), %v; zero=%v; want %v", tt.enc, tm.Time(), tm.Time().Unix(), err, + t.Errorf("unmarshal %q = %v (%d), %v; zero=%v; want %v", tt.enc, tm.Time(), tm.Time().Unix(), err, !tt.z, tt.z) } }