In Swift, how can I get the "last Sunday of a month before the current date"?

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?

Replies

I did not test if there's a bug.

But to get the result I would:

  • get the date of 1/1 of following month
  • step backward 1 day
  • teint read shay day it is
  • and compute backward to get the last Sunday.

Hope that's useful.

If I use a positive weekdayOrdinal, it's working normally and the same nextDate(…) method provides the correct date.

I’ve never seen anyone use negative values for weekdayOrdinal. Is that documented somewhere?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

  • @eskimo I don’t think it is documented so I guess this is not supported. But I would have found useful in situations like these where you want to count backwards. When we create EKRecurrenceRule, we can use negative setPositions: Negative values indicate counting backwards from the end of the recurrence rule’s frequency (week, month, or year).. This is the equivalent to rrule bySetPos.

Add a Comment