Skip to content

Conversation

@sam-at-luther
Copy link
Member

Overview

This PR adds the package, which provides a canonical (years, months, days) difference calculator for civil dates.

Key Features

  • O(1) Algorithm: Computes date differences in constant time (no day-by-day loops)
  • DoS-Safe: Guards against overflow, invalid date ranges, and mega-span attacks
  • Flexible Month Rollover: Injectable allows custom month-addition semantics
  • Civil Date Model: Works with proleptic Gregorian calendar dates (Year 1-9999)
  • No Duration Overflow: Uses civil serial-day function instead of time.Duration arithmetic

API

Main Functions

  • DiffYMD(start, end, addMonths): Compute (Y,M,D) difference with default guards
  • DiffYMDOpts(start, end, opts): Full control over month policy and DoS limits
  • YMDiff.Apply(start, addMonths): Reconstruct end date from YMD difference

Types

  • YMDiff: Canonical (Years, Months, Days) tuple
  • AddMonthsFn: Injectable function for month-rollover semantics
  • DiffOptions: Configuration for span limits and custom policies

Testing

✅ All tests pass with comprehensive coverage:

  • Monthly increment tests for all month start/end dates
  • Random date pair validation
  • Leap year edge cases (Feb 29 handling)
  • Error condition testing
  • Round-trip invariant verification
  • Custom AddMonthsFn injection

✅ Code lints cleanly with golangci-lint (0 issues)

Implementation Details

  • Uses Howard Hinnant's civil-day algorithm for date serial conversion
  • Defaults to Go's time.AddDate(0, m, 0) clamping for month arithmetic
  • Maximum whole months algorithm: find M where addMonths(start, M) <= end
  • Leftover days computed via civil serial-day subtraction (no DST artifacts)

Notes

  • Package name matches directory name (libdates)
  • Compatible with testify for test assertions
  • All date calculations normalized to UTC midnight (no time zone effects)
  • Designed to mirror ELPS cc:add-months semantics when using custom AddMonthsFn

- Implements canonical (years, months, days) difference between civil dates
- Uses DoS-safe O(1) algorithm with configurable month-rollover semantics
- Provides DiffYMD() and DiffYMDOpts() for flexible date calculations
- Includes comprehensive test coverage with testify
- All tests pass and code lints cleanly
- Supports custom AddMonthsFn injection for runtime compatibility
- Guards against overflow, invalid ranges, and mega-span attacks
Security update to address vulnerabilities in the phonenumbers package.
@sam-at-luther sam-at-luther merged commit 8c6d9c9 into main Nov 12, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants