Es scheint, dass NSDateFormatter
es eine "Funktion" gibt, die Sie unerwartet beißt: Wenn Sie eine einfache "feste" Formatoperation ausführen, wie z.
NSDateFormatter* fmt = [[NSDateFormatter alloc] init];
[fmt setDateFormat:@"yyyyMMddHHmmss"];
NSString* dateStr = [fmt stringFromDate:someDate];
[fmt release];
Dann funktioniert es in den USA und den meisten Regionen gut, BIS ... jemand, dessen Telefon auf eine 24-Stunden-Region eingestellt ist, den 12/24-Stunden-Schalter in den Einstellungen auf 12 stellt. Dann beginnt das oben Gesagte, "AM" oder "PM" anzuheften das Ende der resultierenden Zeichenfolge.
(Siehe z. B. NSDateFormatter, mache ich etwas falsch oder ist das ein Fehler? )
(Siehe https://developer.apple.com/library/content/qa/qa1480/_index.html )
Anscheinend hat Apple dies als "SCHLECHT" deklariert - Broken As Designed, und sie werden es nicht beheben.
Die Umgehung besteht anscheinend darin, das Gebietsschema des Datumsformatierers für eine bestimmte Region, im Allgemeinen die USA, festzulegen, aber dies ist etwas chaotisch:
NSLocale *loc = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
[df setLocale: loc];
[loc release];
Nicht schlecht in Onsies-Twosies, aber ich habe es mit ungefähr zehn verschiedenen Apps zu tun, und die erste, die ich mir ansehe, enthält 43 Instanzen dieses Szenarios.
Also irgendwelche cleveren Ideen für ein Makro / eine überschriebene Klasse / was auch immer, um den Aufwand zu minimieren, alles zu ändern, ohne den Code zu verschleiern? (Mein erster Instinkt ist, NSDateFormatter mit einer Version zu überschreiben, die das Gebietsschema in der init-Methode festlegt. Erfordert das Ändern von zwei Zeilen - der Alloc / Init-Zeile und dem hinzugefügten Import.)
Hinzugefügt
Das habe ich mir bisher ausgedacht - scheint in allen Szenarien zu funktionieren:
@implementation BNSDateFormatter
-(id)init {
static NSLocale* en_US_POSIX = nil;
NSDateFormatter* me = [super init];
if (en_US_POSIX == nil) {
en_US_POSIX = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
}
[me setLocale:en_US_POSIX];
return me;
}
@end
Kopfgeld!
Ich werde das Kopfgeld an den besten (legitimen) Vorschlag / die beste Kritik vergeben, die ich bis Dienstagmittag sehe. [Siehe unten - Frist verlängert.]
Aktualisieren
Zu OMZs Vorschlag, hier ist was ich finde -
Hier ist die Kategorie Version - h Datei:
#import <Foundation/Foundation.h>
@interface NSDateFormatter (Locale)
- (id)initWithSafeLocale;
@end
Datei der Kategorie m:
#import "NSDateFormatter+Locale.h"
@implementation NSDateFormatter (Locale)
- (id)initWithSafeLocale {
static NSLocale* en_US_POSIX = nil;
self = [super init];
if (en_US_POSIX == nil) {
en_US_POSIX = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
}
NSLog(@"Category's locale: %@ %@", en_US_POSIX.description, [en_US_POSIX localeIdentifier]);
[self setLocale:en_US_POSIX];
return self;
}
@end
Der Code:
NSDateFormatter* fmt;
NSString* dateString;
NSDate* date1;
NSDate* date2;
NSDate* date3;
NSDate* date4;
fmt = [[NSDateFormatter alloc] initWithSafeLocale];
[fmt setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
dateString = [fmt stringFromDate:[NSDate date]];
NSLog(@"dateString = %@", dateString);
date1 = [fmt dateFromString:@"2001-05-05 12:34:56"];
NSLog(@"date1 = %@", date1.description);
date2 = [fmt dateFromString:@"2001-05-05 22:34:56"];
NSLog(@"date2 = %@", date2.description);
date3 = [fmt dateFromString:@"2001-05-05 12:34:56PM"];
NSLog(@"date3 = %@", date3.description);
date4 = [fmt dateFromString:@"2001-05-05 12:34:56 PM"];
NSLog(@"date4 = %@", date4.description);
[fmt release];
fmt = [[BNSDateFormatter alloc] init];
[fmt setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
dateString = [fmt stringFromDate:[NSDate date]];
NSLog(@"dateString = %@", dateString);
date1 = [fmt dateFromString:@"2001-05-05 12:34:56"];
NSLog(@"date1 = %@", date1.description);
date2 = [fmt dateFromString:@"2001-05-05 22:34:56"];
NSLog(@"date2 = %@", date2.description);
date3 = [fmt dateFromString:@"2001-05-05 12:34:56PM"];
NSLog(@"date3 = %@", date3.description);
date4 = [fmt dateFromString:@"2001-05-05 12:34:56 PM"];
NSLog(@"date4 = %@", date4.description);
[fmt release];
Das Ergebnis:
2011-07-11 17:44:43.243 DemoApp[160:307] Category's locale: <__NSCFLocale: 0x11a820> en_US_POSIX
2011-07-11 17:44:43.257 DemoApp[160:307] dateString = 2011-07-11 05:44:43 PM
2011-07-11 17:44:43.264 DemoApp[160:307] date1 = (null)
2011-07-11 17:44:43.272 DemoApp[160:307] date2 = (null)
2011-07-11 17:44:43.280 DemoApp[160:307] date3 = (null)
2011-07-11 17:44:43.298 DemoApp[160:307] date4 = 2001-05-05 05:34:56 PM +0000
2011-07-11 17:44:43.311 DemoApp[160:307] Extended class's locale: <__NSCFLocale: 0x11a820> en_US_POSIX
2011-07-11 17:44:43.336 DemoApp[160:307] dateString = 2011-07-11 17:44:43
2011-07-11 17:44:43.352 DemoApp[160:307] date1 = 2001-05-05 05:34:56 PM +0000
2011-07-11 17:44:43.369 DemoApp[160:307] date2 = 2001-05-06 03:34:56 AM +0000
2011-07-11 17:44:43.380 DemoApp[160:307] date3 = (null)
2011-07-11 17:44:43.392 DemoApp[160:307] date4 = (null)
Das Telefon [machen Sie einen iPod Touch] ist auf Großbritannien eingestellt, der 12/24-Schalter auf 12. Es gibt einen deutlichen Unterschied zwischen den beiden Ergebnissen, und ich beurteile die Kategorieversion als falsch. Beachten Sie, dass das Protokoll in der Kategorieversion ausgeführt wird (und Stopps im Code getroffen werden), sodass der Code nicht einfach nicht verwendet wird.
Kopfgeld-Update:
Da ich noch keine zutreffenden Antworten erhalten habe, werde ich die Kopfgeldfrist um ein oder zwei Tage verlängern.
Das Kopfgeld endet in 21 Stunden - es geht an jeden, der sich am meisten bemüht, zu helfen, auch wenn die Antwort in meinem Fall nicht wirklich nützlich ist.
Eine merkwürdige Beobachtung
Die Implementierung der Kategorie wurde geringfügig geändert:
#import "NSDateFormatter+Locale.h"
@implementation NSDateFormatter (Locale)
- (id)initWithSafeLocale {
static NSLocale* en_US_POSIX2 = nil;
self = [super init];
if (en_US_POSIX2 == nil) {
en_US_POSIX2 = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
}
NSLog(@"Category's locale: %@ %@", en_US_POSIX2.description, [en_US_POSIX2 localeIdentifier]);
[self setLocale:en_US_POSIX2];
NSLog(@"Category's object: %@ and object's locale: %@ %@", self.description, self.locale.description, [self.locale localeIdentifier]);
return self;
}
@end
Grundsätzlich wurde nur der Name der statischen Gebietsschemavariablen geändert (falls es einen Konflikt mit der in der Unterklasse deklarierten statischen Variable gab) und das zusätzliche NSLog hinzugefügt. Aber schauen Sie, was dieser NSLog druckt:
2011-07-15 16:35:24.322 DemoApp[214:307] Category's locale: <__NSCFLocale: 0x160550> en_US_POSIX
2011-07-15 16:35:24.338 DemoApp[214:307] Category's object: <NSDateFormatter: 0x160d90> and object's locale: <__NSCFLocale: 0x12be70> en_GB
2011-07-15 16:35:24.345 DemoApp[214:307] dateString = 2011-07-15 04:35:24 PM
2011-07-15 16:35:24.370 DemoApp[214:307] date1 = (null)
2011-07-15 16:35:24.378 DemoApp[214:307] date2 = (null)
2011-07-15 16:35:24.390 DemoApp[214:307] date3 = (null)
2011-07-15 16:35:24.404 DemoApp[214:307] date4 = 2001-05-05 05:34:56 PM +0000
Wie Sie sehen können, hat die setLocale dies einfach nicht getan. Das Gebietsschema des Formatierers ist immer noch en_GB. Es scheint, dass eine Init-Methode in einer Kategorie etwas "Seltsames" hat.
Endgültige Antwort
Siehe die akzeptierte Antwort unten.
- (NSDateFormatterBehavior)formatterBehavior
?