types: make Time3339 work for Go 1 too

Fixes http://code.google.com/p/camlistore/issues/detail?id=109

Change-Id: I4c30a77465e7774a0a867e95767f3e0ef1be7ec6
This commit is contained in:
mpl 2013-02-12 22:34:01 +01:00
parent 981a4c9fbd
commit 76d6a101b2
2 changed files with 44 additions and 2 deletions

View File

@ -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

View File

@ -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)
}
}