From 62e7f734f0fc2d4dfdba4800b2b81f332f5f1e2d Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 22 Aug 2022 19:22:32 +0200 Subject: [PATCH 1/3] feat: add `FormatTime` and `ParseTimeString` methods --- CHANGELOG.md | 1 + types/utils.go | 35 +++++++++++++++++++++++---- types/utils_test.go | 58 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24223964fc35..e5eca1e329b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements +* [#]() Add `FormatTime` and `ParseTimeString` methods * [#12952](https://github.com/cosmos/cosmos-sdk/pull/12952) Replace keyring module to Cosmos fork. * [#12352](https://github.com/cosmos/cosmos-sdk/pull/12352) Move the `RegisterSwaggerAPI` logic into a separate helper function in the server package. * [#12876](https://github.com/cosmos/cosmos-sdk/pull/12876) Remove proposer-based rewards. diff --git a/types/utils.go b/types/utils.go index efd9a9c71a81..f0fe0cf4be55 100644 --- a/types/utils.go +++ b/types/utils.go @@ -63,17 +63,42 @@ const SortableTimeFormat = "2006-01-02T15:04:05.000000000" // Formats a time.Time into a []byte that can be sorted func FormatTimeBytes(t time.Time) []byte { - return []byte(t.UTC().Round(0).Format(SortableTimeFormat)) + return []byte(FormatTimeString(t)) +} + +// Formats a time.Time into a string +func FormatTimeString(t time.Time) string { + return t.UTC().Round(0).Format(SortableTimeFormat) } // Parses a []byte encoded using FormatTimeKey back into a time.Time func ParseTimeBytes(bz []byte) (time.Time, error) { - str := string(bz) - t, err := time.Parse(SortableTimeFormat, str) + return ParseTime(bz) +} + +// Parses an encoded type using FormatTimeKey back into a time.Time +func ParseTime(T any) (time.Time, error) { + var ( + result time.Time + err error + ) + + switch t := T.(type) { + case time.Time: + result, err = t, nil + case []byte: + result, err = time.Parse(SortableTimeFormat, string(t)) + case string: + result, err = time.Parse(SortableTimeFormat, t) + default: + return time.Time{}, fmt.Errorf("unexpected type %T", t) + } + if err != nil { - return t, err + return result, err } - return t.UTC().Round(0), nil + + return result.UTC().Round(0), nil } // NewLevelDB instantiate a new LevelDB instance according to DBBackend. diff --git a/types/utils_test.go b/types/utils_test.go index 7a196acafe2c..8bdba4082b35 100644 --- a/types/utils_test.go +++ b/types/utils_test.go @@ -110,6 +110,12 @@ func (s *utilsTestSuite) TestFormatTimeBytes() { s.Require().Equal("2020-03-03T19:54:00.000000000", string(sdk.FormatTimeBytes(tm))) } +func (s *utilsTestSuite) TestFormatTimeString() { + tm, err := time.Parse("Jan 2, 2006 at 3:04pm (MST)", "Mar 3, 2020 at 7:54pm (UTC)") + s.Require().NoError(err) + s.Require().Equal("2020-03-03T19:54:00.000000000", sdk.FormatTimeString(tm)) +} + func (s *utilsTestSuite) TestParseTimeBytes() { tm, err := sdk.ParseTimeBytes([]byte("2020-03-03T19:54:00.000000000")) s.Require().NoError(err) @@ -119,6 +125,58 @@ func (s *utilsTestSuite) TestParseTimeBytes() { s.Require().Error(err) } +func (s *utilsTestSuite) TestParseTime() { + testCases := []struct { + name string + input any + expectErr bool + expectedOutput string + }{ + { + name: "valid time string", + input: "2020-03-03T19:54:00.000000000", + expectErr: false, + }, + { + name: "valid time []byte", + input: []byte("2020-03-03T19:54:00.000000000"), + expectErr: false, + }, + { + name: "valid time", + input: time.Date(2020, 3, 3, 19, 54, 0, 0, time.UTC), + expectErr: false, + }, + { + name: "valid time different timezone", + input: func() time.Time { + ams, _ := time.LoadLocation("Asia/Seoul") // no daylight saving time + return time.Date(2020, 3, 4, 4, 54, 0, 0, ams) + }(), + expectErr: false, + }, + { + name: "invalid time", + input: struct{}{}, + expectErr: true, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + tm, err := sdk.ParseTime(tc.input) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().True(tm.Equal(time.Date(2020, 3, 3, 19, 54, 0, 0, time.UTC))) + } + }) + } +} + func (s *utilsTestSuite) TestAppendParseBytes() { test1 := "test1" test2 := "testString2" From 870bc0e7e6504f16dc5ad9a7c373770ff742dc22 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 22 Aug 2022 19:25:34 +0200 Subject: [PATCH 2/3] update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5eca1e329b8..729b5a67fd5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,7 +45,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements -* [#]() Add `FormatTime` and `ParseTimeString` methods +* [#12995](https://github.com/cosmos/cosmos-sdk/pull/12995) Add `FormatTime` and `ParseTimeString` methods * [#12952](https://github.com/cosmos/cosmos-sdk/pull/12952) Replace keyring module to Cosmos fork. * [#12352](https://github.com/cosmos/cosmos-sdk/pull/12352) Move the `RegisterSwaggerAPI` logic into a separate helper function in the server package. * [#12876](https://github.com/cosmos/cosmos-sdk/pull/12876) Remove proposer-based rewards. From d2ec08ce0e6baa572ca5ed03bbf5b85ea328857d Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 22 Aug 2022 20:30:33 +0200 Subject: [PATCH 3/3] add nolint --- types/utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/utils.go b/types/utils.go index f0fe0cf4be55..f299756fdb09 100644 --- a/types/utils.go +++ b/types/utils.go @@ -77,7 +77,7 @@ func ParseTimeBytes(bz []byte) (time.Time, error) { } // Parses an encoded type using FormatTimeKey back into a time.Time -func ParseTime(T any) (time.Time, error) { +func ParseTime(T any) (time.Time, error) { //nolint:gocritic var ( result time.Time err error