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