mirror of
https://github.com/golang/go
synced 2024-11-26 04:58:00 -07:00
time: implement the encoding.(Binary|Text)Appender for Time
"Time.Marshal(Binary|Text)" could also gain some performance improvements. Here is the benchmark highlight: │ old │ new │ │ sec/op │ sec/op vs base │ MarshalText-8 104.00n ± 3% 67.27n ± 2% -35.32% (p=0.000 n=10) MarshalBinary-8 31.77n ± 2% 12.13n ± 1% -61.82% (p=0.000 n=10) geomean 57.48n 28.57n -50.30% │ old │ new │ │ B/op │ B/op vs base │ MarshalText-8 48.00 ± 0% 0.00 ± 0% -100.00% (p=0.000 n=10) MarshalBinary-8 16.00 ± 0% 0.00 ± 0% -100.00% (p=0.000 n=10) │ old │ new │ │ allocs/op │ allocs/op vs base │ MarshalText-8 1.000 ± 0% 0.000 ± 0% -100.00% (p=0.000 n=10) MarshalBinary-8 1.000 ± 0% 0.000 ± 0% -100.00% (p=0.000 n=10) For #62384
This commit is contained in:
parent
27093581b2
commit
e04f8df9c2
@ -9,3 +9,5 @@ pkg math/big, method (*Float) AppendText([]uint8) ([]uint8, error) #62384
|
|||||||
pkg math/big, method (*Int) AppendText([]uint8) ([]uint8, error) #62384
|
pkg math/big, method (*Int) AppendText([]uint8) ([]uint8, error) #62384
|
||||||
pkg math/big, method (*Rat) AppendText([]uint8) ([]uint8, error) #62384
|
pkg math/big, method (*Rat) AppendText([]uint8) ([]uint8, error) #62384
|
||||||
pkg regexp, method (*Regexp) AppendText([]uint8) ([]uint8, error) #62384
|
pkg regexp, method (*Regexp) AppendText([]uint8) ([]uint8, error) #62384
|
||||||
|
pkg time, method (Time) AppendBinary([]uint8) ([]uint8, error) #62384
|
||||||
|
pkg time, method (Time) AppendText([]uint8) ([]uint8, error) #62384
|
||||||
|
1
doc/next/6-stdlib/99-minor/time/62384.md
Normal file
1
doc/next/6-stdlib/99-minor/time/62384.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
[Time] now implements the [encoding.BinaryAppender] and [encoding.TextAppender] interfaces.
|
@ -119,9 +119,9 @@ import (
|
|||||||
// these methods does not change the actual instant it represents, only the time
|
// these methods does not change the actual instant it represents, only the time
|
||||||
// zone in which to interpret it.
|
// zone in which to interpret it.
|
||||||
//
|
//
|
||||||
// Representations of a Time value saved by the [Time.GobEncode], [Time.MarshalBinary],
|
// Representations of a Time value saved by the [Time.GobEncode], [Time.MarshalBinary], [Time.AppendBinary],
|
||||||
// [Time.MarshalJSON], and [Time.MarshalText] methods store the [Time.Location]'s offset, but not
|
// [Time.MarshalJSON], [Time.MarshalText] and [Time.AppendText] methods store the [Time.Location]'s offset,
|
||||||
// the location name. They therefore lose information about Daylight Saving Time.
|
// but not the location name. They therefore lose information about Daylight Saving Time.
|
||||||
//
|
//
|
||||||
// In addition to the required “wall clock” reading, a Time may contain an optional
|
// In addition to the required “wall clock” reading, a Time may contain an optional
|
||||||
// reading of the current process's monotonic clock, to provide additional precision
|
// reading of the current process's monotonic clock, to provide additional precision
|
||||||
@ -1435,8 +1435,8 @@ const (
|
|||||||
timeBinaryVersionV2 // For LMT only
|
timeBinaryVersionV2 // For LMT only
|
||||||
)
|
)
|
||||||
|
|
||||||
// MarshalBinary implements the encoding.BinaryMarshaler interface.
|
// AppendBinary implements the [encoding.BinaryAppender] interface.
|
||||||
func (t Time) MarshalBinary() ([]byte, error) {
|
func (t Time) AppendBinary(b []byte) ([]byte, error) {
|
||||||
var offsetMin int16 // minutes east of UTC. -1 is UTC.
|
var offsetMin int16 // minutes east of UTC. -1 is UTC.
|
||||||
var offsetSec int8
|
var offsetSec int8
|
||||||
version := timeBinaryVersionV1
|
version := timeBinaryVersionV1
|
||||||
@ -1452,38 +1452,46 @@ func (t Time) MarshalBinary() ([]byte, error) {
|
|||||||
|
|
||||||
offset /= 60
|
offset /= 60
|
||||||
if offset < -32768 || offset == -1 || offset > 32767 {
|
if offset < -32768 || offset == -1 || offset > 32767 {
|
||||||
return nil, errors.New("Time.MarshalBinary: unexpected zone offset")
|
return b, errors.New("Time.MarshalBinary: unexpected zone offset")
|
||||||
}
|
}
|
||||||
offsetMin = int16(offset)
|
offsetMin = int16(offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
sec := t.sec()
|
sec := t.sec()
|
||||||
nsec := t.nsec()
|
nsec := t.nsec()
|
||||||
enc := []byte{
|
b = append(b,
|
||||||
version, // byte 0 : version
|
version, // byte 0 : version
|
||||||
byte(sec >> 56), // bytes 1-8: seconds
|
byte(sec>>56), // bytes 1-8: seconds
|
||||||
byte(sec >> 48),
|
byte(sec>>48),
|
||||||
byte(sec >> 40),
|
byte(sec>>40),
|
||||||
byte(sec >> 32),
|
byte(sec>>32),
|
||||||
byte(sec >> 24),
|
byte(sec>>24),
|
||||||
byte(sec >> 16),
|
byte(sec>>16),
|
||||||
byte(sec >> 8),
|
byte(sec>>8),
|
||||||
byte(sec),
|
byte(sec),
|
||||||
byte(nsec >> 24), // bytes 9-12: nanoseconds
|
byte(nsec>>24), // bytes 9-12: nanoseconds
|
||||||
byte(nsec >> 16),
|
byte(nsec>>16),
|
||||||
byte(nsec >> 8),
|
byte(nsec>>8),
|
||||||
byte(nsec),
|
byte(nsec),
|
||||||
byte(offsetMin >> 8), // bytes 13-14: zone offset in minutes
|
byte(offsetMin>>8), // bytes 13-14: zone offset in minutes
|
||||||
byte(offsetMin),
|
byte(offsetMin),
|
||||||
}
|
)
|
||||||
if version == timeBinaryVersionV2 {
|
if version == timeBinaryVersionV2 {
|
||||||
enc = append(enc, byte(offsetSec))
|
b = append(b, byte(offsetSec))
|
||||||
}
|
}
|
||||||
|
return b, nil
|
||||||
return enc, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
|
// MarshalBinary implements the [encoding.BinaryMarshaler] interface.
|
||||||
|
func (t Time) MarshalBinary() ([]byte, error) {
|
||||||
|
b, err := t.AppendBinary(make([]byte, 0, 16))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBinary implements the [encoding.BinaryUnmarshaler] interface.
|
||||||
func (t *Time) UnmarshalBinary(data []byte) error {
|
func (t *Time) UnmarshalBinary(data []byte) error {
|
||||||
buf := data
|
buf := data
|
||||||
if len(buf) == 0 {
|
if len(buf) == 0 {
|
||||||
@ -1576,12 +1584,11 @@ func (t *Time) UnmarshalJSON(data []byte) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalText implements the [encoding.TextMarshaler] interface.
|
// AppendText implements the [encoding.TextAppender] interface.
|
||||||
// The time is formatted in RFC 3339 format with sub-second precision.
|
// The time is formatted in RFC 3339 format with sub-second precision.
|
||||||
// If the timestamp cannot be represented as valid RFC 3339
|
// If the timestamp cannot be represented as valid RFC 3339
|
||||||
// (e.g., the year is out of range), then an error is reported.
|
// (e.g., the year is out of range), then an error is returned.
|
||||||
func (t Time) MarshalText() ([]byte, error) {
|
func (t Time) AppendText(b []byte) ([]byte, error) {
|
||||||
b := make([]byte, 0, len(RFC3339Nano))
|
|
||||||
b, err := t.appendStrictRFC3339(b)
|
b, err := t.appendStrictRFC3339(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("Time.MarshalText: " + err.Error())
|
return nil, errors.New("Time.MarshalText: " + err.Error())
|
||||||
@ -1589,6 +1596,14 @@ func (t Time) MarshalText() ([]byte, error) {
|
|||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarshalText implements the [encoding.TextMarshaler] interface. The output
|
||||||
|
// matches that of calling the [Time.AppendText] method.
|
||||||
|
//
|
||||||
|
// See [Time.AppendText] for more information.
|
||||||
|
func (t Time) MarshalText() ([]byte, error) {
|
||||||
|
return t.AppendText(make([]byte, 0, len(RFC3339Nano)))
|
||||||
|
}
|
||||||
|
|
||||||
// UnmarshalText implements the [encoding.TextUnmarshaler] interface.
|
// UnmarshalText implements the [encoding.TextUnmarshaler] interface.
|
||||||
// The time must be in the RFC 3339 format.
|
// The time must be in the RFC 3339 format.
|
||||||
func (t *Time) UnmarshalText(data []byte) error {
|
func (t *Time) UnmarshalText(data []byte) error {
|
||||||
|
@ -1403,6 +1403,13 @@ var defaultLocTests = []struct {
|
|||||||
{"UnixMilli", func(t1, t2 Time) bool { return t1.UnixMilli() == t2.UnixMilli() }},
|
{"UnixMilli", func(t1, t2 Time) bool { return t1.UnixMilli() == t2.UnixMilli() }},
|
||||||
{"UnixMicro", func(t1, t2 Time) bool { return t1.UnixMicro() == t2.UnixMicro() }},
|
{"UnixMicro", func(t1, t2 Time) bool { return t1.UnixMicro() == t2.UnixMicro() }},
|
||||||
|
|
||||||
|
{"AppendBinary", func(t1, t2 Time) bool {
|
||||||
|
buf1 := make([]byte, 4, 32)
|
||||||
|
buf2 := make([]byte, 4, 32)
|
||||||
|
a1, b1 := t1.AppendBinary(buf1)
|
||||||
|
a2, b2 := t2.AppendBinary(buf2)
|
||||||
|
return bytes.Equal(a1[4:], a2[4:]) && b1 == b2
|
||||||
|
}},
|
||||||
{"MarshalBinary", func(t1, t2 Time) bool {
|
{"MarshalBinary", func(t1, t2 Time) bool {
|
||||||
a1, b1 := t1.MarshalBinary()
|
a1, b1 := t1.MarshalBinary()
|
||||||
a2, b2 := t2.MarshalBinary()
|
a2, b2 := t2.MarshalBinary()
|
||||||
@ -1418,6 +1425,14 @@ var defaultLocTests = []struct {
|
|||||||
a2, b2 := t2.MarshalJSON()
|
a2, b2 := t2.MarshalJSON()
|
||||||
return bytes.Equal(a1, a2) && b1 == b2
|
return bytes.Equal(a1, a2) && b1 == b2
|
||||||
}},
|
}},
|
||||||
|
{"AppendText", func(t1, t2 Time) bool {
|
||||||
|
maxCap := len(RFC3339Nano) + 4
|
||||||
|
buf1 := make([]byte, 4, maxCap)
|
||||||
|
buf2 := make([]byte, 4, maxCap)
|
||||||
|
a1, b1 := t1.AppendText(buf1)
|
||||||
|
a2, b2 := t2.AppendText(buf2)
|
||||||
|
return bytes.Equal(a1[4:], a2[4:]) && b1 == b2
|
||||||
|
}},
|
||||||
{"MarshalText", func(t1, t2 Time) bool {
|
{"MarshalText", func(t1, t2 Time) bool {
|
||||||
a1, b1 := t1.MarshalText()
|
a1, b1 := t1.MarshalText()
|
||||||
a2, b2 := t2.MarshalText()
|
a2, b2 := t2.MarshalText()
|
||||||
@ -1510,6 +1525,13 @@ func BenchmarkMarshalText(b *testing.B) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkMarshalBinary(b *testing.B) {
|
||||||
|
t := Now()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
t.MarshalBinary()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkParse(b *testing.B) {
|
func BenchmarkParse(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
Parse(ANSIC, "Mon Jan 2 15:04:05 2006")
|
Parse(ANSIC, "Mon Jan 2 15:04:05 2006")
|
||||||
|
Loading…
Reference in New Issue
Block a user