diff --git a/civil/civil.go b/civil/civil.go index 454deab4af13..cf663022dea4 100644 --- a/civil/civil.go +++ b/civil/civil.go @@ -111,6 +111,17 @@ func (d Date) After(d2 Date) bool { return d2.Before(d) } +// Compare compares d and d2. If d is before d2, it returns -1; +// if d is after d2, it returns +1; otherwise it returns 0. +func (d Date) Compare(d2 Date) int { + if d.Before(d2) { + return -1 + } else if d.After(d2) { + return +1 + } + return 0 +} + // IsZero reports whether date fields are set to their default value. func (d Date) IsZero() bool { return (d.Year == 0) && (int(d.Month) == 0) && (d.Day == 0) @@ -209,6 +220,17 @@ func (t Time) After(t2 Time) bool { return t2.Before(t) } +// Compare compares t and t2. If t is before t2, it returns -1; +// if t is after t2, it returns +1; otherwise it returns 0. +func (t Time) Compare(t2 Time) int { + if t.Before(t2) { + return -1 + } else if t.After(t2) { + return +1 + } + return 0 +} + // MarshalText implements the encoding.TextMarshaler interface. // The output is the result of t.String(). func (t Time) MarshalText() ([]byte, error) { @@ -302,6 +324,12 @@ func (dt DateTime) After(dt2 DateTime) bool { return dt2.Before(dt) } +// Compare compares dt and dt2. If dt is before dt2, it returns -1; +// if dt is after dt2, it returns +1; otherwise it returns 0. +func (dt DateTime) Compare(dt2 DateTime) int { + return dt.In(time.UTC).Compare(dt2.In(time.UTC)) +} + // IsZero reports whether datetime fields are set to their default value. func (dt DateTime) IsZero() bool { return dt.Date.IsZero() && dt.Time.IsZero() diff --git a/civil/civil_test.go b/civil/civil_test.go index c9354f3277a9..590e77b90af9 100644 --- a/civil/civil_test.go +++ b/civil/civil_test.go @@ -193,6 +193,21 @@ func TestDateAfter(t *testing.T) { } } +func TestDateCompare(t *testing.T) { + for _, test := range []struct { + d1, d2 Date + want int + }{ + {Date{2016, 12, 31}, Date{2017, 1, 1}, -1}, + {Date{2016, 1, 1}, Date{2016, 1, 1}, 0}, + {Date{2016, 12, 31}, Date{2016, 12, 30}, +1}, + } { + if got := test.d1.Compare(test.d2); got != test.want { + t.Errorf("%v.Compare(%v): got %d, want %d", test.d1, test.d2, got, test.want) + } + } +} + func TestDateIsZero(t *testing.T) { for _, test := range []struct { date Date @@ -330,6 +345,27 @@ func TestTimeAfter(t *testing.T) { } } +func TestTimeCompare(t *testing.T) { + for _, test := range []struct { + t1, t2 Time + want int + }{ + {Time{12, 0, 0, 0}, Time{14, 0, 0, 0}, -1}, + {Time{12, 20, 0, 0}, Time{12, 30, 0, 0}, -1}, + {Time{12, 20, 10, 0}, Time{12, 20, 20, 0}, -1}, + {Time{12, 20, 10, 5}, Time{12, 20, 10, 10}, -1}, + {Time{14, 0, 0, 0}, Time{12, 0, 0, 0}, +1}, + {Time{12, 30, 0, 0}, Time{12, 20, 0, 0}, +1}, + {Time{12, 20, 20, 0}, Time{12, 20, 10, 0}, +1}, + {Time{12, 20, 10, 10}, Time{12, 20, 10, 5}, +1}, + {Time{12, 20, 10, 5}, Time{12, 20, 10, 5}, 0}, + } { + if got := test.t1.Compare(test.t2); got != test.want { + t.Errorf("%v.Compare(%v): got %d, want %d", test.t1, test.t2, got, test.want) + } + } +} + func TestDateTimeToString(t *testing.T) { for _, test := range []struct { str string @@ -453,6 +489,27 @@ func TestDateTimeAfter(t *testing.T) { } } +func TestDateTimeCompare(t *testing.T) { + d1 := Date{2016, 12, 31} + d2 := Date{2017, 1, 1} + t1 := Time{5, 6, 7, 8} + t2 := Time{5, 6, 7, 9} + for _, test := range []struct { + dt1, dt2 DateTime + want int + }{ + {DateTime{d1, t1}, DateTime{d2, t1}, -1}, + {DateTime{d1, t1}, DateTime{d1, t2}, -1}, + {DateTime{d2, t1}, DateTime{d1, t1}, +1}, + {DateTime{d1, t2}, DateTime{d1, t1}, +1}, + {DateTime{d2, t1}, DateTime{d2, t1}, 0}, + } { + if got := test.dt1.Compare(test.dt2); got != test.want { + t.Errorf("%v.Compare(%v): got %d, want %d", test.dt1, test.dt2, got, test.want) + } + } +} + func TestDateTimeIsZero(t *testing.T) { for _, test := range []struct { dt DateTime