From c2238c71b873742d0eebae9e26afc522d1fc0f70 Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Mon, 8 Apr 2024 21:39:45 +0300 Subject: [PATCH] minor improvement of the x/jsonx.SimpleDate time parser more features designed for the past 2-3 months to come, this is just a hotfix --- x/jsonx/simple_date.go | 40 +++++++++++++++++++++++++++++-------- x/jsonx/simple_date_test.go | 34 +++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 8 deletions(-) diff --git a/x/jsonx/simple_date.go b/x/jsonx/simple_date.go index 4d882fa1b..acba470c6 100644 --- a/x/jsonx/simple_date.go +++ b/x/jsonx/simple_date.go @@ -10,12 +10,17 @@ import ( "github.com/kataras/iris/v12/x/timex" ) -// SimpleDateLayout represents the "year-month-day" Go time format. -const SimpleDateLayout = "2006-01-02" +const ( + // SimpleDateLayout represents the "year-month-day" Go time format. + SimpleDateLayout = "2006-01-02" + simpleDateLayoutPostgres = "2006-1-2" +) // SimpleDate holds a json "year-month-day" time. type SimpleDate time.Time +var _ Exampler = (*SimpleDate)(nil) + // SimpleDateFromTime accepts a "t" Time and returns // a SimpleDate. If format fails, it returns the zero value of time.Time. func SimpleDateFromTime(t time.Time) SimpleDate { @@ -24,6 +29,10 @@ func SimpleDateFromTime(t time.Time) SimpleDate { } // ParseSimpleDate reads from "s" and returns the SimpleDate time. +// +// The function supports the following formats: +// - "2024-01-01" +// - "2024-1-1" func ParseSimpleDate(s string) (SimpleDate, error) { if s == "" || s == "null" { return SimpleDate{}, nil @@ -36,10 +45,16 @@ func ParseSimpleDate(s string) (SimpleDate, error) { tt, err = time.Parse(SimpleDateLayout, s) if err != nil { - return SimpleDate{}, err + // After v5.0.0-alpha.3 of pgx this is coming as "1993-1-1" instead of the stored + // value "1993-01-01". + var err2 error + tt, err2 = time.Parse(simpleDateLayoutPostgres, s) + if err2 != nil { + return SimpleDate{}, fmt.Errorf("%s: %w", err2.Error(), err) + } } - return SimpleDate(tt.UTC()), nil + return SimpleDate(tt), nil } // UnmarshalJSON binds the json "data" to "t" with the `SimpleDateLayout`. @@ -49,11 +64,10 @@ func (t *SimpleDate) UnmarshalJSON(data []byte) error { } data = trimQuotes(data) - if len(data) == 0 { - return nil // as an excepption here, allow empty "" on simple dates, as the server would render it on a response. - } - dataStr := string(data) + if len(dataStr) == 0 { + return nil // do not allow empty "" on simple dates. + } tt, err := time.Parse(SimpleDateLayout, dataStr) if err != nil { @@ -74,6 +88,14 @@ func (t SimpleDate) MarshalJSON() ([]byte, error) { return emptyQuoteBytes, nil } +// Examples returns a list of example values. +func (t SimpleDate) ListExamples() any { + return []string{ + "2024-01-01", + "2024-1-1", + } +} + // IsZero reports whether "t" is zero time. // It completes the pg.Zeroer interface. func (t SimpleDate) IsZero() bool { @@ -85,6 +107,7 @@ func (t SimpleDate) Add(d time.Duration) SimpleDate { return SimpleDateFromTime(t.ToTime().Add(d)) } +// CountPastDays returns the count of days between "t" and "pastDate". func (t SimpleDate) CountPastDays(pastDate SimpleDate) int { t1, t2 := t.ToTime(), pastDate.ToTime() return int(t1.Sub(t2).Hours() / 24) @@ -113,6 +136,7 @@ func (t SimpleDate) ToTime() time.Time { return time.Time(t) } +// Value completes the pg and native sql driver.Valuer interface. func (t SimpleDate) Value() (driver.Value, error) { return t.String(), nil } diff --git a/x/jsonx/simple_date_test.go b/x/jsonx/simple_date_test.go index c5531f3e8..2809cf939 100644 --- a/x/jsonx/simple_date_test.go +++ b/x/jsonx/simple_date_test.go @@ -57,3 +57,37 @@ func TestSimpleDateAterBefore(t *testing.T) { t.Fatalf("[after] expected d2 to be after d1") } } + +func TestCountPastDays(t *testing.T) { + tests := []struct { + AfterDate SimpleDate + BeforeDate SimpleDate + ExpectedPastDays int + }{ + { + AfterDate: mustParseSimpleDate("2023-01-01"), + BeforeDate: mustParseSimpleDate("2022-12-31"), + ExpectedPastDays: 1, + }, + { + AfterDate: mustParseSimpleDate("2023-01-01"), + BeforeDate: mustParseSimpleDate("2022-01-01"), + ExpectedPastDays: 365, + }, + } + + for i, tt := range tests { + if expected, got := tt.ExpectedPastDays, tt.AfterDate.CountPastDays(tt.BeforeDate); expected != got { + t.Fatalf("[%d] expected past days count: %d but got: %d", i, expected, got) + } + } +} + +func mustParseSimpleDate(s string) SimpleDate { + d, err := ParseSimpleDate(s) + if err != nil { + panic(err) + } + + return d +}