mirror of
https://github.com/golang/go
synced 2024-11-12 08:10:21 -07:00
time: make Time implement encoding interfaces
See golang.org/s/go12encoding for design. R=golang-dev, bradfitz CC=golang-dev https://golang.org/cl/12706043
This commit is contained in:
parent
413d4c6c11
commit
071e44e4e4
@ -839,10 +839,10 @@ func (t Time) UnixNano() int64 {
|
|||||||
return (t.sec+internalToUnix)*1e9 + int64(t.nsec)
|
return (t.sec+internalToUnix)*1e9 + int64(t.nsec)
|
||||||
}
|
}
|
||||||
|
|
||||||
const timeGobVersion byte = 1
|
const timeBinaryVersion byte = 1
|
||||||
|
|
||||||
// GobEncode implements the gob.GobEncoder interface.
|
// MarshalBinary implements the encoding.BinaryMarshaler interface.
|
||||||
func (t Time) GobEncode() ([]byte, error) {
|
func (t Time) MarshalBinary() ([]byte, error) {
|
||||||
var offsetMin int16 // minutes east of UTC. -1 is UTC.
|
var offsetMin int16 // minutes east of UTC. -1 is UTC.
|
||||||
|
|
||||||
if t.Location() == &utcLoc {
|
if t.Location() == &utcLoc {
|
||||||
@ -850,17 +850,17 @@ func (t Time) GobEncode() ([]byte, error) {
|
|||||||
} else {
|
} else {
|
||||||
_, offset := t.Zone()
|
_, offset := t.Zone()
|
||||||
if offset%60 != 0 {
|
if offset%60 != 0 {
|
||||||
return nil, errors.New("Time.GobEncode: zone offset has fractional minute")
|
return nil, errors.New("Time.MarshalBinary: zone offset has fractional minute")
|
||||||
}
|
}
|
||||||
offset /= 60
|
offset /= 60
|
||||||
if offset < -32768 || offset == -1 || offset > 32767 {
|
if offset < -32768 || offset == -1 || offset > 32767 {
|
||||||
return nil, errors.New("Time.GobEncode: unexpected zone offset")
|
return nil, errors.New("Time.MarshalBinary: unexpected zone offset")
|
||||||
}
|
}
|
||||||
offsetMin = int16(offset)
|
offsetMin = int16(offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
enc := []byte{
|
enc := []byte{
|
||||||
timeGobVersion, // byte 0 : version
|
timeBinaryVersion, // byte 0 : version
|
||||||
byte(t.sec >> 56), // bytes 1-8: seconds
|
byte(t.sec >> 56), // bytes 1-8: seconds
|
||||||
byte(t.sec >> 48),
|
byte(t.sec >> 48),
|
||||||
byte(t.sec >> 40),
|
byte(t.sec >> 40),
|
||||||
@ -880,18 +880,19 @@ func (t Time) GobEncode() ([]byte, error) {
|
|||||||
return enc, nil
|
return enc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GobDecode implements the gob.GobDecoder interface.
|
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
|
||||||
func (t *Time) GobDecode(buf []byte) error {
|
func (t *Time) UnmarshalBinary(data []byte) error {
|
||||||
|
buf := data
|
||||||
if len(buf) == 0 {
|
if len(buf) == 0 {
|
||||||
return errors.New("Time.GobDecode: no data")
|
return errors.New("Time.UnmarshalBinary: no data")
|
||||||
}
|
}
|
||||||
|
|
||||||
if buf[0] != timeGobVersion {
|
if buf[0] != timeBinaryVersion {
|
||||||
return errors.New("Time.GobDecode: unsupported version")
|
return errors.New("Time.UnmarshalBinary: unsupported version")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(buf) != /*version*/ 1+ /*sec*/ 8+ /*nsec*/ 4+ /*zone offset*/ 2 {
|
if len(buf) != /*version*/ 1+ /*sec*/ 8+ /*nsec*/ 4+ /*zone offset*/ 2 {
|
||||||
return errors.New("Time.GobDecode: invalid length")
|
return errors.New("Time.UnmarshalBinary: invalid length")
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = buf[1:]
|
buf = buf[1:]
|
||||||
@ -915,8 +916,22 @@ func (t *Time) GobDecode(buf []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(rsc): Remove GobEncoder, GobDecoder, MarshalJSON, UnmarshalJSON in Go 2.
|
||||||
|
// The same semantics will be provided by the generic MarshalBinary, MarshalText,
|
||||||
|
// UnmarshalBinary, UnmarshalText.
|
||||||
|
|
||||||
|
// GobEncode implements the gob.GobEncoder interface.
|
||||||
|
func (t Time) GobEncode() ([]byte, error) {
|
||||||
|
return t.MarshalBinary()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GobDecode implements the gob.GobDecoder interface.
|
||||||
|
func (t *Time) GobDecode(data []byte) error {
|
||||||
|
return t.UnmarshalBinary(data)
|
||||||
|
}
|
||||||
|
|
||||||
// MarshalJSON implements the json.Marshaler interface.
|
// MarshalJSON implements the json.Marshaler interface.
|
||||||
// Time is formatted as RFC3339.
|
// The time is a quoted string in RFC 3339 format, with sub-second precision added if present.
|
||||||
func (t Time) MarshalJSON() ([]byte, error) {
|
func (t Time) MarshalJSON() ([]byte, error) {
|
||||||
if y := t.Year(); y < 0 || y >= 10000 {
|
if y := t.Year(); y < 0 || y >= 10000 {
|
||||||
return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")
|
return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")
|
||||||
@ -925,13 +940,30 @@ func (t Time) MarshalJSON() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||||
// Time is expected in RFC3339 format.
|
// The time is expected to be a quoted string in RFC 3339 format.
|
||||||
func (t *Time) UnmarshalJSON(data []byte) (err error) {
|
func (t *Time) UnmarshalJSON(data []byte) (err error) {
|
||||||
// Fractional seconds are handled implicitly by Parse.
|
// Fractional seconds are handled implicitly by Parse.
|
||||||
*t, err = Parse(`"`+RFC3339+`"`, string(data))
|
*t, err = Parse(`"`+RFC3339+`"`, string(data))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarshalText implements the encoding.TextMarshaler interface.
|
||||||
|
// The time is formatted in RFC 3339 format, with sub-second precision added if present.
|
||||||
|
func (t Time) MarshalText() ([]byte, error) {
|
||||||
|
if y := t.Year(); y < 0 || y >= 10000 {
|
||||||
|
return nil, errors.New("Time.MarshalText: year outside of range [0,9999]")
|
||||||
|
}
|
||||||
|
return []byte(t.Format(RFC3339Nano)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||||
|
// The time is expected to be in RFC 3339 format.
|
||||||
|
func (t *Time) UnmarshalText(data []byte) (err error) {
|
||||||
|
// Fractional seconds are handled implicitly by Parse.
|
||||||
|
*t, err = Parse(RFC3339, string(data))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Unix returns the local Time corresponding to the given Unix time,
|
// Unix returns the local Time corresponding to the given Unix time,
|
||||||
// sec seconds and nsec nanoseconds since January 1, 1970 UTC.
|
// sec seconds and nsec nanoseconds since January 1, 1970 UTC.
|
||||||
// It is valid to pass nsec outside the range [0, 999999999].
|
// It is valid to pass nsec outside the range [0, 999999999].
|
||||||
|
@ -1148,9 +1148,9 @@ var invalidEncodingTests = []struct {
|
|||||||
bytes []byte
|
bytes []byte
|
||||||
want string
|
want string
|
||||||
}{
|
}{
|
||||||
{[]byte{}, "Time.GobDecode: no data"},
|
{[]byte{}, "Time.UnmarshalBinary: no data"},
|
||||||
{[]byte{0, 2, 3}, "Time.GobDecode: unsupported version"},
|
{[]byte{0, 2, 3}, "Time.UnmarshalBinary: unsupported version"},
|
||||||
{[]byte{1, 2, 3}, "Time.GobDecode: invalid length"},
|
{[]byte{1, 2, 3}, "Time.UnmarshalBinary: invalid length"},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInvalidTimeGob(t *testing.T) {
|
func TestInvalidTimeGob(t *testing.T) {
|
||||||
@ -1160,6 +1160,10 @@ func TestInvalidTimeGob(t *testing.T) {
|
|||||||
if err == nil || err.Error() != tt.want {
|
if err == nil || err.Error() != tt.want {
|
||||||
t.Errorf("time.GobDecode(%#v) error = %v, want %v", tt.bytes, err, tt.want)
|
t.Errorf("time.GobDecode(%#v) error = %v, want %v", tt.bytes, err, tt.want)
|
||||||
}
|
}
|
||||||
|
err = ignored.UnmarshalBinary(tt.bytes)
|
||||||
|
if err == nil || err.Error() != tt.want {
|
||||||
|
t.Errorf("time.UnmarshalBinary(%#v) error = %v, want %v", tt.bytes, err, tt.want)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1167,10 +1171,10 @@ var notEncodableTimes = []struct {
|
|||||||
time Time
|
time Time
|
||||||
want string
|
want string
|
||||||
}{
|
}{
|
||||||
{Date(0, 1, 2, 3, 4, 5, 6, FixedZone("", 1)), "Time.GobEncode: zone offset has fractional minute"},
|
{Date(0, 1, 2, 3, 4, 5, 6, FixedZone("", 1)), "Time.MarshalBinary: zone offset has fractional minute"},
|
||||||
{Date(0, 1, 2, 3, 4, 5, 6, FixedZone("", -1*60)), "Time.GobEncode: unexpected zone offset"},
|
{Date(0, 1, 2, 3, 4, 5, 6, FixedZone("", -1*60)), "Time.MarshalBinary: unexpected zone offset"},
|
||||||
{Date(0, 1, 2, 3, 4, 5, 6, FixedZone("", -32769*60)), "Time.GobEncode: unexpected zone offset"},
|
{Date(0, 1, 2, 3, 4, 5, 6, FixedZone("", -32769*60)), "Time.MarshalBinary: unexpected zone offset"},
|
||||||
{Date(0, 1, 2, 3, 4, 5, 6, FixedZone("", 32768*60)), "Time.GobEncode: unexpected zone offset"},
|
{Date(0, 1, 2, 3, 4, 5, 6, FixedZone("", 32768*60)), "Time.MarshalBinary: unexpected zone offset"},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNotGobEncodableTime(t *testing.T) {
|
func TestNotGobEncodableTime(t *testing.T) {
|
||||||
@ -1179,6 +1183,10 @@ func TestNotGobEncodableTime(t *testing.T) {
|
|||||||
if err == nil || err.Error() != tt.want {
|
if err == nil || err.Error() != tt.want {
|
||||||
t.Errorf("%v GobEncode error = %v, want %v", tt.time, err, tt.want)
|
t.Errorf("%v GobEncode error = %v, want %v", tt.time, err, tt.want)
|
||||||
}
|
}
|
||||||
|
_, err = tt.time.MarshalBinary()
|
||||||
|
if err == nil || err.Error() != tt.want {
|
||||||
|
t.Errorf("%v MarshalBinary error = %v, want %v", tt.time, err, tt.want)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user