feat(quando-wny): implement explicit parsing with layout format
Add ParseWithLayout() function to handle ambiguous and custom date formats by providing an explicit Go layout string. Implementation: - ParseWithLayout(s, layout string) delegates to time.Parse() - Wraps result in quando.Date with default EN language - Returns ErrInvalidFormat on parse failure - Trims whitespace and validates empty input - Never panics, always returns errors as values Features: - Disambiguate US vs EU slash formats (01/02/2026) - Support custom formats with month names (9. February 2026) - Full Go layout format support (reference date: Mon Jan 2 15:04:05 MST 2006) - Thread-safe and immutable Testing: - 13 success test cases (US/EU, custom formats, edge cases) - 8 error test cases (invalid inputs, validation) - Immutability test - 2 benchmarks: ~87-104 ns/op (100x faster than 10µs target) - Zero allocations - 100% test coverage for new code - 3 example tests demonstrating key use cases Files modified: - parse.go: Added ParseWithLayout() with comprehensive godoc - parse_test.go: Added 21 test cases + 2 benchmarks - example_test.go: Added 3 example functions
This commit is contained in:
parent
999ac9a7a3
commit
00353c2d4b
4 changed files with 346 additions and 1 deletions
55
parse.go
55
parse.go
|
|
@ -150,3 +150,58 @@ func isYearPrefix(s string) bool {
|
|||
|
||||
return true
|
||||
}
|
||||
|
||||
// ParseWithLayout parses a date string using an explicit Go layout format.
|
||||
// This is useful for disambiguating ambiguous formats or parsing custom formats
|
||||
// that cannot be automatically detected.
|
||||
//
|
||||
// Layout Format:
|
||||
// Go uses a reference date approach. The layout string must use the reference date:
|
||||
// Mon Jan 2 15:04:05 MST 2006
|
||||
//
|
||||
// Components you can use in your layout:
|
||||
// Year: 2006 (4-digit), 06 (2-digit)
|
||||
// Month: 01 (2-digit), 1 (1-digit), Jan (short), January (long)
|
||||
// Day: 02 (2-digit), 2 (1-digit), _2 (space-padded)
|
||||
// Weekday: Mon (short), Monday (long)
|
||||
// Hour: 15 (24-hour), 03 (12-hour), 3 (1-digit 12-hour)
|
||||
// Minute: 04 (2-digit), 4 (1-digit)
|
||||
// Second: 05 (2-digit), 5 (1-digit)
|
||||
// AM/PM: PM
|
||||
// Timezone: MST (abbrev), -0700 (offset), Z07:00 (ISO 8601)
|
||||
//
|
||||
// Note: Month and weekday names must be in English (Go limitation).
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// // Disambiguate US vs EU slash format
|
||||
// ParseWithLayout("01/02/2026", "01/02/2006") // US: January 2, 2026
|
||||
// ParseWithLayout("01/02/2026", "02/01/2006") // EU: February 1, 2026
|
||||
//
|
||||
// // Custom format with text month
|
||||
// ParseWithLayout("9. February 2026", "2. January 2006") // February 9, 2026
|
||||
//
|
||||
// // ISO 8601 with time
|
||||
// ParseWithLayout("2026-02-09T14:30:00", "2006-01-02T15:04:05")
|
||||
//
|
||||
// If the string cannot be parsed with the given layout, returns an error
|
||||
// wrapping ErrInvalidFormat. The returned Date uses UTC timezone unless
|
||||
// the layout and input include timezone information.
|
||||
func ParseWithLayout(s, layout string) (Date, error) {
|
||||
// Trim whitespace from input
|
||||
s = strings.TrimSpace(s)
|
||||
|
||||
// Empty input check
|
||||
if s == "" {
|
||||
return Date{}, fmt.Errorf("parsing date with layout %q: empty input: %w", layout, ErrInvalidFormat)
|
||||
}
|
||||
|
||||
// Parse using time.Parse with the provided layout
|
||||
t, err := time.Parse(layout, s)
|
||||
if err != nil {
|
||||
return Date{}, fmt.Errorf("parsing date %q with layout %q: %w", s, layout, ErrInvalidFormat)
|
||||
}
|
||||
|
||||
// Wrap in quando.Date with default language
|
||||
return Date{t: t, lang: EN}, nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue