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) }