Изглежда, че NSDateFormatter
има "функция", която ви ухапва неочаквано: Ако извършите проста операция с "фиксиран" формат като:
NSDateFormatter* fmt = [[NSDateFormatter alloc] init];
[fmt setDateFormat:@"yyyyMMddHHmmss"];
NSString* dateStr = [fmt stringFromDate:someDate];
[fmt release];
След това работи добре в САЩ и повечето локали ДОКАТО... някой, чийто телефон е настроен на 24-часов регион, настройва превключвателя за 12/24 часа в настройките на 12. След това горното започва да поставя „AM“ или „PM“ на края на получения низ.
(Вижте напр. NSDateFormatter, правя ли нещо не е наред или това е грешка?)
(И вижте https://developer.apple.com/library/content/qa/qa1480/_index.html)
Очевидно Apple са обявили това за "ЛОШО" - Повредено, както е проектирано, и няма да го поправят.
Заобикалянето очевидно е да се зададе локалът на формата на дата за конкретен регион, обикновено САЩ, но това е малко объркващо:
NSLocale *loc = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
[df setLocale: loc];
[loc release];
Не е много лошо в onsies-twosies, но имам работа с около десет различни приложения и първото, което гледам, има 43 случая на този сценарий.
И така, някакви умни идеи за макрос/заменен клас/каквото и да е, за да се сведат до минимум усилията за промяна на всичко, без да се прави кодът неясно? (Първият ми инстинкт е да заменя NSDateFormatter с версия, която ще зададе локала в метода init. Изисква промяна на два реда -- реда alloc/init и добавеното импортиране.)
Добавено
Това е, което измислих досега - изглежда работи във всички сценарии:
@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
Баунти!
Ще присъдя наградата на най-доброто (легитимно) предложение/критика, която видя до средата на деня във вторник. [Вижте по-долу – крайният срок е удължен.]
Актуализация
Относно предложението на OMZ, ето какво откривам --
Ето версията на категорията -- h файл:
#import <Foundation/Foundation.h>
@interface NSDateFormatter (Locale)
- (id)initWithSafeLocale;
@end
Категория 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
Кодът:
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];
Резултатът:
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)
Телефонът [направете този iPod Touch] е настроен на Великобритания, с превключвател 12/24, настроен на 12. Има ясна разлика в двата резултата и смятам, че версията на категорията е грешна. Обърнете внимание, че регистрационният файл във версията на категорията СЕ изпълнява (и спиранията, поставени в кода, са ударени), така че това не е просто случай, когато кодът по някакъв начин не се използва.
Актуализация на наградата:
Тъй като все още не съм получил никакви приложими отговори, ще удължа крайния срок за наградите с още ден или два.
Баунти приключва след 21 часа -- ще отиде при всеки, който положи най-много усилия да помогне, дори ако отговорът не е наистина полезен в моя случай.
Любопитно наблюдение
Променено е леко изпълнението на категорията:
#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
По принцип просто промени името на променливата за статичен локал (в случай че има някакъв конфликт със статиката, декларирана в подкласа) и добави допълнителния NSLog. Но вижте какво отпечатва този NSLog:
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
Както можете да видите, setLocale просто не го направи. Локалът на форматиращия все още е en_GB. Изглежда, че има нещо "странно" в init метод в категория.
Окончателен отговор
Вижте приетия отговор по-долу.
- (NSDateFormatterBehavior)formatterBehavior
? - person bshirley   schedule 12.07.2011