From 399d90e69b6c9007a0203ebc4df1df5b05ea5caa Mon Sep 17 00:00:00 2001 From: Vilen Topchii <32271530+vtopc@users.noreply.github.com> Date: Sat, 27 Jan 2024 13:02:06 +0200 Subject: [PATCH 1/5] actions/setup-go@v5 --- .github/workflows/workflow.yaml | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/.github/workflows/workflow.yaml b/.github/workflows/workflow.yaml index 72b6333..f15cbaf 100644 --- a/.github/workflows/workflow.yaml +++ b/.github/workflows/workflow.yaml @@ -19,19 +19,10 @@ jobs: - uses: actions/checkout@v3 - name: Install Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version: ${{ matrix.go-version }} - - uses: actions/cache@v3 - with: - path: | - ~/.cache/go-build - ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- - - name: Download deps run: go mod download From 8476011e0e42cd5735d811601c0e98523274df32 Mon Sep 17 00:00:00 2001 From: Vilen Topchii <32271530+vtopc@users.noreply.github.com> Date: Sat, 27 Jan 2024 13:02:11 +0200 Subject: [PATCH 2/5] bump deps --- go.mod | 6 +++--- go.sum | 14 ++++++++++---- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 3bd0d7c..1e4f68b 100644 --- a/go.mod +++ b/go.mod @@ -2,10 +2,10 @@ module github.com/vtopc/epoch go 1.17 -require github.com/stretchr/testify v1.6.1 +require github.com/stretchr/testify v1.8.4 require ( - github.com/davecgh/go-spew v1.1.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index afe7890..479781e 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,17 @@ -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From 9e12c8eb925ec900b44441180f9d010ca035301e Mon Sep 17 00:00:00 2001 From: Vilen Topchii <32271530+vtopc@users.noreply.github.com> Date: Sat, 27 Jan 2024 14:26:02 +0200 Subject: [PATCH 3/5] added FloatMS --- epoch.go | 14 ++++- epoch_test.go | 7 +++ float_ms.go | 40 ++++++++++++ float_ms_test.go | 147 +++++++++++++++++++++++++++++++++++++++++++ milliseconds.go | 5 -- milliseconds_test.go | 2 - 6 files changed, 207 insertions(+), 8 deletions(-) create mode 100644 epoch_test.go create mode 100644 float_ms.go create mode 100644 float_ms_test.go diff --git a/epoch.go b/epoch.go index 327e519..3de65b4 100644 --- a/epoch.go +++ b/epoch.go @@ -1,7 +1,19 @@ package epoch -import "strconv" +import ( + "strconv" + "time" +) + +const ( + msPerS = int64(time.Second / time.Millisecond) + nsPerMs = int64(time.Millisecond) +) func parseInt64(s string) (int64, error) { return strconv.ParseInt(s, 10, 64) } + +func parseFloat64(s string) (float64, error) { + return strconv.ParseFloat(s, 64) +} diff --git a/epoch_test.go b/epoch_test.go new file mode 100644 index 0000000..31b81d5 --- /dev/null +++ b/epoch_test.go @@ -0,0 +1,7 @@ +package epoch + +import ( + "time" +) + +var tmsTime = time.Unix(1136239445, 999*nsPerMs) diff --git a/float_ms.go b/float_ms.go new file mode 100644 index 0000000..d1cc949 --- /dev/null +++ b/float_ms.go @@ -0,0 +1,40 @@ +package epoch + +import ( + "encoding/json" + "fmt" + "math" + "time" +) + +// FloatMS - integer part of timestamp represents seconds and fractional - milliseconds since +// the Epoch(Unix time), e.g. 1136239445.999 +// Inherits built-in time.Time type, thus has all it methods, but has custom serializer and +// deserializer(converts float timestamp into built-in time.Time and vice versa). +type FloatMS struct { + time.Time +} + +// NewFloatMS - returns FloatMS +func NewFloatMS(t time.Time) FloatMS { + return FloatMS{Time: t} +} + +// MarshalJSON - implements JSON marshaling interface +func (s FloatMS) MarshalJSON() ([]byte, error) { + milli := s.Time.UnixMilli() + f := float64(milli) / float64(msPerS) + return json.Marshal(f) +} + +func (s *FloatMS) UnmarshalJSON(data []byte) error { + f, err := parseFloat64(string(data)) + if err != nil { + return fmt.Errorf("failed to parse epoch.FloatMS: %w", err) + } + + i, frac := math.Modf(f) + s.Time = time.Unix(int64(i), int64(frac*1_000)*nsPerMs) + + return nil +} diff --git a/float_ms_test.go b/float_ms_test.go new file mode 100644 index 0000000..7109351 --- /dev/null +++ b/float_ms_test.go @@ -0,0 +1,147 @@ +package epoch + +import ( + "encoding/json" + "errors" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type testFloatMSValueStruct struct { + Timestamp FloatMS `json:"timestamp"` +} + +type testFloatMSPointerStruct struct { + Timestamp *FloatMS `json:"timestamp"` +} + +func TestFloatMS_Marshal(t *testing.T) { + const js = `{"timestamp":1136239445.999}` + + t.Run("value", func(t *testing.T) { + tests := map[string]struct { + v testFloatMSValueStruct + want string + wantErr error + }{ + "positive": { + v: testFloatMSValueStruct{ + Timestamp: FloatMS{Time: tmsTime}, + }, + want: js, + }, + "rounding": { + v: testFloatMSValueStruct{ + Timestamp: FloatMS{Time: time.Unix(1136239445, 500999000)}, + }, + want: `{"timestamp":1136239445.5}`, + }, + } + + for name, tc := range tests { + tc := tc + t.Run(name, func(t *testing.T) { + got, err := json.Marshal(tc.v) + require.NoError(t, err) + assert.Equal(t, tc.want, string(got)) + }) + } + }) + + t.Run("pointer", func(t *testing.T) { + tests := map[string]struct { + v testFloatMSPointerStruct + want string + wantErr error + }{ + "positive": { + v: testFloatMSPointerStruct{ + Timestamp: &FloatMS{Time: tmsTime}, + }, + want: js, + }, + "nil": { + v: testFloatMSPointerStruct{ + Timestamp: nil, + }, + want: `{"timestamp":null}`, + }, + } + + for name, tc := range tests { + tc := tc + t.Run(name, func(t *testing.T) { + got, err := json.Marshal(tc.v) + require.NoError(t, err) + assert.Equal(t, tc.want, string(got)) + }) + } + }) +} + +func TestFloatMS_Unmarshal(t *testing.T) { + const js = `{"timestamp":1136239445.999}` + + t.Run("value", func(t *testing.T) { + tests := map[string]struct { + v string + want FloatMS + wantErr error + }{ + "positive": { + v: js, + want: FloatMS{Time: tmsTime}, + }, + "not_int": { + v: `{"timestamp":"text"}`, + wantErr: errors.New("failed to parse epoch.FloatMS: strconv.ParseFloat: parsing \"\\\"text\\\"\": invalid syntax"), + }, + } + + for name, tc := range tests { + tc := tc + t.Run(name, func(t *testing.T) { + var got testFloatMSValueStruct + err := json.Unmarshal([]byte(tc.v), &got) + if tc.wantErr == nil { + require.NoError(t, err) + assert.Equal(t, tc.want, got.Timestamp) + + return + } + + require.EqualError(t, err, tc.wantErr.Error()) + }) + } + }) + + t.Run("pointer", func(t *testing.T) { + tests := map[string]struct { + v string + want *FloatMS + wantErr error + }{ + "positive": { + v: js, + want: &FloatMS{Time: tmsTime}, + }, + "nil": { + v: `{"timestamp":null}`, + want: nil, + }, + } + + for name, tc := range tests { + tc := tc + t.Run(name, func(t *testing.T) { + var got testFloatMSPointerStruct + err := json.Unmarshal([]byte(tc.v), &got) + require.NoError(t, err) + assert.Equal(t, tc.want, got.Timestamp) + }) + } + }) +} diff --git a/milliseconds.go b/milliseconds.go index 0efb79e..95c0a4d 100644 --- a/milliseconds.go +++ b/milliseconds.go @@ -35,11 +35,6 @@ func (m *Milliseconds) UnmarshalJSON(data []byte) error { return nil } -const ( - msPerS = int64(time.Second / time.Millisecond) - nsPerMs = int64(time.Millisecond) -) - func msToTime(ms int64) time.Time { s := ms / msPerS ns := (ms % msPerS) * nsPerMs diff --git a/milliseconds_test.go b/milliseconds_test.go index 4d3139e..2ca7c2f 100644 --- a/milliseconds_test.go +++ b/milliseconds_test.go @@ -21,8 +21,6 @@ type testMillisecondsPointerStruct struct { const tms = int64(1136239445999) -var tmsTime = time.Unix(1136239445, 999*nsPerMs) - func TestNewMilliseconds(t *testing.T) { const ns = 123 * nsPerMs t.Run("seconds", func(t *testing.T) { From 9a67fe9bb54ad5aa9781b32068f0ffd2d143cbdb Mon Sep 17 00:00:00 2001 From: Vilen Topchii <32271530+vtopc@users.noreply.github.com> Date: Sat, 27 Jan 2024 14:30:09 +0200 Subject: [PATCH 4/5] readme --- README.md | 13 ++++++++++--- float_ms.go | 4 +++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 96c0f04..c7ef8c2 100644 --- a/README.md +++ b/README.md @@ -68,11 +68,18 @@ Same as epoch.Milliseconds, but for strings, e.g.: {"timestamp":"1136239445999"} ``` -## Additional terms of use for users from Russia and Belarus +## FloatMS +Integer part of timestamp represents seconds and fractional - milliseconds since the Epoch(Unix time), +e.g.: +```json + {"timestamp":1136239445.999} +``` + +## Additional terms of use for users from russia and Belarus By using the code provided in these repositories you agree with the following: -* Russia has [illegally annexed Crimea in 2014](https://en.wikipedia.org/wiki/Annexation_of_Crimea_by_the_Russian_Federation) and [brought the war in Donbas](https://en.wikipedia.org/wiki/War_in_Donbas) followed by [full-scale invasion of Ukraine in 2022](https://en.wikipedia.org/wiki/2022_Russian_invasion_of_Ukraine). -* Russia has brought sorrow and devastations to millions of Ukrainians, killed hundreds of innocent people, damaged thousands of buildings, and forced several million people to flee. +* russia has [illegally annexed Crimea in 2014](https://en.wikipedia.org/wiki/Annexation_of_Crimea_by_the_Russian_Federation) and [brought the war in Donbas](https://en.wikipedia.org/wiki/War_in_Donbas) followed by [full-scale invasion of Ukraine in 2022](https://en.wikipedia.org/wiki/2022_Russian_invasion_of_Ukraine). +* russia has brought sorrow and devastations to millions of Ukrainians, killed hundreds of innocent people, damaged thousands of buildings, and forced several million people to flee. * [Putin khuylo!](https://en.wikipedia.org/wiki/Putin_khuylo!) Glory to Ukraine! πŸ‡ΊπŸ‡¦ diff --git a/float_ms.go b/float_ms.go index d1cc949..442db64 100644 --- a/float_ms.go +++ b/float_ms.go @@ -8,7 +8,9 @@ import ( ) // FloatMS - integer part of timestamp represents seconds and fractional - milliseconds since -// the Epoch(Unix time), e.g. 1136239445.999 +// the Epoch(Unix time), e.g. +// 1136239445.999 +// // Inherits built-in time.Time type, thus has all it methods, but has custom serializer and // deserializer(converts float timestamp into built-in time.Time and vice versa). type FloatMS struct { From f87f3c3bcb9a796d91e7d94c94093986719d9f88 Mon Sep 17 00:00:00 2001 From: Vilen Topchii <32271530+vtopc@users.noreply.github.com> Date: Sat, 27 Jan 2024 14:39:58 +0200 Subject: [PATCH 5/5] wsl --- float_ms.go | 1 + 1 file changed, 1 insertion(+) diff --git a/float_ms.go b/float_ms.go index 442db64..279f9c7 100644 --- a/float_ms.go +++ b/float_ms.go @@ -26,6 +26,7 @@ func NewFloatMS(t time.Time) FloatMS { func (s FloatMS) MarshalJSON() ([]byte, error) { milli := s.Time.UnixMilli() f := float64(milli) / float64(msPerS) + return json.Marshal(f) }