How to change the order of Calendar weekdaySymbols


Greetings, traveler!

Today, I want to talk about weekday order in Swift. Sometimes, we need to compose weekdays, for example, if we are creating a calendar with weekday representation. Swift offers a Calendar.weekdaySymbols—an instance property representing a weekday list.

Let’s use it then.

let calendar = Calendar.current
let symbols = Calendar
    .current
    .weekdaySymbols
    
symbols // ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]

As we can see, we’ve got an array where the first day of the week is Sunday. We can change a Calendar’s firstWeekday property value, but this won’t help us to change the result.

var calendar = Calendar.current
calendar.firstWeekday = 2

This is because weekdaySymbols provides a static list regardless of any settings. Even if we change the calendar locale, we will not get the expected result.

The firstWeekday property value is locale-related. So, we can Calendar.current.firstWeekday if we want to represent weekdays according to the user’s device locale. We can also set it to the desired value if we don’t want to relate to any locale. To create a weekday symbols array, we can write something like this:

let firstWeekday = Calendar.current.firstWeekday
var weekdays = calendar.weekdaySymbols
weekdays = Array(weekdays[firstWeekday - 1..<symbols.count]) + weekdays[0..<firstWeekday - 1]

We can also use a Locale.Weekday enum and create an allCases static property.

First, to build an array of all cases elegantly, let’s create an extension for Array to append the sequence.

extension Array {
    func appendingSequence(_ sequence: [Element]) -> [Element] {
        self + sequence
    }
}

Now, we can use it like this:

extension Locale.Weekday {
    static var allCases: [Locale.Weekday] {
        Array(Calendar.current.weekdaySymbols[Calendar.current.firstWeekday - 1..<Calendar.current.weekdaySymbols.count])
            .appendingSequence(Array(Calendar.current.weekdaySymbols[0..<Calendar.current.firstWeekday - 1]))
            .compactMap { Locale.Weekday(rawValue: String($0.lowercased().prefix(3))) }
}