What is the best way to deal with the NSDateFormatter locale "feechur"?

Solution 1:

Duh!!

Sometimes you have an "Aha!!" moment, sometimes it's more of a "Duh!!" This is the latter. In the category for initWithSafeLocale the "super" init was coded as self = [super init];. This inits the SUPERCLASS of NSDateFormatter but does not init the NSDateFormatter object itself.

Apparently when this initialization is skipped, setLocale "bounces off", presumably because of some missing data structure in the object. Changing the init to self = [self init]; causes the NSDateFormatter initialization to occur, and setLocale is happy again.

Here is the "final" source for the category's .m:

#import "NSDateFormatter+Locale.h"

@implementation NSDateFormatter (Locale)

- (id)initWithSafeLocale {
    static NSLocale* en_US_POSIX = nil;
    self = [self init];
    if (en_US_POSIX == nil) {
        en_US_POSIX = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
    }
    [self setLocale:en_US_POSIX];
    return self;    
}

@end

Solution 2:

Instead of subclassing, you could create an NSDateFormatter category with an additional initializer that takes care of assigning the locale and possibly also a format string, so you'd have a ready-to-use formatter right after initializing it.

@interface NSDateFormatter (LocaleAdditions)

- (id)initWithPOSIXLocaleAndFormat:(NSString *)formatString;

@end

@implementation NSDateFormatter (LocaleAdditions)

- (id)initWithPOSIXLocaleAndFormat:(NSString *)formatString {
    self = [super init];
    if (self) {
        NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
        [self setLocale:locale];
        [locale release];
        [self setFormat:formatString];
    }
    return self;
}

@end

Then you could use NSDateFormatter anywhere in your code with just:

NSDateFormatter* fmt = [[NSDateFormatter alloc] initWithPOSIXLocaleAndFormat:@"yyyyMMddHHmmss"];

You might want to prefix your category method somehow to avoid name conflicts, just in case Apple decides to add such a method in a future version of the OS.

In case you're always using the same date format(s), you could also add category methods that return singleton instances with certain configurations (something like +sharedRFC3339DateFormatter). Be aware however that NSDateFormatter is not thread-safe and you have to use locks or @synchronized blocks when you're using the same instance from multiple threads.