NSDateFormatter
Sana beklenmedik bir şekilde ısırır bir "özelliği" var gibi görünüyor : Eğer gibi basit bir "sabit" format işlemi yaparsanız:
NSDateFormatter* fmt = [[NSDateFormatter alloc] init];
[fmt setDateFormat:@"yyyyMMddHHmmss"];
NSString* dateStr = [fmt stringFromDate:someDate];
[fmt release];
Daha sonra ABD'de iyi çalışır ve çoğu yerel KADAR kadar ... telefonlarını 24 saatlik bir bölgeye ayarlayan biri 12/24 saat anahtarını ayarlarda 12'ye ayarlar. Sonra yukarıdaki "AM" veya "PM" sonuçta elde edilen dizenin sonu.
(Bkz. Örneğin NSDateFormatter, yanlış bir şey mi yapıyorum yoksa bu bir hata mı? )
(Ve bkz. Https://developer.apple.com/library/content/qa/qa1480/_index.html )
Görünüşe göre Apple bunu "KÖTÜ" olarak ilan etti - Tasarlandığı Gibi Kırıldı ve düzeltmeyecekler.
Atlatma, belirli bir bölge, genellikle ABD için tarih biçimlendiricisinin yerel ayarını yapmaktır, ancak bu biraz dağınıktır:
NSLocale *loc = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
[df setLocale: loc];
[loc release];
Onsies-twosies çok kötü değil, ama yaklaşık on farklı uygulama ile ilgileniyorum, ve ilk baktığım bu senaryo 43 örneği vardır.
Yani bir makro / geçersiz kılınan sınıf / her şeyi değiştirme çabasını en aza indirecek herhangi bir zekice fikir, kodu belirsiz hale getirmeden? (İlk içgüdüm, init yönteminde yerel ayarı ayarlayacak bir sürümle NSDateFormatter'ı geçersiz kılmaktır. İki satırın (ayırma / init satırı ve eklenen içe aktarma) değiştirilmesini gerektirir.)
Katma
Şimdiye kadar bulduğum şey bu - tüm senaryolarda çalışıyor gibi görünüyor:
@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
Ödül!
Ödülünü Salı gün ortası itibariyle gördüğüm en iyi (meşru) öneri / eleştiriye vereceğim. [Aşağıya bakın - süre uzatıldı.]
Güncelleme
Re OMZ'nin teklifi, işte bulduğum şey -
Kategori sürümü - h dosyası:
#import <Foundation/Foundation.h>
@interface NSDateFormatter (Locale)
- (id)initWithSafeLocale;
@end
Kategori m dosyası:
#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
Kod:
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];
Sonuç:
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)
Telefon, bir iPod Touch olmasını sağlayın, 12/24 anahtarı 12'ye ayarlanmış olarak İngiltere'ye ayarlandı. İki sonuçta net bir fark var ve kategori versiyonunun yanlış olduğuna karar veriyorum. Kategori sürümündeki günlüğün yürütüldüğünü (ve koda yerleştirilen durakların vurulduğunu) unutmayın, bu nedenle kodun bir şekilde kullanılmadığı bir durum değildir.
Ödül güncellemesi:
Henüz geçerli bir yanıt alamadığım için ödül tarihini bir iki gün daha uzatacağım.
Ödül 21 saat içinde sona erer - cevabım benim durumumda gerçekten yararlı olmasa bile, yardım etmek için en fazla çaba harcayan kişiye gider.
Meraklı bir gözlem
Kategori uygulamasında biraz değişiklik yapıldı:
#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
Temel olarak, statik yerel ayar değişkeninin adını değiştirdi (alt sınıfta bildirilen statikle bazı çakışma olması durumunda) ve fazladan NSLog ekledi. Ancak NSLog'un ne yazdırdığına bakın:
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
Gördüğünüz gibi, setLocale basitçe yapmadı. Formatlayıcının yerel ayarı hala en_GB. Bir kategorideki init yöntemi hakkında "garip" bir şey olduğu anlaşılıyor.
Son cevap
Bkz kabul cevabı aşağıda.
- (NSDateFormatterBehavior)formatterBehavior
mi?