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