I want to find the "last Sunday of a month before the current date" in Swift, but using the Calendar nextDate function doesn’t work (always returns nil).
var calendar: Calendar = Calendar(identifier: .gregorian)
calendar.timeZone = .gmt
let lastSundayDateComponents: DateComponents = DateComponents(
weekday: 1,
weekdayOrdinal: -1
)
let previousLastSundayDate: Date? = calendar.nextDate(
after: Date.now,
matching: lastSundayDateComponents,
matchingPolicy: .nextTime,
repeatedTimePolicy: .first,
direction: .backward
)
print(previousLastSundayDate ?? "Not found") // "Not found"
If I use a positive weekdayOrdinal, it’s working normally and the same nextDate method provides the correct date.
let firstSundayDateComponents: DateComponents = DateComponents(
weekday: 1,
weekdayOrdinal: 1
)
When I check if the date components can provide a valid date for the given calendar, it returns false…
let lastSundayInNovember2023DateComponents: DateComponents = DateComponents(
year: 2023,
month: 11,
weekday: 1,
weekdayOrdinal: -1
)
// THIS RETURNS FALSE
let isValid: Bool = lastSundayInNovember2023DateComponents.isValidDate(in: calendar)
print(isValid) // false
… even if the correct date can be created.
let lastSundayInNovember2023: Date = calendar.date(from: lastSundayInNovember2023DateComponents)!
print(lastSundayInNovember2023) // 2023-11-26 00:00:00 +0000
Is that a bug in Foundation?
2
Answers
It seems like there might be an issue with using negative weekdayOrdinal values in combination with the nextDate function in Swift’s Calendar class. This behavior is not well-documented, and there might be an inconsistency or limitation in the implementation.
As a workaround, you can use the following approach to find the last Sunday of the month before the current date:
This approach first calculates the first day of the current month and then finds the last day of the previous month. Finally, it uses the dateComponents method to get the last Sunday of the previous month based on the year, week of the year, and weekday components.
This workaround should provide you with the correct result without relying on negative weekdayOrdinal values.
From the documentation of
weekdayOrdinal
, it doesn’t sound like it should ever be negative:Its name also suggests that it is an ordinal number, which cannot be negative.
I would find the last Sunday of a month by finding what the
weekdayOrdinal
of the next Sunday.and so on.