skip to Main Content

I’m looking for a way to fill a Set with the weeks that hold the first of any month for the current year. For example, since the first week of the year normally holds the first day in January, I would simply add it to the SET as a 1, and then I would check for any other weeks in the year that holds the first of any month and add it to the SET as well. My current problem is finding out a way to check what weeks hold the first of any month in the current year. I thought at first of getting the first and last day of the a month but I’ve started to confuse myself at this point. Any help would be appreciated.

extension Date {

    func getStart(of component: Calendar.Component, calendar: Calendar = Calendar.current) -> Date? {
        return calendar.dateInterval(of: component, for: self)?.start
    }

    func getEnd(of component: Calendar.Component, calendar: Calendar = Calendar.current) -> Date? {
        return calendar.dateInterval(of: component, for: self)?.end
    }
}

Goal: 2023, Set = (1,5,9…etc)

2

Answers


  1. I think you are overcomplicating this. Just loop through the 12 months of the year, create a date from year, month and day, and get its week-of-year.

    let year = 2023
    let calendar = Calendar(identifier: .gregorian)
    for month in 1...12 {
        let dateComponents = DateComponents(calendar: calendar, year: year, month: month/*, day: 1*/)
        guard let firstDayOfMonth = dateComponents.date else {
            print("unable to get first day of month")
            continue
        }
        let weekNumber = calendar.component(.weekOfYear, from: firstDayOfMonth)
        print(weekNumber) // or add it to a set or whatever
    }
    
    Login or Signup to reply.
  2. This is a different approach with dedicated enumerateDates(startingAfter:matching:matchingPolicy:using:) of Calendar.

    Unfortunately the API has (still) a bug: It doesn’t find any date if the year is specified in the matching components, so you have to check for the end manually.

    Basically if you are dealing with weeks the iso8601 calendar is preferable

    let year = 2023
    let calendar = Calendar(identifier: .iso8601)
    let queryComponents = DateComponents(calendar: calendar, day: 1)
    var weeks = Set<Int>()
    let startOfYear = calendar.date(from: DateComponents(calendar: calendar, year: year, month: 1, day: 1, hour: 10))!
    calendar.enumerateDates(startingAfter: startOfYear,
                            matching: queryComponents,
                            matchingPolicy: .nextTime,
                            using: { date, _, stop in
        if let date {
            let weekOfYearComponents = calendar.dateComponents([.weekOfYear, .year], from: date)
            if weekOfYearComponents.year! > year { stop = true }
            weeks.insert(weekOfYearComponents.weekOfYear!)
        }
    })
    print(weeks)
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search