diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e987a2..356a9af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ allowing users to use pointer with json. ### Added - Add `String` method to `atomic.Pointer[T]` type allowing users to safely print underlying values of pointers. +- Support JSON serialization and deserialization of `atomic.Time` [1.11.0]: https://github.com/uber-go/atomic/compare/v1.10.0...v1.11.0 diff --git a/time.go b/time.go index cc2a230..6dd0c12 100644 --- a/time.go +++ b/time.go @@ -53,3 +53,18 @@ func (x *Time) Load() time.Time { func (x *Time) Store(val time.Time) { x.v.Store(packTime(val)) } + +// MarshalText encodes the wrapped time.Time into string. +func (x *Time) MarshalText() ([]byte, error) { + return x.Load().MarshalText() +} + +// UnmarshalText decodes a time.Time from string. +func (x *Time) UnmarshalText(b []byte) error { + var v time.Time + if err := v.UnmarshalText(b); err != nil { + return err + } + x.Store(v) + return nil +} diff --git a/time_ext.go b/time_ext.go index 1e3dc97..10b3a22 100644 --- a/time_ext.go +++ b/time_ext.go @@ -22,7 +22,7 @@ package atomic import "time" -//go:generate bin/gen-atomicwrapper -name=Time -type=time.Time -wrapped=Value -pack=packTime -unpack=unpackTime -imports time -file=time.go +//go:generate bin/gen-atomicwrapper -name=Time -type=time.Time -wrapped=Value -pack=packTime -unpack=unpackTime -json -imports time -file=time.go func packTime(t time.Time) interface{} { return t diff --git a/time_test.go b/time_test.go index 83ac022..8471dfb 100644 --- a/time_test.go +++ b/time_test.go @@ -21,6 +21,7 @@ package atomic import ( + "encoding/json" "testing" "time" @@ -71,6 +72,31 @@ func TestLargeTime(t *testing.T) { atom.Store(dayBeforePast) assert.Equal(t, 1677, atom.Load().Year()) }) + + t.Run("JSON/Marshal", func(t *testing.T) { + now := time.Now() + atom := NewTime(now) + bytes, err := json.Marshal(atom) + require.NoError(t, err, "json.Marshal errored unexpectedly.") + + oBytes, err := json.Marshal(now) + require.NoError(t, err, "json.Marshal errored unexpectedly on the native time.Time.") + require.Equal(t, oBytes, bytes, "json.Marshal encoded the wrong bytes.") + }) + + t.Run("JSON/Unmarshal", func(t *testing.T) { + now := time.Now() + atom := NewTime(time.Time{}) + + oBytes, err := json.Marshal(now) + require.NoError(t, err, "json.Marshal errored unexpectedly on the native time.Time.") + err = json.Unmarshal(oBytes, &atom) + require.NoError(t, err, "json.Unmarshal errored unexpectedly.") + // NOTE: https://pkg.go.dev/time#Time.MarshalJSON, the time is formatted as RFC 3339 + // example: 2022-11-25T21:06:44.6023404+01:00 + // So we cannot compare now and atom.Load() because we lack nanoseconds + require.Equal(t, now.UnixMicro(), atom.Load().UnixMicro(), "json.Unmarshal didn't set the correct value.") + }) } func TestMonotonic(t *testing.T) {