diff --git a/Sources/FoundationEssentials/Calendar/Calendar.swift b/Sources/FoundationEssentials/Calendar/Calendar.swift index 348b468b1..a35488120 100644 --- a/Sources/FoundationEssentials/Calendar/Calendar.swift +++ b/Sources/FoundationEssentials/Calendar/Calendar.swift @@ -1153,9 +1153,17 @@ public struct Calendar : Hashable, Equatable, Sendable { } let weekendEndComponents = DateComponents(weekday: weekend.end) - // We only care about the end date to get the interval of the weekend, so we don't care if it falls ahead of the passed in date. Always search forward from here, since we just found the *beginning* of the weekend. - guard var end = nextDate(after: start, matching: weekendEndComponents, matchingPolicy: .nextTime, repeatedTimePolicy: .first, direction: .forward) else { - return nil + + var end: Date + if weekend.start == weekend.end { + // This locale has a 1-day weekend + end = start + } else { + // We only care about the end date to get the interval of the weekend, so we don't care if it falls ahead of the passed in date. Always search forward from here, since we just found the *beginning* of the weekend. + guard let possibleEnd = nextDate(after: start, matching: weekendEndComponents, matchingPolicy: .nextTime, repeatedTimePolicy: .first, direction: .forward) else { + return nil + } + end = possibleEnd } if let ceaseTime = weekend.ceaseTime, ceaseTime > 0 { @@ -1667,7 +1675,8 @@ package struct WeekendRange: Equatable, Hashable { package var ceaseTime: TimeInterval? package var start: Int package var end: Int - + + // start == end means a one-day weekend. There isn't a known use case for 7-day weekend. package init(onsetTime: TimeInterval? = nil, ceaseTime: TimeInterval? = nil, start: Int, end: Int) { self.onsetTime = onsetTime self.ceaseTime = ceaseTime diff --git a/Tests/FoundationInternationalizationTests/CalendarTests.swift b/Tests/FoundationInternationalizationTests/CalendarTests.swift index c83abb986..3a2d67e74 100644 --- a/Tests/FoundationInternationalizationTests/CalendarTests.swift +++ b/Tests/FoundationInternationalizationTests/CalendarTests.swift @@ -907,7 +907,49 @@ private struct CalendarTests { #expect(weekend != nil) #expect(weekend == weekendForNilLocale) } - + + @Test func weekendRange_1dayWeekend() throws { + var calendar = Calendar(identifier: .gregorian) + calendar.locale = Locale(identifier: "en_IN") + calendar.timeZone = .gmt + + do { + // Date(timeIntervalSinceReferenceDate: 0) is a Monday + // India's weekend is on Sunday + let weekend = try #require(calendar.nextWeekend(startingAfter: Date(timeIntervalSinceReferenceDate: 0))) + let expectStart = try Date("2001-01-07T00:00:00Z", strategy: .iso8601) + #expect(weekend.start == expectStart) + + let expectEnd = try Date("2001-01-08T00:00:00Z", strategy: .iso8601) + #expect(weekend.end == expectEnd) + + let previousWeekend = try #require(calendar.nextWeekend(startingAfter: Date(timeIntervalSinceReferenceDate: 0), direction: .backward)) + let expectedPreviousStart = try Date("2000-12-31T00:00:00Z", strategy: .iso8601) + #expect(previousWeekend.start == expectedPreviousStart) + + let expectedPreviousEnd = try Date("2001-01-01T00:00:00Z", strategy: .iso8601) + #expect(previousWeekend.end == expectedPreviousEnd) + } + + // Starting on a weekend + do { + let sundayMidnight = Date(timeIntervalSinceReferenceDate: -86400) + let weekend = try #require(calendar.nextWeekend(startingAfter: sundayMidnight)) + let expectStart = try Date("2001-01-07T00:00:00Z", strategy: .iso8601) + #expect(weekend.start == expectStart) + + let expectEnd = try Date("2001-01-08T00:00:00Z", strategy: .iso8601) + #expect(weekend.end == expectEnd) + + let previousWeekend = try #require(calendar.nextWeekend(startingAfter: sundayMidnight, direction: .backward)) + let expectedPreviousStart = try Date("2000-12-24T00:00:00Z", strategy: .iso8601) + #expect(previousWeekend.start == expectedPreviousStart) + + let expectedPreviousEnd = try Date("2000-12-25T00:00:00Z", strategy: .iso8601) + #expect(previousWeekend.end == expectedPreviousEnd) + } + } + @Test func datesAdding_range() { let startDate = Date(timeIntervalSinceReferenceDate: 689292158.712307) // 2022-11-04 22:02:38 UTC let endDate = startDate + (86400 * 3) + (3600 * 2) // 3 days + 2 hours later - cross a DST boundary which adds a day with an additional hour in it