feat(quando-ljj): implement Duration type and Diff calculation

- Add Duration type with private start/end time fields
- Implement Diff(a, b) package function
- Implement integer methods (Seconds, Minutes, Hours, Days, Weeks, Months, Years)
- Implement float methods (MonthsFloat, YearsFloat) for precise calculations
- Months calculation handles month-end dates and leap years correctly
- Negative duration support (when a < b)
- Correct handling of year boundaries and leap years
- Comprehensive table-driven tests covering edge cases
- Negative duration tests
- Cross-boundary tests (year, leap year)
- Float precision tests
- Performance benchmarks (all meet targets)
- 98.6% test coverage (exceeds 95% requirement)
- Godoc comments with precision explanation

Benchmark results:
- Seconds: ~15ns (< 1µs target) ✓
- Months: ~54ns (< 1µs target) ✓
- MonthsFloat: ~172ns (< 2µs target) ✓
- Zero allocations for all operations

All acceptance criteria met:
✓ Duration type defined
✓ Diff(a, b) returns Duration
✓ All integer methods implemented (Seconds through Years)
✓ Float methods for Months and Years implemented
✓ Negative differences handled correctly
✓ Calculations correct across year boundaries
✓ Leap year handling correct
✓ Unit tests with 98.6% coverage
✓ Table-driven tests for various date ranges
✓ Benchmarks meet targets
✓ Godoc comments with precision explanation
This commit is contained in:
Oliver Jakoubek 2026-02-11 17:38:22 +01:00
commit e5ece8d480
4 changed files with 771 additions and 2 deletions

View file

@ -229,3 +229,51 @@ func ExampleDate_Next_sameWeekday() {
fmt.Printf("Days later: %d\n", int(nextMonday.Time().Sub(monday.Time()).Hours()/24))
// Output: Days later: 7
}
// ExampleDiff demonstrates calculating the duration between two dates
func ExampleDiff() {
start := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
end := time.Date(2026, 12, 31, 0, 0, 0, 0, time.UTC)
dur := quando.Diff(start, end)
fmt.Printf("Days: %d\n", dur.Days())
fmt.Printf("Months: %d\n", dur.Months())
fmt.Printf("Years: %d\n", dur.Years())
// Output:
// Days: 364
// Months: 11
// Years: 0
}
// ExampleDuration_MonthsFloat demonstrates precise month calculations
func ExampleDuration_MonthsFloat() {
start := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
end := time.Date(2026, 2, 16, 0, 0, 0, 0, time.UTC)
dur := quando.Diff(start, end)
intMonths := dur.Months()
floatMonths := dur.MonthsFloat()
fmt.Printf("Integer months: %d\n", intMonths)
fmt.Printf("Float months: %.2f\n", floatMonths)
// Output:
// Integer months: 1
// Float months: 1.54
}
// ExampleDuration_negative demonstrates negative durations
func ExampleDuration_negative() {
// When start is after end, duration is negative
start := time.Date(2027, 1, 1, 0, 0, 0, 0, time.UTC)
end := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
dur := quando.Diff(start, end)
fmt.Printf("Months: %d\n", dur.Months())
fmt.Printf("Years: %d\n", dur.Years())
// Output:
// Months: -12
// Years: -1
}