Search code examples
iosdatelocalizationnsdateformatterhebrew

NSDateFormatter doesn't support long-form day periods ('b' or 'B')


NSDateFormatter doesn't seem able to use the 'B' or 'b' format specifiers. 'B' is a little like 'a' (am/pm), but it outputs things like "at night" or "in the morning".

For example, this code:

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
NSLocale* locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en-US"];
NSString *dateTemplate = [NSDateFormatter dateFormatFromTemplate:@"h:mmB" 
                                                         options:0 
                                                         locale:locale];
[dateFormatter setDateFormat:dateTemplate];
[dateFormatter setLocale:locale];
NSString* now = [dateFormatter stringFromDate:[NSDate date]];

NSLog(@"String:\t%@\ndateTemplate:\t%@", 
      now,
      dateFormatter.dateFormat);

...prints this:

String: 10:23 PM         // Should be "10:23 at night"
dateTemplate:   h:mm a   // Note that 'B' turned into 'a' (am/pm)

Skipping dateFormatFromTemplate and putting the format directly into the formatter has the same effect.

The docs say that iOS 7 and later use tr35-31. It's unclear whether that spec supports 'B'. The formatting table for version 31 mentions 'a', but does not mention 'B'. On the other hand, the spec for all of tr35 does indeed mention 'B'.

If you download the actual CLDR data for version 31, you can find dayPeriod entries for "in the evening" etc.

The data exists; is there another formatting string I can use to get longer "day period" strings?


Solution

  • You are correct that B is used for a "natural language" description of the day period. However, the problem you're experiencing is arising from using it in a date format template.

    It would seem that the CLDR does not recognize that it should keep B in a date format string when you ask it to localize a template format. Thus, it's substituting a back in to the final format string.

    Incidentally, if you run through +[NSLocale availableLocaleIdentifiers], you'll see that there isn't any locale that support B in a template string.

    However, if you use B in a date format string directly, then it works as expected:

    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    dateFormatter.dateFormat = @"h:mm B";
    NSLog(@"%@", [dateFormatter stringFromDate:[NSDate date]]);
    

    Outputs:

    12:57 in the afternoon