diff --git a/Proposals/nnnn-calendar-recurrence-rule-partial-range.md b/Proposals/nnnn-calendar-recurrence-rule-partial-range.md new file mode 100644 index 000000000..32314732b --- /dev/null +++ b/Proposals/nnnn-calendar-recurrence-rule-partial-range.md @@ -0,0 +1,94 @@ +# Search for recurrence in partial ranges + +* Proposal: SF-NNNN +* Author: Hristo Staykov +* Implementation: [#1456](https://github.com/swiftlang/swift-foundation/pull/1456) +* Status: **Draft** + +## Revision history + +* **v1** Initial version + +## Introduction + +In [SF-0009](0009-calendar-recurrence-rule.md) we introduced `Calendar.RecurrenceRule`. With this API, we can find occurences of a recurring event in a given range: + +```swift +let birthday = Date(timeIntervalSince1970: 813283200.0) // 1995-10-10T00:00:00-0000 +let rangeStart = Date(timeIntervalSince1970: 946684800.0) // 2000-01-01T00:00:00-0000 +let rangeEnd = Date(timeIntervalSince1970: 1293840000.0) // 2011-01-01T00:00:00-0000 + +let recurrence = Calendar.RecurrenceRule(calendar: .current, frequency: .yearly) +for date in recurrence.recurrences(of: birthday, in: rangeStart..= rangeStart { + // All occurrences of `birthday` after 2000 +} +``` + +or specify a range that stretches to `Date.distantPast` or `Date.distantFuture`: + +```swift +for date in recurrence.recurrences(of: birthday, in: rangeStart.. + ) -> some (Sequence & Sendable) + @available(FoundationPreview 6.3, *) + public func recurrences(of start: Date, + in range: PartialRangeTo + ) -> some (Sequence & Sendable) + @available(FoundationPreview 6.3, *) + public func recurrences(of start: Date, + in range: PartialRangeFrom + ) -> some (Sequence & Sendable) + @available(FoundationPreview 6.3, *) + public func recurrences(of start: Date, + in range: ClosedRange + ) -> some (Sequence & Sendable) +} +``` + + +With this, the above example would simply become: + +```swift +for date in recurrence.recurrences(of: birthday, in: rangeStart...) { + // All occurrences of `birthday` after 2000 +} +``` + + +## Impact on existing code + +None. + +## Alternatives considered + +This API is a convenience over the workarounds presented in the introduction, but it +is also more performant since we don't calculate dates we don't need in the final range. + +For cases where we're looking for recurrences up until a date, it might be tempting to set the `end` property of the recurrence rule to the end of the range: +```swift +recurrence.end = .afterDate(rangeEnd) +``` +That is not advised for the recurrence rule might already have an `end` property of `.afterOcurrences()`. Besides, the recurrence rule struct represents when the event occurs, and the range in which we search is does not change that. + +We did consider instead only adding one method that accepts a `RangeExpression` argument. However, that means supporting any arbitrary ranges conforming to the protocol, in which cases we may not have lower and upper bounds that allow us to optimize search.