Home > Software design >  Properly ordering month and date according to locale
Properly ordering month and date according to locale

Time:03-14

I want to display start and end date of week in a human readable format. Using MMMM d as date format base. For example:

- March 7 - 13
- February 28 - March 6
- 7-13 de marzo

So if week start and end falls under the same month, I want to mention month only once. And I want this to be accurate in different locales. In Spanish and Belarussian for example day would go before month, and in Spanish there will be "de" added before the month name.

I'm using

DateFormatter.dateFormat(
                fromTemplate: "MMMM d",
                options: 0,
                locale: Locale(identifier: Bundle.main.preferredLocalizations.first

to get proper format and then try to parse it and replace days with two numbers for when week completely falls into same month. I realized that code I have is a bit hacky and might not guarantee to work with all possible locales. But I have no idea is there easier / better way.

Here is what I have so far:

func weekDateTitle(firstDay: Date, lastDay: Date) -> String {
    let dateTemplate = DateFormatter.dateFormat(
        fromTemplate: "MMMM d",
        options: 0,
        locale: Locale(identifier: Bundle.main.preferredLocalizations.first ?? "en"))
    let formatter = DateFormatter()

    // If the week ends on the same month as it begins, we use short label format,
    // like "Month X - Y"
    if firstDay.isSameMonth(as: lastDay) {
        formatter.dateFormat = "MMMM"
        let month = formatter.string(from: firstDay)
        
        formatter.dateFormat = "d"
        let days = "\(formatter.string(from: firstDay)) - \(formatter.string(from: lastDay))"
        
        return dateTemplate?
             .replacingFirstOccurrence(of: "MMMM", with: month)
             .replacingFirstOccurrence(of: "d", with: days)
             .replacingOccurrences(of: "'", with: "") ?? ""
    } else {
    // Not really important 
    }
}

CodePudding user response:

Consider DateIntervalFormatter:

let formatter = DateIntervalFormatter()

formatter.locale = locale
formatter.dateTemplate = "MMMMd"

let string = formatter.string(from: date1, to: date2)

For the same month, that will generate “7 – 13 de marzo” and “March 7 – 13”.

For different months, “7 de febrero – 13 de marzo” and “February 7 – March 13”.

There are weird edge cases with these formatters (e.g., a dateStyle of .long works in English speaking locales, but not in others). And I wouldn’t be surprised if the above was not working perfectly in all of your target locales, so you might want to double check. But, in my experience, these formatters can get you pretty close. It appears to achieve what you need in English and Spanish…

  • Related