grahan
grahan

Reputation: 2398

Get the current week number in month from Date

I am currently facing a weird issue. I am trying to find out in which week of a month a given Date instance lies.

My code is the following:

var calendar : Calendar {
    var calendar = Calendar(identifier: .iso8601)
    calendar.timeZone = .UTC

    return calendar
}


func generateDate(year: Int, month: Int, day: Int) -> Date {
    let dateComponents = DateComponents(year: year, month: month, day: day)
    return calendar.date(from: dateComponents)!
}

print(calendar.component(.weekOfMonth, from: Date.generateDate(year: 2019, month: 12, day: 1))) // prints "0"
print(calendar.component(.weekOfMonth, from: Date.generateDate(year: 2020, month: 1, day: 1))) // prints "1"

generateDate simply generates a Date with the help of calendar. When I print the both statements I get 0 and 1 as the result. In my opinion this is wrong. I would assume I get the same value for both since both dates should be in the first week of their respective month value.

Another example would be the 2. Dec 2019, this should give the second week as well as the 6. January 2020 should also give me the second week.

Does anyone know what could be wrong here or where my mistake could be ?

Upvotes: 0

Views: 553

Answers (2)

Joakim Danielson
Joakim Danielson

Reputation: 51892

The logic for .weekOfMonth seems to be that if the "first" week is less than half a week, that is 3 days, then it is considered to be week 0 and otherwise week 1. But note that this is dependent on what locale is being used, for a country like Canada that has Sunday as first day of week there is never a week 0 when running the below code. So when the first day of week is Monday .weekOfMonth will return a value between 0 and 5 but when it is Sunday the range is 1 to 6.

This can be seen running the following code in a playground

let calendar = Calendar.current
let year = 2019

print("First day of week: \(calendar.weekdaySymbols[calendar.firstWeekday - 1])")

for month in 1...12 {
    print(calendar.monthSymbols[month - 1])
    let first = calendar.date(from: DateComponents(year: year, month: month, day: 1))!
    if let range = calendar.range(of: .day, in: .month, for: first) {
        var currentWeek = -1
        for day in range {
            let date = calendar.date(from: DateComponents(year: year, month: month, day: day))!
            let week = calendar.component(.weekOfMonth, from: date)
            if week > currentWeek {
                currentWeek = week
                let dayOfWeek = calendar.component(.weekday, from: date)
                print("Week# \(week), weekday \(calendar.weekdaySymbols[dayOfWeek - 1])")
            }
        }
    }
}

It seems to me if you want whatever day it is on the 1st to be the first day of weekOfMonth = 1 then you need to write your own code for this

Upvotes: 1

Abishek Aditya
Abishek Aditya

Reputation: 812

This is due to the 1st day of the month falling on a sunday, try march 01, 2020 if you want confirmation.

The first week of the month is chosen by Swift according to their own standards as ISO standards do not suggest any specific implementations so the Swift team went with this. You can ask them in their forums what their reasoning behind this is Wikipedia link

Upvotes: 1

Related Questions