Skip to content

Conversation

@ChuckNovice
Copy link
Owner

Summary

  • Add CreateRecurrenceOptions parameter to CreateRecurrenceAsync with OutOfBoundsMonthBehavior setting
  • Introduce MonthDayOutOfBoundsStrategy enum: Throw (default), Skip, Clamp
  • Add MonthDayOutOfBoundsException containing affected months when Throw strategy is used
  • Implement strategy pattern for occurrence generation with IOccurrenceGenerator interface
  • Add MonthDayBehavior field to Recurrence domain entity and database schemas

Details

When creating monthly recurrences with days that don't exist in all months (e.g., 31st in April, June, September, November; or 29th/30th/31st in February), the caller can now specify how to handle these cases:

Strategy Behavior
Throw (default) Throws MonthDayOutOfBoundsException with AffectedMonths list, allowing the caller to prompt the user
Skip Skips months where the specified day doesn't exist
Clamp Uses the last day of short months (e.g., 31st → 30th in April, 31st → 28th/29th in February)

New Files

  • src/RecurringThings/Options/MonthDayOutOfBoundsStrategy.cs
  • src/RecurringThings/Options/CreateRecurrenceOptions.cs
  • src/RecurringThings/Exceptions/MonthDayOutOfBoundsException.cs
  • src/RecurringThings/Engine/Virtualization/IOccurrenceGenerator.cs
  • src/RecurringThings/Engine/Virtualization/IcalNetOccurrenceGenerator.cs
  • src/RecurringThings/Engine/Virtualization/ClampedMonthlyOccurrenceGenerator.cs
  • src/RecurringThings/Engine/Virtualization/OccurrenceGeneratorFactory.cs
  • src/RecurringThings.PostgreSQL/Migrations/20260127200000_AddMonthDayBehavior.cs
  • tests/RecurringThings.Tests/Engine/RecurrenceEngineMonthlyBoundsTests.cs

Test plan

  • Build succeeds with 0 warnings
  • All 190 unit tests pass
  • Code formatted with dotnet format

🤖 Generated with Claude Code

When creating monthly recurrences with days that don't exist in all months
(e.g., 31st in April), callers can now specify a strategy via CreateRecurrenceOptions:
- Throw (default): Throws MonthDayOutOfBoundsException with affected months
- Skip: Skips months where the day doesn't exist
- Clamp: Uses the last day of short months

Introduces strategy pattern for occurrence generation with IOccurrenceGenerator,
IcalNetOccurrenceGenerator (for Skip), and ClampedMonthlyOccurrenceGenerator (for Clamp).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@ChuckNovice ChuckNovice merged commit 80a7f75 into main Jan 28, 2026
2 checks passed
@ChuckNovice ChuckNovice deleted the feature/monthly-out-of-bounds-handling branch January 28, 2026 04:49
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