package timefmt import ( "testing" "time" ) func TestFormat_GoFormat(t *testing.T) { tests := []struct { name string format *Format want string }{ { name: "ISO 8601 date", format: NewFormat( Year4Digit, "-", MonthNumeric2, "-", DayNumeric2, ), want: "2006-01-02", }, { name: "24-hour time", format: NewFormat( Hour24, ":", Minute, ":", Second, ), want: "15:04:05", }, { name: "Full datetime", format: NewFormat( Year4Digit, "-", MonthNumeric2, "-", DayNumeric2, " ", Hour24, ":", Minute, ":", Second, ), want: "2006-01-02 15:04:05", }, { name: "12-hour with AM/PM", format: NewFormat( Hour12, ":", Minute, " ", AMPM, ), want: "3:04 PM", }, { name: "Full date with weekday and month name", format: NewFormat( WeekdayFull, ", ", MonthFull, " ", DayNumeric, ", ", Year4Digit, ), want: "Monday, January 2, 2006", }, { name: "ISO 8601 with timezone", format: NewFormat( Year4Digit, "-", MonthNumeric2, "-", DayNumeric2, "T", Hour24, ":", Minute, ":", Second, TimezoneISO8601Colon, ), want: "2006-01-02T15:04:05Z07:00", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := tt.format.GoFormat() if got != tt.want { t.Errorf("GoFormat() = %q, want %q", got, tt.want) } }) } } func TestFormat_LDML(t *testing.T) { tests := []struct { name string format *Format want string }{ { name: "ISO 8601 date", format: NewFormat( Year4Digit, "-", MonthNumeric2, "-", DayNumeric2, ), want: "yyyy-MM-dd", }, { name: "24-hour time", format: NewFormat( Hour24, ":", Minute, ":", Second, ), want: "HH:mm:ss", }, { name: "Full datetime", format: NewFormat( Year4Digit, "-", MonthNumeric2, "-", DayNumeric2, " ", Hour24, ":", Minute, ":", Second, ), want: "yyyy-MM-dd HH:mm:ss", }, { name: "12-hour with AM/PM", format: NewFormat( Hour12, ":", Minute, " ", AMPM, ), want: "h:mm a", }, { name: "ISO 8601 with T literal", format: NewFormat( Year4Digit, "-", MonthNumeric2, "-", DayNumeric2, "T", Hour24, ":", Minute, ":", Second, ), want: "yyyy-MM-dd'T'HH:mm:ss", }, { name: "Month name (abbreviated)", format: NewFormat( MonthShort, " ", DayNumeric2, ", ", Year4Digit, ), want: "MMM dd, yyyy", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := tt.format.LDML() if got != tt.want { t.Errorf("LDML() = %q, want %q", got, tt.want) } }) } } func TestFormat_Description(t *testing.T) { tests := []struct { name string format *Format want string }{ { name: "ISO 8601 date", format: NewFormat( Year4Digit, "-", MonthNumeric2, "-", DayNumeric2, ), want: "Year (4-digit), dash, Month (2-digit), dash, Day (2-digit)", }, { name: "24-hour time", format: NewFormat( Hour24, ":", Minute, ":", Second, ), want: "Hour (24-hour, 2-digit), colon, Minute (2-digit), colon, Second (2-digit)", }, { name: "12-hour with AM/PM", format: NewFormat( Hour12, ":", Minute, " ", AMPM, ), want: "Hour (12-hour), colon, Minute (2-digit), space, AM/PM (uppercase)", }, { name: "Date with literal T", format: NewFormat( Year4Digit, "-", MonthNumeric2, "-", DayNumeric2, "T", Hour24, ), want: "Year (4-digit), dash, Month (2-digit), dash, Day (2-digit), literal 'T', Hour (24-hour, 2-digit)", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := tt.format.Description() if got != tt.want { t.Errorf("Description() = %q, want %q", got, tt.want) } }) } } func TestFormat_Format(t *testing.T) { // Use a specific test time testTime := time.Date(2026, time.February, 8, 15, 4, 5, 0, time.UTC) tests := []struct { name string format *Format want string }{ { name: "ISO 8601 date", format: NewFormat( Year4Digit, "-", MonthNumeric2, "-", DayNumeric2, ), want: "2026-02-08", }, { name: "24-hour time", format: NewFormat( Hour24, ":", Minute, ":", Second, ), want: "15:04:05", }, { name: "Full datetime", format: NewFormat( Year4Digit, "-", MonthNumeric2, "-", DayNumeric2, " ", Hour24, ":", Minute, ":", Second, ), want: "2026-02-08 15:04:05", }, { name: "Month name", format: NewFormat( MonthFull, " ", DayNumeric, ", ", Year4Digit, ), want: "February 8, 2026", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := tt.format.Format(testTime) if got != tt.want { t.Errorf("Format() = %q, want %q", got, tt.want) } }) } } func TestFormat_Parse(t *testing.T) { tests := []struct { name string format *Format input string wantYear int wantMonth time.Month wantDay int wantHour int wantMin int wantSec int }{ { name: "ISO 8601 date", format: NewFormat( Year4Digit, "-", MonthNumeric2, "-", DayNumeric2, ), input: "2026-02-08", wantYear: 2026, wantMonth: time.February, wantDay: 8, }, { name: "Full datetime", format: NewFormat( Year4Digit, "-", MonthNumeric2, "-", DayNumeric2, " ", Hour24, ":", Minute, ":", Second, ), input: "2026-02-08 15:04:05", wantYear: 2026, wantMonth: time.February, wantDay: 8, wantHour: 15, wantMin: 4, wantSec: 5, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := tt.format.Parse(tt.input) if err != nil { t.Fatalf("Parse() error = %v", err) } if got.Year() != tt.wantYear { t.Errorf("Parse() year = %v, want %v", got.Year(), tt.wantYear) } if got.Month() != tt.wantMonth { t.Errorf("Parse() month = %v, want %v", got.Month(), tt.wantMonth) } if got.Day() != tt.wantDay { t.Errorf("Parse() day = %v, want %v", got.Day(), tt.wantDay) } if got.Hour() != tt.wantHour { t.Errorf("Parse() hour = %v, want %v", got.Hour(), tt.wantHour) } if got.Minute() != tt.wantMin { t.Errorf("Parse() minute = %v, want %v", got.Minute(), tt.wantMin) } if got.Second() != tt.wantSec { t.Errorf("Parse() second = %v, want %v", got.Second(), tt.wantSec) } }) } } func TestFormat_Example(t *testing.T) { tests := []struct { name string format *Format // We'll just check that Example() returns a non-empty string // The exact output depends on the reference time used }{ { name: "ISO 8601 date", format: NewFormat( Year4Digit, "-", MonthNumeric2, "-", DayNumeric2, ), }, { name: "Full datetime", format: NewFormat( Year4Digit, "-", MonthNumeric2, "-", DayNumeric2, " ", Hour24, ":", Minute, ":", Second, ), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := tt.format.Example() if got == "" { t.Errorf("Example() returned empty string") } }) } } func TestFormat_Fragments(t *testing.T) { format := NewFormat( Year4Digit, "-", MonthNumeric2, ) fragments := format.Fragments() if len(fragments) != 3 { t.Errorf("Fragments() returned %d fragments, want 3", len(fragments)) } // Verify it's a copy (modifying it doesn't affect the original) fragments[0] = "modified" originalFragments := format.Fragments() if len(originalFragments) != 3 { t.Errorf("Original format was modified") } }