aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHowJMay <vulxj0j8j8@gmail.com>2021-09-16 18:22:06 +0000
committerIan Lance Taylor <iant@golang.org>2021-09-17 23:18:47 +0000
commitac7c34767dd710643f5f5fea1720a18cc392b7f8 (patch)
tree95095960f57de2ccc379be332a4707d66f63b7b2
parent07b30a4f77cf89a283c45c338f0cfcb68e15aab1 (diff)
downloadgo-ac7c34767dd710643f5f5fea1720a18cc392b7f8.tar.gz
go-ac7c34767dd710643f5f5fea1720a18cc392b7f8.zip
time: support fractional timezone minutes in MarshalBinary
If the time is in 'LMT' and has fractional minute, then `MarshalBinary()` and `UnmarshalBinary()` will encode/decode the time in `timeBinaryVersionV2` in which the fractional minute is at bit 15 and 16, and presented in seconds. Fixes #39616 Change-Id: Ib762fb5fa26f54b1a8377a5dde0b994dd5a1236a GitHub-Last-Rev: 455d7a2496ba67d4a82890b14d57000e1a8a1415 GitHub-Pull-Request: golang/go#40293 Reviewed-on: https://go-review.googlesource.com/c/go/+/243402 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org> Trust: Carlos Amedee <carlos@golang.org>
-rw-r--r--src/time/time.go30
-rw-r--r--src/time/time_test.go32
2 files changed, 55 insertions, 7 deletions
diff --git a/src/time/time.go b/src/time/time.go
index 1919ebbc2c..edf0c62610 100644
--- a/src/time/time.go
+++ b/src/time/time.go
@@ -1162,19 +1162,26 @@ func (t Time) UnixNano() int64 {
return (t.unixSec())*1e9 + int64(t.nsec())
}
-const timeBinaryVersion byte = 1
+const (
+ timeBinaryVersionV1 byte = iota + 1 // For general situation
+ timeBinaryVersionV2 // For LMT only
+)
// MarshalBinary implements the encoding.BinaryMarshaler interface.
func (t Time) MarshalBinary() ([]byte, error) {
var offsetMin int16 // minutes east of UTC. -1 is UTC.
+ var offsetSec int8
+ version := timeBinaryVersionV1
if t.Location() == UTC {
offsetMin = -1
} else {
_, offset := t.Zone()
if offset%60 != 0 {
- return nil, errors.New("Time.MarshalBinary: zone offset has fractional minute")
+ version = timeBinaryVersionV2
+ offsetSec = int8(offset % 60)
}
+
offset /= 60
if offset < -32768 || offset == -1 || offset > 32767 {
return nil, errors.New("Time.MarshalBinary: unexpected zone offset")
@@ -1185,8 +1192,8 @@ func (t Time) MarshalBinary() ([]byte, error) {
sec := t.sec()
nsec := t.nsec()
enc := []byte{
- timeBinaryVersion, // byte 0 : version
- byte(sec >> 56), // bytes 1-8: seconds
+ version, // byte 0 : version
+ byte(sec >> 56), // bytes 1-8: seconds
byte(sec >> 48),
byte(sec >> 40),
byte(sec >> 32),
@@ -1201,6 +1208,9 @@ func (t Time) MarshalBinary() ([]byte, error) {
byte(offsetMin >> 8), // bytes 13-14: zone offset in minutes
byte(offsetMin),
}
+ if version == timeBinaryVersionV2 {
+ enc = append(enc, byte(offsetSec))
+ }
return enc, nil
}
@@ -1212,11 +1222,16 @@ func (t *Time) UnmarshalBinary(data []byte) error {
return errors.New("Time.UnmarshalBinary: no data")
}
- if buf[0] != timeBinaryVersion {
+ version := buf[0]
+ if version != timeBinaryVersionV1 && version != timeBinaryVersionV2 {
return errors.New("Time.UnmarshalBinary: unsupported version")
}
- if len(buf) != /*version*/ 1+ /*sec*/ 8+ /*nsec*/ 4+ /*zone offset*/ 2 {
+ wantLen := /*version*/ 1 + /*sec*/ 8 + /*nsec*/ 4 + /*zone offset*/ 2
+ if version == timeBinaryVersionV2 {
+ wantLen++
+ }
+ if len(buf) != wantLen {
return errors.New("Time.UnmarshalBinary: invalid length")
}
@@ -1229,6 +1244,9 @@ func (t *Time) UnmarshalBinary(data []byte) error {
buf = buf[4:]
offset := int(int16(buf[1])|int16(buf[0])<<8) * 60
+ if version == timeBinaryVersionV2 {
+ offset += int(buf[2])
+ }
*t = Time{}
t.wall = uint64(nsec)
diff --git a/src/time/time_test.go b/src/time/time_test.go
index cea5f2d3f5..e2fb897b6d 100644
--- a/src/time/time_test.go
+++ b/src/time/time_test.go
@@ -767,7 +767,6 @@ var notEncodableTimes = []struct {
time Time
want string
}{
- {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.MarshalBinary: 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.MarshalBinary: unexpected zone offset"},
@@ -1437,6 +1436,37 @@ func TestMarshalBinaryZeroTime(t *testing.T) {
}
}
+func TestMarshalBinaryVersion2(t *testing.T) {
+ t0, err := Parse(RFC3339, "1880-01-01T00:00:00Z")
+ if err != nil {
+ t.Errorf("Failed to parse time, error = %v", err)
+ }
+ loc, err := LoadLocation("US/Eastern")
+ if err != nil {
+ t.Errorf("Failed to load location, error = %v", err)
+ }
+ t1 := t0.In(loc)
+ b, err := t1.MarshalBinary()
+ if err != nil {
+ t.Errorf("Failed to Marshal, error = %v", err)
+ }
+
+ t2 := Time{}
+ err = t2.UnmarshalBinary(b)
+ if err != nil {
+ t.Errorf("Failed to Unmarshal, error = %v", err)
+ }
+
+ if !(t0.Equal(t1) && t1.Equal(t2)) {
+ if !t0.Equal(t1) {
+ t.Errorf("The result t1: %+v after Marshal is not matched original t0: %+v", t1, t0)
+ }
+ if !t1.Equal(t2) {
+ t.Errorf("The result t2: %+v after Unmarshal is not matched original t1: %+v", t2, t1)
+ }
+ }
+}
+
// Issue 17720: Zero value of time.Month fails to print
func TestZeroMonthString(t *testing.T) {
if got, want := Month(0).String(), "%!Month(0)"; got != want {