Ric Santos
Ric Santos

Reputation: 16477

How to generate an ordered list of DateComponents.weekday values for the current locale

From the docs for DateComponents.weekday

Weekday units are the numbers 1 through n, where n is the number of days in the week. For example, in the Gregorian calendar, n is 7 and Sunday is represented by 1.

And from Calendar.firstWeekday

The default value of firstWeekday varies by calendar and locale ... For Gregorian and ISO 8601 calendars, 1 is Sunday.

Given this information, how can we get an array of the weekdays for the current locale, e.g.

returns [2, 3, 4, 5, 6, 7, 1] in Australia, and

returns [1, 2, 3, 4, 5, 6, 7] in USA

Upvotes: 0

Views: 380

Answers (3)

Rob
Rob

Reputation: 438417

In another variation on the theme, I would make it a Calendar extension. E.g., adapting Willeke’s answer:

extension Calendar {
    /// Array of weekday values
    ///
    /// - Returns: An array of `Int` that represent the days of the week where 1 = Sunday and 7 = Saturday.

    func orderedWeekdays() -> [Int] {
        Array(firstWeekday...7) + Array(1..<firstWeekday)
    }
}

Or, alternatively, you can fetch the range of weekdays, and then build the results from that:

extension Calendar {
    /// Array of weekday values
    ///
    /// - Returns: An array of `Int` that represent the days of the week where 1 = Sunday and 7 = Saturday.

    func orderedWeekdays() -> [Int] {
        guard
            let weekdays = range(of: .weekday, in: .weekOfYear, for: Date()),
            let index = weekdays.firstIndex(of: firstWeekday)
        else { return [] }

        return Array(weekdays[index...]) + Array(weekdays[..<index])
    }
}

Upvotes: 3

Willeke
Willeke

Reputation: 15633

Here you go:

extension DateComponents {

    /// Returns an array of Int that represent the days of the week in the given calendar's locale
    ///    e.g. returns [2, 3, 4, 5, 6, 7, 1] in Australia
    ///    e.g. returns [1, 2, 3, 4, 5, 6, 7] in USA
    static func orderedWeekdays(for calendar: Calendar) -> [Int] {
        let firstWeekday = calendar.firstWeekday
        return Array(firstWeekday...7) + Array(1..<firstWeekday)
    }
    
}

Edit: It should be a Calendar extension. See Rob's Answer.

Upvotes: 2

Ric Santos
Ric Santos

Reputation: 16477

This is what I've done, hopefully there is a better way...

extension DateComponents {
    /// Returns an array of Int that represent the days of the week in the given calendar's locale
    ///    e.g. returns [2, 3, 4, 5, 6, 7, 1] in Australia
    ///    e.g. returns [1, 2, 3, 4, 5, 6, 7] in USA
    static func orderedWeekdays(for calendar: Calendar) -> [Int] {
        let unorderedWeekdays: [Int] = Array(1...7)
        var orderedWeekdays: [Int] = []
        if var index = unorderedWeekdays.firstIndex(of: calendar.firstWeekday) {
            while (orderedWeekdays.count < unorderedWeekdays.count) {
                orderedWeekdays.append(unorderedWeekdays[index])
                index += 1
                if index >= unorderedWeekdays.count {
                    index = 0
                }
            }
        } else {
            orderedWeekdays = unorderedWeekdays
        }
        return orderedWeekdays
    }
}

Upvotes: 1

Related Questions