Add Format type with preset constants (ISO, EU, US, Long, RFC2822) and
Format() method for convenient date formatting.
Key features:
- Type-safe Format enum with 5 preset formats
- ISO (2026-02-09), EU (09.02.2026), US (02/09/2026)
- Long format with i18n support (EN: "February 9, 2026", DE: "9. Februar 2026")
- RFC2822 email format
- Language-independent formats (ISO, EU, US, RFC2822) ignore Lang setting
- Language-dependent Long format respects WithLang()
Implementation:
- format.go: Format type, constants, Format() method, formatLong() helper
- format_test.go: 26 tests covering all formats, edge cases, immutability
- example_test.go: 8 example functions demonstrating usage
Performance (exceeds targets):
- ISO/EU/US: ~90 ns (target: <5 µs)
- RFC2822: ~207 ns (target: <5 µs)
- Long EN/DE: ~270 ns (target: <10 µs)
All tests pass with comprehensive coverage of leap years, month boundaries,
and language dependency.
Add ParseRelative() and ParseRelativeWithClock() for parsing relative
date expressions like "today", "tomorrow", "+2 days", "-1 week", etc.
Features:
- Keywords: today, tomorrow, yesterday (case-insensitive)
- Relative offsets: +/-N <unit> format
- Supported units: day(s), week(s), month(s), quarter(s), year(s)
- All results return at 00:00:00 in local timezone
- Comprehensive error handling with ErrInvalidFormat
Implementation:
- parse.go: Added ParseRelative(), ParseRelativeWithClock(), parseUnitString()
- parse_test.go: Added 38 test cases covering all expressions and errors
- example_test.go: Added 4 example functions demonstrating usage
Test results:
- 100% code coverage for all ParseRelative functions
- Benchmarks: ~67ns (keywords), ~563ns (offsets) - well under <20µs target
- All existing tests pass
Complex expressions like "next monday" or "start of month" are out of
scope for Phase 1 and documented for future implementation.
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
Add Duration.Human() method for localized, human-readable duration formatting:
- Adaptive granularity: displays 2 largest time units
- i18n support for EN and DE languages
- Handles singular/plural forms automatically
- Supports negative durations with minus prefix
- Zero duration special case handling
Performance: ~0.88µs/op (11x faster than 10µs target)
Coverage: 100% on diff.go, 98.2% overall
Files modified:
- diff.go: Added Human() method with fmt import
- diff_test.go: Added 18 comprehensive tests + 2 benchmarks
- example_test.go: Added 3 example functions
Add internationalization support with translation data for English and
German languages. This provides the foundation for localized formatting
of dates and durations.
Changes:
- Add i18n.go with translation maps for month names, weekday names,
and duration units (both EN and DE)
- Implement helper methods on Lang type: MonthName, MonthNameShort,
WeekdayName, WeekdayNameShort, DurationUnit
- Add automatic fallback to English for unknown languages
- Create comprehensive test suite in i18n_test.go (97.8% coverage)
- Update Lang type documentation with future expansion notes
- Add example tests demonstrating i18n usage
Blocks: quando-10t, quando-5ol, quando-95w
Add In() method to Date type for converting between IANA timezones.
Implements comprehensive DST handling with proper wall-clock time
preservation across daylight saving transitions.
Features:
- In(location) converts to specified IANA timezone
- Returns ErrInvalidTimezone for invalid timezone names
- Never panics on invalid input
- Preserves language settings across conversions
- Maintains immutability pattern
DST Handling:
- Add(1, Days) preserves wall clock time, not duration
- Tested across spring forward (Mar 29, 2026)
- Tested across fall back (Oct 25, 2026)
Testing:
- 100% coverage for In() method
- 6 comprehensive test functions (228 lines)
- Tests for Europe/Berlin, America/New_York, Asia/Tokyo, UTC
- Error handling tests (empty string, invalid timezones)
- Immutability and language preservation tests
- 3 example tests demonstrating usage
Overall coverage: 98.1%
Implement Parse() function that automatically detects and parses common
date formats without requiring explicit layout strings. This provides an
intuitive API for parsing dates from various sources while maintaining
type safety through proper error handling.
Supported formats:
- ISO format (YYYY-MM-DD): "2026-02-09"
- ISO with slash (YYYY/MM/DD): "2026/02/09"
- EU format (DD.MM.YYYY): "09.02.2026"
- RFC2822/RFC1123: "Mon, 09 Feb 2026 00:00:00 +0000"
Key features:
- Detects and rejects ambiguous slash formats (e.g., "01/02/2026")
- Returns clear, contextual errors for invalid or ambiguous inputs
- Never panics - all errors via return values
- Zero allocations for successful parses
- Comprehensive test coverage (98%)
Performance results:
- ISO format: 105.5 ns/op (94x faster than 10µs target)
- ISO slash: 118.3 ns/op
- EU format: 117.4 ns/op
- RFC2822: 257.8 ns/op
Test coverage:
- 42 unit tests covering valid formats, error cases, edge cases
- 3 example tests demonstrating usage patterns
- Benchmarks for all format types
- Parse() function: 100% coverage
Files added:
- parse.go: Main implementation with Parse() and helper functions
- parse_test.go: Comprehensive test suite with table-driven tests
Files modified:
- example_test.go: Added ExampleParse examples
- Add Add(value, unit) method for all 8 units
- Add Sub(value, unit) method (wraps Add with negative value)
- Implement month-end overflow logic for Months/Quarters/Years
- When adding months, if target day doesn't exist, snap to last day of month
- Handle all month-end combinations correctly
- Leap year support (Feb 29 edge cases)
- DST-safe calendar day arithmetic for Days unit
- Negative value support (Add(-1) == Sub(1))
- Method chaining support (fluent API)
- Immutability verified (original date never modified)
- Timezone preservation across operations
- Comprehensive table-driven tests for month-end edge cases
- All 30/31 day month combinations tested
- Leap year tests (Feb 29 -> Feb 28)
- Cross-year boundary tests
- Negative value tests
- Method chaining tests
- Performance benchmarks (all < 1µs)
- 98.8% test coverage (exceeds 95% requirement)
- Godoc with month-end overflow examples
Benchmark results:
- AddDays: ~42ns (< 1µs target) ✓
- AddMonths: ~191ns (< 1µs target) ✓
- AddYears: ~202ns (< 1µs target) ✓
- Method chaining: ~263ns for 3 ops ✓
- Zero allocations for all operations
All acceptance criteria met:
✓ Add() implemented for all 8 units
✓ Sub() implemented for all 8 units
✓ Month-end overflow logic correct
✓ Leap year handling (Feb 29 edge cases)
✓ DST handling (calendar days)
✓ Negative values supported
✓ Method chaining works
✓ Unit tests with 98.8% coverage
✓ Table-driven tests for month-end edge cases
✓ Benchmarks meet <1µs target
✓ Godoc comments with month-end examples
- Create errors.go with sentinel errors
- Define ErrInvalidFormat for parsing errors
- Define ErrInvalidTimezone for timezone errors
- Define ErrOverflow for date arithmetic overflow
- Comprehensive godoc for each error with usage context
- Document no-panic policy in error handling
- Document Must* variant panic behavior
- Example tests showing error handling patterns
- Tests for error uniqueness and errors.Is compatibility
- 100% coverage for error definitions
Error Handling Policy:
- Library never panics in normal operations
- All errors returned as values
- Use errors.Is() for error type checking
- Must* functions panic (for test/init use only)
All acceptance criteria met:
✓ errors.go file created
✓ ErrInvalidFormat defined
✓ ErrInvalidTimezone defined
✓ ErrOverflow defined
✓ Godoc for each error with usage context
✓ Documentation of no-panic policy
✓ Documentation of Must* panic behavior
✓ Example tests showing error handling patterns
- Add Next(weekday) method to jump to next occurrence of a weekday
- Add Prev(weekday) method to jump to previous occurrence of a weekday
- Next ALWAYS returns future date (never today, even if same weekday)
- Prev ALWAYS returns past date (never today, even if same weekday)
- Time of day preserved from source date
- Comprehensive unit tests for all weekday combinations
- Same-weekday edge case tests (Monday.Next(Monday) = next Monday)
- Timezone preservation tests
- Immutability verification tests
- Performance benchmarks (~45ns, well under 1µs target)
- Zero allocations for both operations
- 97.8% test coverage (exceeds 95% requirement)
- Godoc comments with same-weekday behavior examples
All acceptance criteria met:
✓ Next() implemented for all weekdays
✓ Prev() implemented for all weekdays
✓ Next() never returns today (always future)
✓ Prev() never returns today (always past)
✓ Time of day preserved from source
✓ Edge case: Same weekday correctly skips to next/prev week
✓ Unit tests for all weekday combinations
✓ Tests for same weekday edge case
✓ Benchmarks meet <1µs target (~45ns)
✓ Godoc comments with same-weekday behavior example
Changed module path from code.beautifulmachines.dev/quando to
code.beautifulmachines.dev/jakoubek/quando to include user namespace.
Updated:
- go.mod: module declaration
- example_test.go: import path
- Implement StartOf(unit) for Weeks, Months, Quarters, Years
- Implement EndOf(unit) for Weeks, Months, Quarters, Years
- Week snapping follows ISO 8601 (Monday start, Sunday end)
- Month-end handling for all month lengths (28/29/30/31 days)
- Quarter definitions: Q1=Jan-Mar, Q2=Apr-Jun, Q3=Jul-Sep, Q4=Oct-Dec
- Comprehensive unit tests for all units and edge cases
- Leap year handling for February
- Timezone preservation tests
- Immutability verification tests
- Performance benchmarks (all <200ns, well under 1µs target)
- Zero allocations for all operations
- 97.3% test coverage (exceeds 95% requirement)
- Godoc comments with usage examples
All acceptance criteria met:
✓ StartOf(Week) returns Monday 00:00:00
✓ EndOf(Week) returns Sunday 23:59:59
✓ StartOf(Month) returns 1st day 00:00:00
✓ EndOf(Month) handles all month lengths correctly
✓ StartOf(Quarter) returns correct quarter start
✓ EndOf(Quarter) returns correct quarter end
✓ StartOf(Year) returns Jan 1 00:00:00
✓ EndOf(Year) returns Dec 31 23:59:59
✓ Leap year handling for February
✓ Unit tests for all units and edge cases
✓ ISO 8601 week compliance tests
✓ Benchmarks meet <1µs target (all <200ns)
✓ Godoc comments with examples
- Define Unit type as int for type-safe time unit constants
- Implement all 8 unit constants (Seconds through Years) using iota
- Add String() method for debugging and error messages
- Comprehensive unit tests verifying constants, ordering, and comparability
- Type safety tests demonstrating compile-time safety
- Example tests showing usage patterns
- 100% test coverage (exceeds 95% requirement)
All acceptance criteria met:
✓ Unit type defined as int
✓ All 8 unit constants defined (Seconds through Years)
✓ Units use iota for ordering
✓ Godoc comments for Unit type and constants
✓ Unit tests verifying constants
- Add Clock interface with Now() and From(t time.Time) methods
- Implement DefaultClock using time.Now() for production code
- Implement FixedClock with fixed time for deterministic testing
- Add factory functions NewClock() and NewFixedClock(time.Time)
- Comprehensive unit tests demonstrating deterministic test patterns
- Edge case testing (epoch, year 0001, year 9999, nanoseconds)
- Timezone preservation tests
- Example tests showing test usage patterns
- Performance benchmarks for both clock implementations
- 100% test coverage (exceeds 95% requirement)
All acceptance criteria met:
✓ Clock interface defined
✓ DefaultClock implementation using time.Now()
✓ FixedClock implementation with fixed time
✓ NewClock() factory function
✓ NewFixedClock(time.Time) factory function
✓ Unit tests demonstrating deterministic test patterns
✓ Godoc comments
✓ Example test showing test usage pattern
- Add Date struct with time.Time and Lang fields
- Implement package-level constructors: Now(), From(time.Time)
- Add conversion methods: Time(), Unix(), FromUnix(int64)
- Support negative Unix timestamps (dates before 1970)
- Support full time.Time range (year 0001-9999+)
- Add WithLang() for i18n support (placeholder)
- Create package documentation in quando.go
- Comprehensive unit tests with 100% coverage
- Example tests for godoc
- Verify immutability through tests
All acceptance criteria met:
✓ Date struct defined with time.Time and Lang fields
✓ Now() returns current date
✓ From(time.Time) converts to Date
✓ Time() extracts underlying time.Time
✓ Unix() returns Unix timestamp (int64)
✓ FromUnix(int64) creates Date from timestamp
✓ Unit tests with 100% coverage (exceeds 95% requirement)
✓ Godoc comments for all exported types/functions
✓ Example tests in example_test.go