@@ -54,6 +54,58 @@ final class CalendarRecurrenceRuleTests: XCTestCase {
54
54
XCTAssertEqual ( results, expectedResults)
55
55
}
56
56
57
+ func testExpandToLeapMonths( ) {
58
+ var lunarCalendar = Calendar ( identifier: . chinese)
59
+ lunarCalendar. timeZone = . gmt
60
+ let locale = Locale ( identifier: " zh-TW " )
61
+
62
+ let start = Date ( timeIntervalSince1970: 1729641600.0 ) // 2024-10-23T00:00:00-0000
63
+
64
+ var rule = Calendar . RecurrenceRule ( calendar: lunarCalendar, frequency: . yearly)
65
+ rule. months = [ Calendar . RecurrenceRule. Month ( 6 , isLeap: true ) ]
66
+ rule. daysOfTheMonth = [ 1 ]
67
+ var sequence = rule. recurrences ( of: start) . makeIterator ( )
68
+
69
+ XCTAssertEqual ( sequence. next ( ) , Date ( timeIntervalSince1970: 1753401600.0 ) ) // 2025-07-25T00:00:00-0000 (Sixth leap month)
70
+ XCTAssertEqual ( sequence. next ( ) , Date ( timeIntervalSince1970: 1786579200.0 ) ) // 2026-08-13T00:00:00-0000 (Seventh month)
71
+ XCTAssertEqual ( sequence. next ( ) , Date ( timeIntervalSince1970: 1817164800.0 ) ) // 2027-08-02T00:00:00-0000 (Seventh month)
72
+ XCTAssertEqual ( sequence. next ( ) , Date ( timeIntervalSince1970: 1850342400.0 ) ) // 2028-08-20T00:00:00-0000 (Seventh month)
73
+ XCTAssertEqual ( sequence. next ( ) , Date ( timeIntervalSince1970: 1881014400.0 ) ) // 2029-08-10T00:00:00-0000 (Seventh month)
74
+ }
75
+
76
+ func testStartFromLeapMonth( ) {
77
+ var lunarCalendar = Calendar ( identifier: . chinese)
78
+ lunarCalendar. timeZone = . gmt
79
+
80
+ // Find recurrences of an event that happens on a leap month
81
+ let start = Date ( timeIntervalSince1970: 1753401600.0 ) // 2025-07-25T00:00:00-0000 (Leap month)
82
+
83
+ // A non-strict recurrence would match the month where the leap month would have been
84
+ let rule = Calendar . RecurrenceRule ( calendar: lunarCalendar, frequency: . yearly, matchingPolicy: . nextTimePreservingSmallerComponents)
85
+ var sequence = rule. recurrences ( of: start) . makeIterator ( )
86
+
87
+ XCTAssertEqual ( sequence. next ( ) , Date ( timeIntervalSince1970: 1753401600.0 ) ) // 2025-07-25T00:00:00-0000 (Sixth leap month)
88
+ XCTAssertEqual ( sequence. next ( ) , Date ( timeIntervalSince1970: 1786579200.0 ) ) // 2026-08-13T00:00:00-0000 (Seventh month)
89
+ XCTAssertEqual ( sequence. next ( ) , Date ( timeIntervalSince1970: 1817164800.0 ) ) // 2027-08-02T00:00:00-0000 (Seventh month)
90
+ XCTAssertEqual ( sequence. next ( ) , Date ( timeIntervalSince1970: 1850342400.0 ) ) // 2028-08-20T00:00:00-0000 (Seventh month)
91
+ XCTAssertEqual ( sequence. next ( ) , Date ( timeIntervalSince1970: 1881014400.0 ) ) // 2029-08-10T00:00:00-0000 (Seventh month)
92
+ XCTAssertEqual ( sequence. next ( ) , Date ( timeIntervalSince1970: 1911600000.0 ) ) // 2030-07-30T00:00:00-0000 (Seventh month)
93
+ XCTAssertEqual ( sequence. next ( ) , Date ( timeIntervalSince1970: 1944777600.0 ) ) // 2031-08-18T00:00:00-0000 (Seventh month)
94
+ XCTAssertEqual ( sequence. next ( ) , Date ( timeIntervalSince1970: 1975363200.0 ) ) // 2032-08-06T00:00:00-0000 (Seventh month)
95
+ XCTAssertEqual ( sequence. next ( ) , Date ( timeIntervalSince1970: 2005948800.0 ) ) // 2033-07-26T00:00:00-0000 (Seventh month)
96
+ XCTAssertEqual ( sequence. next ( ) , Date ( timeIntervalSince1970: 2039126400.0 ) ) // 2034-08-14T00:00:00-0000 (Seventh month)
97
+ XCTAssertEqual ( sequence. next ( ) , Date ( timeIntervalSince1970: 2069798400.0 ) ) // 2035-08-04T00:00:00-0000 (Seventh month)
98
+ XCTAssertEqual ( sequence. next ( ) , Date ( timeIntervalSince1970: 2100384000.0 ) ) // 2036-07-23T00:00:00-0000 (Sixth leap month)
99
+ XCTAssertEqual ( sequence. next ( ) , Date ( timeIntervalSince1970: 2133561600.0 ) ) // 2037-08-11T00:00:00-0000 (Seventh month)
100
+ XCTAssertEqual ( sequence. next ( ) , Date ( timeIntervalSince1970: 2164233600.0 ) ) // 2038-08-01T00:00:00-0000 (Seventh month)
101
+
102
+ // A strict recurrence only matches in years with leap months
103
+ let strictRule = Calendar . RecurrenceRule ( calendar: lunarCalendar, frequency: . yearly, matchingPolicy: . strict)
104
+ var strictSequence = strictRule. recurrences ( of: start) . makeIterator ( )
105
+ XCTAssertEqual ( strictSequence. next ( ) , Date ( timeIntervalSince1970: 1753401600.0 ) ) // 2025-07-25T00:00:00-0000 (Sixth leap month)
106
+ XCTAssertEqual ( strictSequence. next ( ) , Date ( timeIntervalSince1970: 2100384000.0 ) ) // 2036-07-23T00:00:00-0000 (Sixth leap month)
107
+ }
108
+
57
109
func testDaylightSavingsRepeatedTimePolicyFirst( ) {
58
110
let start = Date ( timeIntervalSince1970: 1730535600.0 ) // 2024-11-02T01:20:00-0700
59
111
var rule = Calendar . RecurrenceRule ( calendar: gregorian, frequency: . daily)
@@ -68,9 +120,9 @@ final class CalendarRecurrenceRuleTests: XCTestCase {
68
120
Date ( timeIntervalSince1970: 1730712000.0 ) , // 2024-11-04T01:20:00-0800
69
121
]
70
122
XCTAssertEqual ( results, expectedResults)
71
- }
72
-
73
- func testDaylightSavingsRepeatedTimePolicyLast( ) {
123
+ }
124
+
125
+ func testDaylightSavingsRepeatedTimePolicyLast( ) {
74
126
let start = Date ( timeIntervalSince1970: 1730535600.0 ) // 2024-11-02T01:20:00-0700
75
127
var rule = Calendar . RecurrenceRule ( calendar: gregorian, frequency: . daily)
76
128
rule. repeatedTimePolicy = . last
@@ -84,5 +136,5 @@ final class CalendarRecurrenceRuleTests: XCTestCase {
84
136
Date ( timeIntervalSince1970: 1730712000.0 ) , // 2024-11-04T01:20:00-0800
85
137
]
86
138
XCTAssertEqual ( results, expectedResults)
87
- }
139
+ }
88
140
}
0 commit comments