swiftcocoanscalendarnsdatecomponents

Swift DateComponents weekOfMonth returns wrong value


I'm working on a calendar view (Cocoa macOS app) that shows the current month. When I try to calculate the week number for a given date, I get different results based on the calendar and locale.

For January 1st, 2021, some calls return week 0, others week 1:

    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy-MM-dd"

    let jan2021 = formatter.date(from: "2021-01-01")!

    var deCalendar = Calendar(identifier: .gregorian)
    deCalendar.locale = Locale(identifier: "de_de")
    var usCalendar = Calendar(identifier: .gregorian)
    usCalendar.locale = Locale(identifier: "en_us")
    var deIsoCalendar = Calendar(identifier: .iso8601)
    deIsoCalendar.locale = Locale(identifier: "de_de")
    var usIso = Calendar(identifier: .iso8601)
    usIso.locale = Locale(identifier: "en_us")

    deCalendar.component(.weekOfMonth, from: jan2021)    // 0 
    deIsoCalendar.component(.weekOfMonth, from: jan2021) // 0
    usCalendar.component(.weekOfMonth, from: jan2021)    // 1 ??
    usIso.component(.weekOfMonth, from: jan2021)         // 0

January 1st, 2021 is a Friday so I would expect that the "week of month" is 0 (or 1, depending on if the particular API is zero-based or not).

For February 1st, 2021, which is a Monday, all calls above return week 1!

Just for kicks, Jan 31st, 2021: the us/gregorian calendar returns "week 6", all others "week 4".

Bug?, feature?, what am I missing?

For reference:

calendar


Solution

  • It depends on 2 things in a particular calendar:

    If you look at calendars you used

    deCalendar: minimumDaysInFirstWeek=4, firstWeekday=2
    deIsoCalendar: minimumDaysInFirstWeek=4, firstWeekday=2
    usCalendar: minimumDaysInFirstWeek=1, firstWeekday=1
    usIso: minimumDaysInFirstWeek=4, firstWeekday=2
    

    So 3 calendars require at least 4 days to consider it a first week, and they start from Monday (day 2 in US locale). Hence 3-day week is not going to be considered a first week.

    Calendar 3 has only 1 day requirement for the week, hence even 1-day is a week.