From 080baa8574d627ae93ab199e12a31b79e99787e2 Mon Sep 17 00:00:00 2001 From: Vincent Serpoul Date: Fri, 16 Apr 2021 00:44:31 +0800 Subject: [PATCH] golangci-lint: localtime (#509) --- localtime.go | 62 ++++++++++++++++++++++++++++++----------------- localtime_test.go | 55 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 89 insertions(+), 28 deletions(-) diff --git a/localtime.go b/localtime.go index a2149e9..6555a10 100644 --- a/localtime.go +++ b/localtime.go @@ -44,6 +44,7 @@ type LocalDate struct { func LocalDateOf(t time.Time) LocalDate { var d LocalDate d.Year, d.Month, d.Day = t.Date() + return d } @@ -51,8 +52,9 @@ func LocalDateOf(t time.Time) LocalDate { func ParseLocalDate(s string) (LocalDate, error) { t, err := time.Parse("2006-01-02", s) if err != nil { - return LocalDate{}, err + return LocalDate{}, fmt.Errorf("ParseLocalDate: %w", err) } + return LocalDateOf(t), nil } @@ -92,23 +94,28 @@ func (d LocalDate) DaysSince(s LocalDate) (days int) { // We convert to Unix time so we do not have to worry about leap seconds: // Unix time increases by exactly 86400 seconds per day. deltaUnix := d.In(time.UTC).Unix() - s.In(time.UTC).Unix() - return int(deltaUnix / 86400) + + const secondsInADay = 86400 + + return int(deltaUnix / secondsInADay) } -// Before reports whether d1 occurs before d2. -func (d1 LocalDate) Before(d2 LocalDate) bool { - if d1.Year != d2.Year { - return d1.Year < d2.Year +// Before reports whether d1 occurs before future date. +func (d LocalDate) Before(future LocalDate) bool { + if d.Year != future.Year { + return d.Year < future.Year } - if d1.Month != d2.Month { - return d1.Month < d2.Month + + if d.Month != future.Month { + return d.Month < future.Month } - return d1.Day < d2.Day + + return d.Day < future.Day } -// After reports whether d1 occurs after d2. -func (d1 LocalDate) After(d2 LocalDate) bool { - return d2.Before(d1) +// After reports whether d1 occurs after past date. +func (d LocalDate) After(past LocalDate) bool { + return past.Before(d) } // MarshalText implements the encoding.TextMarshaler interface. @@ -122,6 +129,7 @@ func (d LocalDate) MarshalText() ([]byte, error) { func (d *LocalDate) UnmarshalText(data []byte) error { var err error *d, err = ParseLocalDate(string(data)) + return err } @@ -145,6 +153,7 @@ func LocalTimeOf(t time.Time) LocalTime { var tm LocalTime tm.Hour, tm.Minute, tm.Second = t.Clock() tm.Nanosecond = t.Nanosecond() + return tm } @@ -156,8 +165,9 @@ func LocalTimeOf(t time.Time) LocalTime { func ParseLocalTime(s string) (LocalTime, error) { t, err := time.Parse("15:04:05.999999999", s) if err != nil { - return LocalTime{}, err + return LocalTime{}, fmt.Errorf("ParseLocalTime: %w", err) } + return LocalTimeOf(t), nil } @@ -169,6 +179,7 @@ func (t LocalTime) String() string { if t.Nanosecond == 0 { return s } + return s + fmt.Sprintf(".%09d", t.Nanosecond) } @@ -176,6 +187,7 @@ func (t LocalTime) String() string { func (t LocalTime) IsValid() bool { // Construct a non-zero time. tm := time.Date(2, 2, 2, t.Hour, t.Minute, t.Second, t.Nanosecond, time.UTC) + return LocalTimeOf(tm) == t } @@ -190,6 +202,7 @@ func (t LocalTime) MarshalText() ([]byte, error) { func (t *LocalTime) UnmarshalText(data []byte) error { var err error *t, err = ParseLocalTime(string(data)) + return err } @@ -223,9 +236,10 @@ func ParseLocalDateTime(s string) (LocalDateTime, error) { if err != nil { t, err = time.Parse("2006-01-02t15:04:05.999999999", s) if err != nil { - return LocalDateTime{}, err + return LocalDateTime{}, fmt.Errorf("ParseLocalDateTime: %w", err) } } + return LocalDateTimeOf(t), nil } @@ -253,17 +267,20 @@ func (dt LocalDateTime) IsValid() bool { // // In panics if loc is nil. func (dt LocalDateTime) In(loc *time.Location) time.Time { - return time.Date(dt.Date.Year, dt.Date.Month, dt.Date.Day, dt.Time.Hour, dt.Time.Minute, dt.Time.Second, dt.Time.Nanosecond, loc) + return time.Date( + dt.Date.Year, dt.Date.Month, dt.Date.Day, + dt.Time.Hour, dt.Time.Minute, dt.Time.Second, dt.Time.Nanosecond, loc, + ) } -// Before reports whether dt1 occurs before dt2. -func (dt1 LocalDateTime) Before(dt2 LocalDateTime) bool { - return dt1.In(time.UTC).Before(dt2.In(time.UTC)) +// Before reports whether dt occurs before future. +func (dt LocalDateTime) Before(future LocalDateTime) bool { + return dt.In(time.UTC).Before(future.In(time.UTC)) } -// After reports whether dt1 occurs after dt2. -func (dt1 LocalDateTime) After(dt2 LocalDateTime) bool { - return dt2.Before(dt1) +// After reports whether dt occurs after past. +func (dt LocalDateTime) After(past LocalDateTime) bool { + return past.Before(dt) } // MarshalText implements the encoding.TextMarshaler interface. @@ -273,9 +290,10 @@ func (dt LocalDateTime) MarshalText() ([]byte, error) { } // UnmarshalText implements the encoding.TextUnmarshaler interface. -// The datetime is expected to be a string in a format accepted by ParseLocalDateTime +// The datetime is expected to be a string in a format accepted by ParseLocalDateTime. func (dt *LocalDateTime) UnmarshalText(data []byte) error { var err error *dt, err = ParseLocalDateTime(string(data)) + return err } diff --git a/localtime_test.go b/localtime_test.go index 4bbb5b0..a327577 100644 --- a/localtime_test.go +++ b/localtime_test.go @@ -26,6 +26,8 @@ func cmpEqual(x, y interface{}) bool { } func TestDates(t *testing.T) { + t.Parallel() + for _, test := range []struct { date LocalDate loc *time.Location @@ -61,6 +63,8 @@ func TestDates(t *testing.T) { } func TestDateIsValid(t *testing.T) { + t.Parallel() + for _, test := range []struct { date LocalDate want bool @@ -86,6 +90,10 @@ func TestDateIsValid(t *testing.T) { } func TestParseDate(t *testing.T) { + t.Parallel() + + var emptyDate LocalDate + for _, test := range []struct { str string want LocalDate // if empty, expect an error @@ -93,21 +101,23 @@ func TestParseDate(t *testing.T) { {"2016-01-02", LocalDate{2016, 1, 2}}, {"2016-12-31", LocalDate{2016, 12, 31}}, {"0003-02-04", LocalDate{3, 2, 4}}, - {"999-01-26", LocalDate{}}, - {"", LocalDate{}}, - {"2016-01-02x", LocalDate{}}, + {"999-01-26", emptyDate}, + {"", emptyDate}, + {"2016-01-02x", emptyDate}, } { got, err := ParseLocalDate(test.str) if got != test.want { t.Errorf("ParseLocalDate(%q) = %+v, want %+v", test.str, got, test.want) } - if err != nil && test.want != (LocalDate{}) { + if err != nil && test.want != (emptyDate) { t.Errorf("Unexpected error %v from ParseLocalDate(%q)", err, test.str) } } } func TestDateArithmetic(t *testing.T) { + t.Parallel() + for _, test := range []struct { desc string start LocalDate @@ -167,6 +177,8 @@ func TestDateArithmetic(t *testing.T) { } func TestDateBefore(t *testing.T) { + t.Parallel() + for _, test := range []struct { d1, d2 LocalDate want bool @@ -183,6 +195,8 @@ func TestDateBefore(t *testing.T) { } func TestDateAfter(t *testing.T) { + t.Parallel() + for _, test := range []struct { d1, d2 LocalDate want bool @@ -198,6 +212,8 @@ func TestDateAfter(t *testing.T) { } func TestTimeToString(t *testing.T) { + t.Parallel() + for _, test := range []struct { str string time LocalTime @@ -212,6 +228,7 @@ func TestTimeToString(t *testing.T) { gotTime, err := ParseLocalTime(test.str) if err != nil { t.Errorf("ParseLocalTime(%q): got error: %v", test.str, err) + continue } if gotTime != test.time { @@ -227,6 +244,8 @@ func TestTimeToString(t *testing.T) { } func TestTimeOf(t *testing.T) { + t.Parallel() + for _, test := range []struct { time time.Time want LocalTime @@ -241,6 +260,8 @@ func TestTimeOf(t *testing.T) { } func TestTimeIsValid(t *testing.T) { + t.Parallel() + for _, test := range []struct { time LocalTime want bool @@ -265,6 +286,8 @@ func TestTimeIsValid(t *testing.T) { } func TestDateTimeToString(t *testing.T) { + t.Parallel() + for _, test := range []struct { str string dateTime LocalDateTime @@ -277,6 +300,7 @@ func TestDateTimeToString(t *testing.T) { gotDateTime, err := ParseLocalDateTime(test.str) if err != nil { t.Errorf("ParseLocalDateTime(%q): got error: %v", test.str, err) + continue } if gotDateTime != test.dateTime { @@ -292,6 +316,8 @@ func TestDateTimeToString(t *testing.T) { } func TestParseDateTimeErrors(t *testing.T) { + t.Parallel() + for _, str := range []string{ "", "2016-03-22", // just a date @@ -306,6 +332,8 @@ func TestParseDateTimeErrors(t *testing.T) { } func TestDateTimeOf(t *testing.T) { + t.Parallel() + for _, test := range []struct { time time.Time want LocalDateTime @@ -322,6 +350,8 @@ func TestDateTimeOf(t *testing.T) { } func TestDateTimeIsValid(t *testing.T) { + t.Parallel() + // No need to be exhaustive here; it's just LocalDate.IsValid && LocalTime.IsValid. for _, test := range []struct { dt LocalDateTime @@ -339,19 +369,24 @@ func TestDateTimeIsValid(t *testing.T) { } func TestDateTimeIn(t *testing.T) { + t.Parallel() + dt := LocalDateTime{LocalDate{2016, 1, 2}, LocalTime{3, 4, 5, 6}} - got := dt.In(time.UTC) + want := time.Date(2016, 1, 2, 3, 4, 5, 6, time.UTC) - if !got.Equal(want) { + if got := dt.In(time.UTC); !got.Equal(want) { t.Errorf("got %v, want %v", got, want) } } func TestDateTimeBefore(t *testing.T) { + t.Parallel() + d1 := LocalDate{2016, 12, 31} d2 := LocalDate{2017, 1, 1} t1 := LocalTime{5, 6, 7, 8} t2 := LocalTime{5, 6, 7, 9} + for _, test := range []struct { dt1, dt2 LocalDateTime want bool @@ -368,10 +403,13 @@ func TestDateTimeBefore(t *testing.T) { } func TestDateTimeAfter(t *testing.T) { + t.Parallel() + d1 := LocalDate{2016, 12, 31} d2 := LocalDate{2017, 1, 1} t1 := LocalTime{5, 6, 7, 8} t2 := LocalTime{5, 6, 7, 9} + for _, test := range []struct { dt1, dt2 LocalDateTime want bool @@ -388,6 +426,8 @@ func TestDateTimeAfter(t *testing.T) { } func TestMarshalJSON(t *testing.T) { + t.Parallel() + for _, test := range []struct { value interface{} want string @@ -407,9 +447,12 @@ func TestMarshalJSON(t *testing.T) { } func TestUnmarshalJSON(t *testing.T) { + t.Parallel() + var d LocalDate var tm LocalTime var dt LocalDateTime + for _, test := range []struct { data string ptr interface{}