This commit is contained in:
@@ -0,0 +1,196 @@
|
||||
package rfctime
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.blackforestbytes.com/BlackForestBytes/goext/tst"
|
||||
)
|
||||
|
||||
func TestDateString(t *testing.T) {
|
||||
d := Date{Year: 2023, Month: 5, Day: 7}
|
||||
tst.AssertEqual(t, d.String(), "2023-05-07")
|
||||
tst.AssertEqual(t, d.Serialize(), "2023-05-07")
|
||||
tst.AssertEqual(t, d.GoString(), "rfctime.Date{Year: 2023, Month: 5, Day: 7}")
|
||||
tst.AssertEqual(t, d.FormatStr(), "2006-01-02")
|
||||
}
|
||||
|
||||
func TestDateIsZero(t *testing.T) {
|
||||
tst.AssertEqual(t, Date{}.IsZero(), true)
|
||||
tst.AssertEqual(t, Date{Year: 1, Month: 1, Day: 1}.IsZero(), false)
|
||||
}
|
||||
|
||||
func TestDateNew(t *testing.T) {
|
||||
tm := time.Date(2023, 5, 7, 12, 30, 0, 0, time.UTC)
|
||||
d := NewDate(tm)
|
||||
tst.AssertEqual(t, d.Year, 2023)
|
||||
tst.AssertEqual(t, d.Month, 5)
|
||||
tst.AssertEqual(t, d.Day, 7)
|
||||
}
|
||||
|
||||
func TestDateTimeConversions(t *testing.T) {
|
||||
d := Date{Year: 2023, Month: 5, Day: 7}
|
||||
utc := d.TimeUTC()
|
||||
tst.AssertEqual(t, utc.Year(), 2023)
|
||||
tst.AssertEqual(t, utc.Month(), time.May)
|
||||
tst.AssertEqual(t, utc.Day(), 7)
|
||||
tst.AssertEqual(t, utc.Location(), time.UTC)
|
||||
|
||||
loc := d.TimeLocal()
|
||||
tst.AssertEqual(t, loc.Location(), time.Local)
|
||||
|
||||
custom := d.Time(time.UTC)
|
||||
tst.AssertEqual(t, custom.Hour(), 0)
|
||||
tst.AssertEqual(t, custom.Location(), time.UTC)
|
||||
}
|
||||
|
||||
func TestDateJSON(t *testing.T) {
|
||||
type Wrap struct {
|
||||
D Date `json:"d"`
|
||||
}
|
||||
w1 := Wrap{D: Date{Year: 2023, Month: 5, Day: 7}}
|
||||
b, err := json.Marshal(w1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tst.AssertEqual(t, string(b), `{"d":"2023-05-07"}`)
|
||||
|
||||
var w2 Wrap
|
||||
if err := json.Unmarshal(b, &w2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tst.AssertEqual(t, w2.D, w1.D)
|
||||
}
|
||||
|
||||
func TestDateJSONInvalid(t *testing.T) {
|
||||
var d Date
|
||||
if err := d.UnmarshalJSON([]byte(`"not-a-date"`)); err == nil {
|
||||
t.Errorf("expected parse error")
|
||||
}
|
||||
if err := d.UnmarshalJSON([]byte(`123`)); err == nil {
|
||||
t.Errorf("expected json error for number")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateText(t *testing.T) {
|
||||
d := Date{Year: 2023, Month: 5, Day: 7}
|
||||
b, err := d.MarshalText()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tst.AssertEqual(t, string(b), "2023-05-07")
|
||||
|
||||
var d2 Date
|
||||
if err := d2.UnmarshalText(b); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tst.AssertEqual(t, d2, d)
|
||||
|
||||
if err := d2.UnmarshalText([]byte("garbage")); err == nil {
|
||||
t.Errorf("expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateBinaryGob(t *testing.T) {
|
||||
d := Date{Year: 2023, Month: 5, Day: 7}
|
||||
|
||||
bin, err := d.MarshalBinary()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var d2 Date
|
||||
if err := d2.UnmarshalBinary(bin); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tst.AssertEqual(t, d2, d)
|
||||
|
||||
gob, err := d.GobEncode()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var d3 Date
|
||||
if err := d3.GobDecode(gob); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tst.AssertEqual(t, d3, d)
|
||||
}
|
||||
|
||||
func TestDateAccessors(t *testing.T) {
|
||||
d := Date{Year: 2023, Month: 5, Day: 17}
|
||||
y, m, day := d.Date()
|
||||
tst.AssertEqual(t, y, 2023)
|
||||
tst.AssertEqual(t, m, time.May)
|
||||
tst.AssertEqual(t, day, 17)
|
||||
tst.AssertEqual(t, d.Weekday(), time.Wednesday)
|
||||
|
||||
wy, ww := d.ISOWeek()
|
||||
ey, ew := d.TimeUTC().ISOWeek()
|
||||
tst.AssertEqual(t, wy, ey)
|
||||
tst.AssertEqual(t, ww, ew)
|
||||
|
||||
tst.AssertEqual(t, d.YearDay(), d.TimeUTC().YearDay())
|
||||
tst.AssertEqual(t, d.Unix(), d.TimeUTC().Unix())
|
||||
tst.AssertEqual(t, d.UnixMilli(), d.TimeUTC().UnixMilli())
|
||||
tst.AssertEqual(t, d.UnixMicro(), d.TimeUTC().UnixMicro())
|
||||
tst.AssertEqual(t, d.UnixNano(), d.TimeUTC().UnixNano())
|
||||
tst.AssertEqual(t, d.Format("2006/01/02"), "2023/05/17")
|
||||
}
|
||||
|
||||
func TestDateAddDate(t *testing.T) {
|
||||
d := Date{Year: 2023, Month: 5, Day: 17}
|
||||
d2 := d.AddDate(1, 2, 3)
|
||||
tst.AssertEqual(t, d2.Year, 2024)
|
||||
tst.AssertEqual(t, d2.Month, 7)
|
||||
tst.AssertEqual(t, d2.Day, 20)
|
||||
}
|
||||
|
||||
func TestDateParseString(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
ok bool
|
||||
expected Date
|
||||
}{
|
||||
{"2023-05-07", true, Date{2023, 5, 7}},
|
||||
{"0001-01-01", true, Date{1, 1, 1}},
|
||||
{"2023-13-01", false, Date{}}, // bad month
|
||||
{"2023-12-32", false, Date{}}, // bad day
|
||||
{"2023-00-15", false, Date{}}, // month 0
|
||||
{"2023-05", false, Date{}}, // bad format
|
||||
{"2023-05-07-extra", false, Date{}},
|
||||
{"abcd-ef-gh", false, Date{}},
|
||||
{"-1-05-07", false, Date{}}, // negative year
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
var d Date
|
||||
err := d.ParseString(tc.input)
|
||||
if tc.ok {
|
||||
if err != nil {
|
||||
t.Errorf("ParseString(%q) failed: %v", tc.input, err)
|
||||
continue
|
||||
}
|
||||
tst.AssertEqual(t, d, tc.expected)
|
||||
} else if err == nil {
|
||||
t.Errorf("ParseString(%q) should have failed", tc.input)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNowDate(t *testing.T) {
|
||||
now := time.Now().UTC()
|
||||
d := NowDate(time.UTC)
|
||||
tst.AssertEqual(t, d.Year, now.Year())
|
||||
tst.AssertEqual(t, d.Month, int(now.Month()))
|
||||
tst.AssertEqual(t, d.Day, now.Day())
|
||||
|
||||
dl := NowDateLoc()
|
||||
if dl.Year < 1970 {
|
||||
t.Errorf("NowDateLoc returned implausible year: %d", dl.Year)
|
||||
}
|
||||
|
||||
du := NowDateUTC()
|
||||
if du.Year < 1970 {
|
||||
t.Errorf("NowDateUTC returned implausible year: %d", du.Year)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
package rfctime
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.blackforestbytes.com/BlackForestBytes/goext/timeext"
|
||||
"git.blackforestbytes.com/BlackForestBytes/goext/tst"
|
||||
)
|
||||
|
||||
func TestRFC3339TimeRoundtripJSON(t *testing.T) {
|
||||
type Wrap struct {
|
||||
Value RFC3339Time `json:"v"`
|
||||
}
|
||||
|
||||
val := NewRFC3339(time.Unix(1675951556, 0).In(timeext.TimezoneBerlin))
|
||||
w1 := Wrap{val}
|
||||
|
||||
jstr1, err := json.Marshal(w1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if string(jstr1) != "{\"v\":\"2023-02-09T15:05:56+01:00\"}" {
|
||||
t.Errorf("unexpected json: %s", string(jstr1))
|
||||
}
|
||||
|
||||
w2 := Wrap{}
|
||||
if err := json.Unmarshal(jstr1, &w2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
jstr2, err := json.Marshal(w2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tst.AssertEqual(t, string(jstr1), string(jstr2))
|
||||
|
||||
if !w1.Value.EqualAny(w2.Value) {
|
||||
t.Errorf("time differs after roundtrip")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRFC3339TimeUnmarshalJSONInvalid(t *testing.T) {
|
||||
var v RFC3339Time
|
||||
if err := v.UnmarshalJSON([]byte(`"not-a-date"`)); err == nil {
|
||||
t.Errorf("expected error parsing invalid date")
|
||||
}
|
||||
if err := v.UnmarshalJSON([]byte(`12345`)); err == nil {
|
||||
t.Errorf("expected error for non-string json")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRFC3339TimeText(t *testing.T) {
|
||||
val := NewRFC3339(time.Date(2023, 2, 9, 15, 5, 56, 0, time.UTC))
|
||||
b, err := val.MarshalText()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tst.AssertEqual(t, string(b), "2023-02-09T15:05:56Z")
|
||||
|
||||
var v2 RFC3339Time
|
||||
if err := v2.UnmarshalText(b); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !v2.Equal(val) {
|
||||
t.Errorf("text roundtrip mismatch")
|
||||
}
|
||||
|
||||
if err := v2.UnmarshalText([]byte("garbage")); err == nil {
|
||||
t.Errorf("expected error on bad text")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRFC3339TimeBinaryAndGob(t *testing.T) {
|
||||
val := NewRFC3339(time.Date(2023, 2, 9, 15, 5, 56, 123, time.UTC))
|
||||
|
||||
bin, err := val.MarshalBinary()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var v2 RFC3339Time
|
||||
if err := v2.UnmarshalBinary(bin); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !v2.Equal(val) {
|
||||
t.Errorf("binary roundtrip mismatch")
|
||||
}
|
||||
|
||||
gob, err := val.GobEncode()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var v3 RFC3339Time
|
||||
if err := v3.GobDecode(gob); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !v3.Equal(val) {
|
||||
t.Errorf("gob roundtrip mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRFC3339TimeAccessors(t *testing.T) {
|
||||
loc, _ := time.LoadLocation("UTC")
|
||||
tm := time.Date(2023, 5, 17, 14, 30, 45, 123456789, loc)
|
||||
val := NewRFC3339(tm)
|
||||
|
||||
tst.AssertEqual(t, val.Year(), 2023)
|
||||
tst.AssertEqual(t, val.Month(), time.May)
|
||||
tst.AssertEqual(t, val.Day(), 17)
|
||||
tst.AssertEqual(t, val.Hour(), 14)
|
||||
tst.AssertEqual(t, val.Minute(), 30)
|
||||
tst.AssertEqual(t, val.Second(), 45)
|
||||
tst.AssertEqual(t, val.Nanosecond(), 123456789)
|
||||
tst.AssertEqual(t, val.Weekday(), time.Wednesday)
|
||||
tst.AssertEqual(t, val.YearDay(), tm.YearDay())
|
||||
tst.AssertEqual(t, val.Unix(), tm.Unix())
|
||||
tst.AssertEqual(t, val.UnixMilli(), tm.UnixMilli())
|
||||
tst.AssertEqual(t, val.UnixMicro(), tm.UnixMicro())
|
||||
tst.AssertEqual(t, val.UnixNano(), tm.UnixNano())
|
||||
tst.AssertEqual(t, val.Location(), loc)
|
||||
tst.AssertEqual(t, val.Format(time.RFC3339), tm.Format(time.RFC3339))
|
||||
tst.AssertEqual(t, val.GoString(), tm.GoString())
|
||||
tst.AssertEqual(t, val.String(), tm.String())
|
||||
tst.AssertEqual(t, val.Serialize(), tm.Format(time.RFC3339))
|
||||
tst.AssertEqual(t, val.FormatStr(), time.RFC3339)
|
||||
|
||||
y, mo, d := val.Date()
|
||||
tst.AssertEqual(t, y, 2023)
|
||||
tst.AssertEqual(t, mo, time.May)
|
||||
tst.AssertEqual(t, d, 17)
|
||||
|
||||
wy, ww := val.ISOWeek()
|
||||
ey, ew := tm.ISOWeek()
|
||||
tst.AssertEqual(t, wy, ey)
|
||||
tst.AssertEqual(t, ww, ew)
|
||||
|
||||
h, m, s := val.Clock()
|
||||
tst.AssertEqual(t, h, 14)
|
||||
tst.AssertEqual(t, m, 30)
|
||||
tst.AssertEqual(t, s, 45)
|
||||
|
||||
tst.AssertEqual(t, val.IsZero(), false)
|
||||
tst.AssertEqual(t, RFC3339Time{}.IsZero(), true)
|
||||
}
|
||||
|
||||
func TestRFC3339TimeAddSub(t *testing.T) {
|
||||
tm := time.Date(2023, 5, 17, 14, 30, 45, 0, time.UTC)
|
||||
a := NewRFC3339(tm)
|
||||
b := a.Add(2 * time.Hour)
|
||||
|
||||
tst.AssertEqual(t, b.Sub(a), 2*time.Hour)
|
||||
tst.AssertEqual(t, b.After(a), true)
|
||||
tst.AssertEqual(t, a.Before(b), true)
|
||||
tst.AssertEqual(t, a.After(b), false)
|
||||
tst.AssertEqual(t, b.Before(a), false)
|
||||
|
||||
c := a.AddDate(1, 2, 3)
|
||||
tst.AssertEqual(t, c.Year(), 2024)
|
||||
tst.AssertEqual(t, c.Month(), time.July)
|
||||
tst.AssertEqual(t, c.Day(), 20)
|
||||
}
|
||||
|
||||
func TestRFC3339TimeEqual(t *testing.T) {
|
||||
tm := time.Date(2023, 5, 17, 14, 30, 45, 0, time.UTC)
|
||||
a := NewRFC3339(tm)
|
||||
b := NewRFC3339(tm)
|
||||
c := NewRFC3339(tm.Add(time.Second))
|
||||
|
||||
tst.AssertEqual(t, a.Equal(b), true)
|
||||
tst.AssertEqual(t, a.Equal(c), false)
|
||||
tst.AssertEqual(t, a.EqualAny(b), true)
|
||||
tst.AssertEqual(t, a.EqualAny(c), false)
|
||||
tst.AssertEqual(t, a.EqualAny(nil), false)
|
||||
// Cross-type comparison via tt()
|
||||
tst.AssertEqual(t, a.EqualAny(NewRFC3339Nano(tm)), true)
|
||||
tst.AssertEqual(t, a.EqualAny(tm), true)
|
||||
}
|
||||
|
||||
func TestRFC3339TimeToNano(t *testing.T) {
|
||||
tm := time.Date(2023, 5, 17, 14, 30, 45, 12345, time.UTC)
|
||||
a := NewRFC3339(tm)
|
||||
n := a.ToNano()
|
||||
tst.AssertEqual(t, n.UnixNano(), tm.UnixNano())
|
||||
}
|
||||
|
||||
func TestNowRFC3339(t *testing.T) {
|
||||
before := time.Now()
|
||||
v := NowRFC3339()
|
||||
after := time.Now()
|
||||
|
||||
if v.Time().Before(before.Add(-time.Second)) || v.Time().After(after.Add(time.Second)) {
|
||||
t.Errorf("NowRFC3339 not within expected range")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package rfctime
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.blackforestbytes.com/BlackForestBytes/goext/tst"
|
||||
)
|
||||
|
||||
func TestSecondsF64Basics(t *testing.T) {
|
||||
d := NewSecondsF64(2*time.Second + 500*time.Millisecond)
|
||||
tst.AssertEqual(t, d.Duration(), 2500*time.Millisecond)
|
||||
tst.AssertEqual(t, d.Seconds(), 2.5)
|
||||
tst.AssertEqual(t, d.Milliseconds(), int64(2500))
|
||||
tst.AssertEqual(t, d.Microseconds(), int64(2500000))
|
||||
tst.AssertEqual(t, d.Nanoseconds(), int64(2500000000))
|
||||
tst.AssertEqual(t, d.Minutes(), 2.5/60.0)
|
||||
tst.AssertEqual(t, d.Hours(), 2.5/3600.0)
|
||||
tst.AssertEqual(t, d.String(), (2500 * time.Millisecond).String())
|
||||
}
|
||||
|
||||
func TestSecondsF64JSON(t *testing.T) {
|
||||
type Wrap struct {
|
||||
D SecondsF64 `json:"d"`
|
||||
}
|
||||
|
||||
w1 := Wrap{D: NewSecondsF64(2500 * time.Millisecond)}
|
||||
b, err := json.Marshal(w1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tst.AssertEqual(t, string(b), `{"d":2.5}`)
|
||||
|
||||
var w2 Wrap
|
||||
if err := json.Unmarshal(b, &w2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if math.Abs(float64(w2.D.Duration()-w1.D.Duration())) > float64(time.Microsecond) {
|
||||
t.Errorf("roundtrip mismatch: %v vs %v", w1.D, w2.D)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSecondsF64UnmarshalJSONInvalid(t *testing.T) {
|
||||
var d SecondsF64
|
||||
if err := d.UnmarshalJSON([]byte(`"not-a-number"`)); err == nil {
|
||||
t.Errorf("expected error")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package rfctime
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.blackforestbytes.com/BlackForestBytes/goext/tst"
|
||||
)
|
||||
|
||||
func TestTimeNew(t *testing.T) {
|
||||
v := NewTime(14, 30, 45, 123)
|
||||
tst.AssertEqual(t, v.Hour, 14)
|
||||
tst.AssertEqual(t, v.Minute, 30)
|
||||
tst.AssertEqual(t, v.Second, 45)
|
||||
tst.AssertEqual(t, v.NanoSecond, 123)
|
||||
}
|
||||
|
||||
func TestTimeFromTS(t *testing.T) {
|
||||
tm := time.Date(2023, 5, 17, 14, 30, 45, 123456789, time.UTC)
|
||||
v := NewTimeFromTS(tm)
|
||||
tst.AssertEqual(t, v.Hour, 14)
|
||||
tst.AssertEqual(t, v.Minute, 30)
|
||||
tst.AssertEqual(t, v.Second, 45)
|
||||
tst.AssertEqual(t, v.NanoSecond, 123456789)
|
||||
}
|
||||
|
||||
func TestTimeSerialize(t *testing.T) {
|
||||
v := NewTime(14, 30, 45, 123456789)
|
||||
tst.AssertEqual(t, v.Serialize(), "0014:30:45.123456789")
|
||||
tst.AssertEqual(t, v.String(), "0014:30:45.123456789")
|
||||
tst.AssertEqual(t, v.GoString(), "rfctime.NewTime(14, 30, 45, 123456789)")
|
||||
tst.AssertEqual(t, v.FormatStr(), "15:04:05.999999999")
|
||||
}
|
||||
|
||||
func TestTimeSerializeShort(t *testing.T) {
|
||||
tst.AssertEqual(t, NewTime(14, 30, 0, 0).SerializeShort(), "14:30")
|
||||
tst.AssertEqual(t, NewTime(14, 30, 45, 0).SerializeShort(), "14:30:45")
|
||||
tst.AssertEqual(t, NewTime(14, 30, 45, 123).SerializeShort(), "14:30:45.000000123")
|
||||
tst.AssertEqual(t, NewTime(0, 0, 0, 0).SerializeShort(), "00:00")
|
||||
}
|
||||
|
||||
func TestTimeDeserialize(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
ok bool
|
||||
expected Time
|
||||
}{
|
||||
{"14:30", true, Time{Hour: 14, Minute: 30, Second: 0, NanoSecond: 0}},
|
||||
{"14:30:45", true, Time{Hour: 14, Minute: 30, Second: 45, NanoSecond: 0}},
|
||||
{"14:30:45.123", true, Time{Hour: 14, Minute: 30, Second: 45, NanoSecond: 123000000}},
|
||||
{"14:30:45.123456789", true, Time{Hour: 14, Minute: 30, Second: 45, NanoSecond: 123456789}},
|
||||
{"00:00:00.000000000", true, Time{Hour: 0, Minute: 0, Second: 0, NanoSecond: 0}},
|
||||
{"14", false, Time{}},
|
||||
{"14:30:45.123:extra", false, Time{}},
|
||||
{"ab:cd", false, Time{}},
|
||||
{"14:bb", false, Time{}},
|
||||
{"14:30:cc", false, Time{}},
|
||||
{"14:30:45.zz", false, Time{}},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
var v Time
|
||||
err := v.Deserialize(tc.input)
|
||||
if tc.ok {
|
||||
if err != nil {
|
||||
t.Errorf("Deserialize(%q) failed: %v", tc.input, err)
|
||||
continue
|
||||
}
|
||||
tst.AssertEqual(t, v, tc.expected)
|
||||
} else if err == nil {
|
||||
t.Errorf("Deserialize(%q) should have failed", tc.input)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNowTime(t *testing.T) {
|
||||
now := time.Now().UTC()
|
||||
v := NowTime(time.UTC)
|
||||
// Within a couple of seconds
|
||||
if abs(v.Hour-now.Hour()) > 1 && !(now.Hour() == 23 && v.Hour == 0) {
|
||||
t.Errorf("NowTime hour mismatch: %d vs %d", v.Hour, now.Hour())
|
||||
}
|
||||
|
||||
vl := NowTimeLoc()
|
||||
if vl.Hour < 0 || vl.Hour > 23 {
|
||||
t.Errorf("NowTimeLoc invalid hour: %d", vl.Hour)
|
||||
}
|
||||
|
||||
vu := NowTimeUTC()
|
||||
if vu.Hour < 0 || vu.Hour > 23 {
|
||||
t.Errorf("NowTimeUTC invalid hour: %d", vu.Hour)
|
||||
}
|
||||
}
|
||||
|
||||
func abs(x int) int {
|
||||
if x < 0 {
|
||||
return -x
|
||||
}
|
||||
return x
|
||||
}
|
||||
@@ -0,0 +1,330 @@
|
||||
package rfctime
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.blackforestbytes.com/BlackForestBytes/goext/tst"
|
||||
)
|
||||
|
||||
func TestUnixTimeRoundtripJSON(t *testing.T) {
|
||||
type Wrap struct {
|
||||
Value UnixTime `json:"v"`
|
||||
}
|
||||
|
||||
val := NewUnix(time.Unix(1675951556, 0).UTC())
|
||||
w1 := Wrap{val}
|
||||
|
||||
jstr1, err := json.Marshal(w1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tst.AssertEqual(t, string(jstr1), `{"v":"1675951556"}`)
|
||||
|
||||
w2 := Wrap{}
|
||||
if err := json.Unmarshal(jstr1, &w2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tst.AssertEqual(t, w2.Value.Unix(), val.Unix())
|
||||
}
|
||||
|
||||
func TestUnixTimeUnmarshalJSONInvalid(t *testing.T) {
|
||||
var v UnixTime
|
||||
if err := v.UnmarshalJSON([]byte(`"not-a-number"`)); err == nil {
|
||||
t.Errorf("expected parse error")
|
||||
}
|
||||
if err := v.UnmarshalJSON([]byte(`{}`)); err == nil {
|
||||
t.Errorf("expected json error on object")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnixTimeText(t *testing.T) {
|
||||
val := NewUnix(time.Unix(1675951556, 0))
|
||||
b, err := val.MarshalText()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tst.AssertEqual(t, string(b), "1675951556")
|
||||
|
||||
var v2 UnixTime
|
||||
if err := v2.UnmarshalText(b); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tst.AssertEqual(t, v2.Unix(), val.Unix())
|
||||
|
||||
if err := v2.UnmarshalText([]byte("garbage")); err == nil {
|
||||
t.Errorf("expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnixTimeBinaryGob(t *testing.T) {
|
||||
val := NewUnix(time.Date(2023, 5, 17, 14, 30, 45, 0, time.UTC))
|
||||
|
||||
bin, err := val.MarshalBinary()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var v2 UnixTime
|
||||
if err := v2.UnmarshalBinary(bin); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tst.AssertEqual(t, v2.Unix(), val.Unix())
|
||||
|
||||
gob, err := val.GobEncode()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var v3 UnixTime
|
||||
if err := v3.GobDecode(gob); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tst.AssertEqual(t, v3.Unix(), val.Unix())
|
||||
}
|
||||
|
||||
func TestUnixTimeAccessors(t *testing.T) {
|
||||
tm := time.Date(2023, 5, 17, 14, 30, 45, 12345, time.UTC)
|
||||
val := NewUnix(tm)
|
||||
|
||||
tst.AssertEqual(t, val.Year(), 2023)
|
||||
tst.AssertEqual(t, val.Month(), time.May)
|
||||
tst.AssertEqual(t, val.Day(), 17)
|
||||
tst.AssertEqual(t, val.Hour(), 14)
|
||||
tst.AssertEqual(t, val.Minute(), 30)
|
||||
tst.AssertEqual(t, val.Second(), 45)
|
||||
tst.AssertEqual(t, val.Nanosecond(), 12345)
|
||||
tst.AssertEqual(t, val.Weekday(), time.Wednesday)
|
||||
tst.AssertEqual(t, val.Unix(), tm.Unix())
|
||||
tst.AssertEqual(t, val.UnixMilli(), tm.UnixMilli())
|
||||
tst.AssertEqual(t, val.UnixMicro(), tm.UnixMicro())
|
||||
tst.AssertEqual(t, val.UnixNano(), tm.UnixNano())
|
||||
tst.AssertEqual(t, val.Format(time.RFC3339), tm.Format(time.RFC3339))
|
||||
tst.AssertEqual(t, val.GoString(), tm.GoString())
|
||||
tst.AssertEqual(t, val.String(), tm.String())
|
||||
tst.AssertEqual(t, val.Serialize(), strconv.FormatInt(tm.Unix(), 10))
|
||||
tst.AssertEqual(t, val.IsZero(), false)
|
||||
tst.AssertEqual(t, UnixTime{}.IsZero(), true)
|
||||
|
||||
y, mo, d := val.Date()
|
||||
tst.AssertEqual(t, y, 2023)
|
||||
tst.AssertEqual(t, mo, time.May)
|
||||
tst.AssertEqual(t, d, 17)
|
||||
|
||||
wy, ww := val.ISOWeek()
|
||||
ey, ew := tm.ISOWeek()
|
||||
tst.AssertEqual(t, wy, ey)
|
||||
tst.AssertEqual(t, ww, ew)
|
||||
|
||||
h, m, s := val.Clock()
|
||||
tst.AssertEqual(t, h, 14)
|
||||
tst.AssertEqual(t, m, 30)
|
||||
tst.AssertEqual(t, s, 45)
|
||||
|
||||
tst.AssertEqual(t, val.YearDay(), tm.YearDay())
|
||||
}
|
||||
|
||||
func TestUnixTimeAddSubCompare(t *testing.T) {
|
||||
tm := time.Date(2023, 5, 17, 14, 30, 45, 0, time.UTC)
|
||||
a := NewUnix(tm)
|
||||
b := a.Add(time.Hour)
|
||||
|
||||
tst.AssertEqual(t, b.Sub(a), time.Hour)
|
||||
tst.AssertEqual(t, b.After(a), true)
|
||||
tst.AssertEqual(t, a.Before(b), true)
|
||||
|
||||
c := a.AddDate(0, 1, 0)
|
||||
tst.AssertEqual(t, c.Month(), time.June)
|
||||
|
||||
d := NewUnix(tm)
|
||||
tst.AssertEqual(t, a.Equal(d), true)
|
||||
tst.AssertEqual(t, a.EqualAny(d), true)
|
||||
tst.AssertEqual(t, a.EqualAny(b), false)
|
||||
tst.AssertEqual(t, a.EqualAny(nil), false)
|
||||
}
|
||||
|
||||
func TestNowUnix(t *testing.T) {
|
||||
before := time.Now()
|
||||
v := NowUnix()
|
||||
after := time.Now()
|
||||
|
||||
if v.Time().Before(before.Add(-time.Second)) || v.Time().After(after.Add(time.Second)) {
|
||||
t.Errorf("NowUnix not within expected range")
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- UnixMilliTime ----------
|
||||
|
||||
func TestUnixMilliTimeRoundtripJSON(t *testing.T) {
|
||||
type Wrap struct {
|
||||
Value UnixMilliTime `json:"v"`
|
||||
}
|
||||
|
||||
val := NewUnixMilli(time.UnixMilli(1675951556789).UTC())
|
||||
w1 := Wrap{val}
|
||||
|
||||
jstr1, err := json.Marshal(w1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tst.AssertEqual(t, string(jstr1), `{"v":"1675951556789"}`)
|
||||
|
||||
w2 := Wrap{}
|
||||
if err := json.Unmarshal(jstr1, &w2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tst.AssertEqual(t, w2.Value.UnixMilli(), val.UnixMilli())
|
||||
}
|
||||
|
||||
func TestUnixMilliTimeText(t *testing.T) {
|
||||
val := NewUnixMilli(time.UnixMilli(1675951556789))
|
||||
b, err := val.MarshalText()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tst.AssertEqual(t, string(b), "1675951556789")
|
||||
|
||||
var v2 UnixMilliTime
|
||||
if err := v2.UnmarshalText(b); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tst.AssertEqual(t, v2.UnixMilli(), val.UnixMilli())
|
||||
}
|
||||
|
||||
func TestUnixMilliTimeUnmarshalJSONInvalid(t *testing.T) {
|
||||
var v UnixMilliTime
|
||||
if err := v.UnmarshalJSON([]byte(`"abc"`)); err == nil {
|
||||
t.Errorf("expected error")
|
||||
}
|
||||
if err := v.UnmarshalJSON([]byte(`[]`)); err == nil {
|
||||
t.Errorf("expected error on array")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnixMilliTimeAccessors(t *testing.T) {
|
||||
tm := time.Date(2023, 5, 17, 14, 30, 45, 1000000, time.UTC)
|
||||
val := NewUnixMilli(tm)
|
||||
|
||||
tst.AssertEqual(t, val.Year(), 2023)
|
||||
tst.AssertEqual(t, val.Serialize(), strconv.FormatInt(tm.UnixMilli(), 10))
|
||||
tst.AssertEqual(t, val.IsZero(), false)
|
||||
tst.AssertEqual(t, UnixMilliTime{}.IsZero(), true)
|
||||
|
||||
a := val.Add(time.Hour)
|
||||
tst.AssertEqual(t, a.Sub(val), time.Hour)
|
||||
tst.AssertEqual(t, a.After(val), true)
|
||||
tst.AssertEqual(t, val.Before(a), true)
|
||||
|
||||
d := NewUnixMilli(tm)
|
||||
tst.AssertEqual(t, val.Equal(d), true)
|
||||
tst.AssertEqual(t, val.EqualAny(d), true)
|
||||
tst.AssertEqual(t, val.EqualAny(nil), false)
|
||||
}
|
||||
|
||||
func TestNowUnixMilli(t *testing.T) {
|
||||
before := time.Now()
|
||||
v := NowUnixMilli()
|
||||
after := time.Now()
|
||||
|
||||
if v.Time().Before(before.Add(-time.Second)) || v.Time().After(after.Add(time.Second)) {
|
||||
t.Errorf("NowUnixMilli not within expected range")
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- UnixNanoTime ----------
|
||||
|
||||
func TestUnixNanoTimeRoundtripJSON(t *testing.T) {
|
||||
type Wrap struct {
|
||||
Value UnixNanoTime `json:"v"`
|
||||
}
|
||||
|
||||
val := NewUnixNano(time.Unix(0, 1675951556820915171).UTC())
|
||||
w1 := Wrap{val}
|
||||
|
||||
jstr1, err := json.Marshal(w1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tst.AssertEqual(t, string(jstr1), `{"v":"1675951556820915171"}`)
|
||||
|
||||
w2 := Wrap{}
|
||||
if err := json.Unmarshal(jstr1, &w2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tst.AssertEqual(t, w2.Value.UnixNano(), val.UnixNano())
|
||||
}
|
||||
|
||||
func TestUnixNanoTimeText(t *testing.T) {
|
||||
val := NewUnixNano(time.Unix(0, 1675951556820915171))
|
||||
b, err := val.MarshalText()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tst.AssertEqual(t, string(b), "1675951556820915171")
|
||||
|
||||
var v2 UnixNanoTime
|
||||
if err := v2.UnmarshalText(b); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tst.AssertEqual(t, v2.UnixNano(), val.UnixNano())
|
||||
|
||||
if err := v2.UnmarshalText([]byte("xyz")); err == nil {
|
||||
t.Errorf("expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnixNanoTimeUnmarshalJSONInvalid(t *testing.T) {
|
||||
var v UnixNanoTime
|
||||
if err := v.UnmarshalJSON([]byte(`"abc"`)); err == nil {
|
||||
t.Errorf("expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnixNanoTimeAccessors(t *testing.T) {
|
||||
tm := time.Date(2023, 5, 17, 14, 30, 45, 123456789, time.UTC)
|
||||
val := NewUnixNano(tm)
|
||||
|
||||
tst.AssertEqual(t, val.Year(), 2023)
|
||||
tst.AssertEqual(t, val.Nanosecond(), 123456789)
|
||||
tst.AssertEqual(t, val.Serialize(), strconv.FormatInt(tm.UnixNano(), 10))
|
||||
tst.AssertEqual(t, val.IsZero(), false)
|
||||
tst.AssertEqual(t, UnixNanoTime{}.IsZero(), true)
|
||||
|
||||
a := val.Add(2 * time.Second)
|
||||
tst.AssertEqual(t, a.Sub(val), 2*time.Second)
|
||||
tst.AssertEqual(t, a.After(val), true)
|
||||
tst.AssertEqual(t, val.Before(a), true)
|
||||
|
||||
c := val.AddDate(0, 0, 1)
|
||||
tst.AssertEqual(t, c.Day(), 18)
|
||||
|
||||
d := NewUnixNano(tm)
|
||||
tst.AssertEqual(t, val.Equal(d), true)
|
||||
tst.AssertEqual(t, val.EqualAny(d), true)
|
||||
tst.AssertEqual(t, val.EqualAny(nil), false)
|
||||
}
|
||||
|
||||
func TestNowUnixNano(t *testing.T) {
|
||||
before := time.Now()
|
||||
v := NowUnixNano()
|
||||
after := time.Now()
|
||||
|
||||
if v.Time().Before(before.Add(-time.Second)) || v.Time().After(after.Add(time.Second)) {
|
||||
t.Errorf("NowUnixNano not within expected range")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnixCrossTypeEqualAny(t *testing.T) {
|
||||
tm := time.Date(2023, 5, 17, 14, 30, 45, 0, time.UTC)
|
||||
u := NewUnix(tm)
|
||||
um := NewUnixMilli(tm)
|
||||
un := NewUnixNano(tm)
|
||||
r := NewRFC3339(tm)
|
||||
rn := NewRFC3339Nano(tm)
|
||||
|
||||
tst.AssertEqual(t, u.EqualAny(um), true)
|
||||
tst.AssertEqual(t, u.EqualAny(un), true)
|
||||
tst.AssertEqual(t, u.EqualAny(r), true)
|
||||
tst.AssertEqual(t, u.EqualAny(rn), true)
|
||||
tst.AssertEqual(t, u.EqualAny(tm), true)
|
||||
}
|
||||
Reference in New Issue
Block a user