package utils import ( "testing" "time" "github.com/stretchr/testify/assert" ) func TestDBTimestampToUnix(t *testing.T) { ref := time.Date(2024, 6, 15, 10, 30, 45, 0, time.UTC) refUnix := ref.Unix() tests := []struct { name string input interface{} expect interface{} }{ {"nil", nil, nil}, {"empty string", "", nil}, {"MySQL DATETIME", "2024-06-15 10:30:45", refUnix}, {"PG with fractional seconds", "2024-06-15 10:30:45.123456", refUnix}, {"PG with +00 offset", "2024-06-15 10:30:45.123456+00", refUnix}, {"PG with -07 offset", "2024-06-15 03:30:45.123456-07", refUnix}, {"ISO Z suffix", "2024-06-15T10:30:45Z", refUnix}, {"RFC3339", "2024-06-15T10:30:45+00:00", refUnix}, {"RFC3339Nano", "2024-06-15T10:30:45.123456789+00:00", refUnix}, {"*string nil", (*string)(nil), nil}, {"*string valid", strPtr("2024-06-15 10:30:45"), refUnix}, {"*string empty", strPtr(""), nil}, {"non-string type", 12345, nil}, {"unparseable string", "not-a-date", nil}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := DBTimestampToUnix(tt.input) assert.Equal(t, tt.expect, result) }) } } func TestUnixToDBTimestamp(t *testing.T) { refUnix := int64(1718444445) expected := time.Unix(refUnix, 0).UTC().Format("2006-01-02 15:04:05") tests := []struct { name string input interface{} expect interface{} }{ {"nil", nil, nil}, {"int64", refUnix, expected}, {"*int64 valid", int64Ptr(refUnix), expected}, {"*int64 nil", (*int64)(nil), nil}, {"int", int(refUnix), expected}, {"float64", float64(refUnix), expected}, {"unknown type", "not-a-number", nil}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := UnixToDBTimestamp(tt.input) assert.Equal(t, tt.expect, result) }) } } func TestToUnixTimestamp(t *testing.T) { refUnix := int64(1718444445) tests := []struct { name string input interface{} expect interface{} }{ {"nil", nil, nil}, {"int64", refUnix, refUnix}, {"*int64 valid", int64Ptr(refUnix), refUnix}, {"*int64 nil", (*int64)(nil), nil}, {"int", int(refUnix), refUnix}, {"float64", float64(refUnix), refUnix}, {"string MySQL", "2024-06-15 10:00:45", time.Date(2024, 6, 15, 10, 0, 45, 0, time.UTC).Unix()}, {"string PG fractional", "2024-06-15 10:00:45.123456", time.Date(2024, 6, 15, 10, 0, 45, 0, time.UTC).Unix()}, {"string RFC3339", "2024-06-15T10:00:45Z", time.Date(2024, 6, 15, 10, 0, 45, 0, time.UTC).Unix()}, {"*string valid", strPtr("2024-06-15 10:00:45"), time.Date(2024, 6, 15, 10, 0, 45, 0, time.UTC).Unix()}, {"*string nil", (*string)(nil), nil}, {"string empty", "", nil}, {"unknown type", struct{}{}, nil}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := ToUnixTimestamp(tt.input) assert.Equal(t, tt.expect, result) }) } } func TestToTimeStringWithPGFormats(t *testing.T) { tests := []struct { name string input interface{} expect string }{ {"PG fractional", "2024-06-15 10:30:45.123456", "2024-06-15T10:30:45Z"}, {"PG +00 offset", "2024-06-15 10:30:45.123456+00", "2024-06-15T10:30:45Z"}, {"PG -07 offset", "2024-06-15 03:30:45.123456-07", "2024-06-15T03:30:45-07:00"}, {"MySQL format", "2024-06-15 10:30:45", "2024-06-15T10:30:45Z"}, {"RFC3339Nano", "2024-06-15T10:30:45.123456789+00:00", "2024-06-15T10:30:45Z"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := ToTimeString(tt.input) assert.Equal(t, tt.expect, result) }) } } func TestNanoToTime(t *testing.T) { t.Run("Zero", func(t *testing.T) { assert.True(t, NanoToTime(0).IsZero()) }) t.Run("ValidTimestamp", func(t *testing.T) { ns := int64(1609459200000000000) // 2021-01-01 00:00:00 UTC got := NanoToTime(ns) assert.Equal(t, 2021, got.Year()) assert.Equal(t, time.January, got.Month()) assert.Equal(t, 1, got.Day()) assert.Equal(t, 0, got.Hour()) assert.Equal(t, time.UTC, got.Location()) }) t.Run("PreservesNanoseconds", func(t *testing.T) { ns := int64(1609459200123456789) got := NanoToTime(ns) assert.Equal(t, 123456789, got.Nanosecond()) }) t.Run("Negative", func(t *testing.T) { got := NanoToTime(-1) assert.False(t, got.IsZero()) assert.Equal(t, time.UTC, got.Location()) }) } func TestTimeToNano(t *testing.T) { t.Run("Zero", func(t *testing.T) { assert.Equal(t, int64(0), TimeToNano(time.Time{})) }) t.Run("ValidTime", func(t *testing.T) { ts := time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC) assert.Equal(t, int64(1609459200000000000), TimeToNano(ts)) }) t.Run("WithNanoseconds", func(t *testing.T) { ts := time.Date(2021, 1, 1, 0, 0, 0, 123456789, time.UTC) assert.Equal(t, int64(1609459200123456789), TimeToNano(ts)) }) t.Run("RoundTrip", func(t *testing.T) { original := time.Date(2026, 3, 26, 15, 30, 45, 123456789, time.UTC) ns := TimeToNano(original) restored := NanoToTime(ns) assert.True(t, original.Equal(restored)) }) } func strPtr(s string) *string { return &s } func int64Ptr(i int64) *int64 { return &i }