Search code examples
iosswiftlocalizationwatchoshebrew

Incorrect localized Hebrew date on iOS and watchOS


I’m working on a date/time app that does things that Apple didn’t build into its OSs and bundled applications.

I’m leveraging built-in classes like Date and DateFormatter for certain parts, and I’m getting some odd results for dates on the Hebrew calendar localized in Hebrew.

If I request the standard full, long, medium, and short formats, everything is fine. But when I supply a template for DateFormatter to use, something weird happens.

That middle row in the three-date complication (containing the date on the Gregorian, Hebrew, and Muslim calendars), is wrong.

It should be יום א׳, ז׳ בחשון תשפ״א, because the convention is for Hebrew dates in Hebrew to use Hebrew numerals.

The relevant code that produces the Hebrew date:

We first start with setting the locale and time zone of our specialized Hebrew and Islamic calendar class’s date formatter.

    if localeIdentifier == "" {
        self.dateFormatter.locale = Locale.current
    } else {
        self.dateFormatter.locale = Locale(identifier: localeIdentifier)
    }
    self.dateFormatter.timeZone = timeZone

After some code dealing with generating the correct time (not really used in a complication), we set the DateFormatter’s dateStyle or date format based one the value of an enum (“majorDateFormat”); if we are supposed to use a template (case .localizedLDML), we use a specific string (“dateGeekFormat”) as the template.

In this case, I have specified a format with weekday, day, month, and year narrow enough to squeeze into a watchOS complication without losing information. We then generate the date string for the Date fixedNow.

   switch majorDateFormat {
    case .localizedLDML:
        let dateFormat = DateFormatter.dateFormat(fromTemplate:dateGeekFormat, options: 0, locale: self.dateFormatter.locale)!
        self.dateFormatter.setLocalizedDateFormatFromTemplate(dateFormat)

    case .none:
        self.dateFormatter.dateStyle = .none

    case .full:
        self.dateFormatter.dateStyle = .full

    case .long:
        self.dateFormatter.dateStyle = .long

    case .medium:
        self.dateFormatter.dateStyle = .medium

    case .short:
        self.dateFormatter.dateStyle = .short

    default:
        self.dateFormatter.dateStyle = .full
    } // switch majorDateFormat

    let dateString = self.dateFormatter.string(from: fixedNow)

Now the weird things are:

  1. For the Islamic calendar in Arabic, Arabic numerals are correctly produced.

  2. This code actually used to correctly work for the Hebrew calendar in Hebrew.

I had no problems with this on watchOS 5 on my old series 0 Apple Watch, but I recently upgraded to an Apple Watch SE running watchOS 7 and discovered this problem.

Has anyone else seen such a problem before? Is this a bug on Apple’s part, or is there something I’ve missed?

Thanks in advance for any help anyone can provide.


Solution

  • Here's how you can produce "יום א׳, ז׳ בחשון תשפ״א"

    let formatter = DateFormatter()
    
    formatter.calendar = Calendar(identifier: .hebrew)
    formatter.locale = Locale(identifier: "he")
    formatter.dateStyle = .short // must come before date format below         
    formatter.setLocalizedDateFormatFromTemplate("c dd MMMM yyyy")
    
    print(formatter.string(from: Date())) // יום א׳, ז׳ בחשון תשפ״א