Dường như NSDateFormatter
có một "tính năng" khiến bạn bất ngờ cắn: Nếu bạn thực hiện một thao tác định dạng "cố định" đơn giản như:
NSDateFormatter* fmt = [[NSDateFormatter alloc] init];
[fmt setDateFormat:@"yyyyMMddHHmmss"];
NSString* dateStr = [fmt stringFromDate:someDate];
[fmt release];
Sau đó, nó hoạt động tốt ở Hoa Kỳ và hầu hết các địa phương UNTIL ... ai đó với điện thoại của họ được đặt thành khu vực 24 giờ sẽ đặt công tắc 12/24 giờ trong cài đặt thành 12. Sau đó, phần trên bắt đầu ghép "AM" hoặc "PM" lên kết thúc chuỗi kết quả.
(Xem, ví dụ: NSDateFormatter, tôi đang làm gì đó sai hay đây là lỗi? )
(Và xem https://developer.apple.com/l Library / content / qa / qa1480 / _index.html )
Rõ ràng Apple đã tuyên bố đây là "BAD" - Hỏng như được thiết kế và họ sẽ không sửa nó.
Việc lách luật rõ ràng là đặt ngôn ngữ của trình định dạng ngày cho một khu vực cụ thể, nói chung là Hoa Kỳ, nhưng điều này hơi lộn xộn:
NSLocale *loc = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
[df setLocale: loc];
[loc release];
Không quá tệ trong các phần hai mươi, nhưng tôi đang xử lý khoảng mười ứng dụng khác nhau và ứng dụng đầu tiên tôi nhìn thấy có 43 trường hợp của kịch bản này.
Vì vậy, bất kỳ ý tưởng thông minh cho một lớp vĩ mô / ghi đè / bất cứ điều gì để giảm thiểu nỗ lực thay đổi mọi thứ, mà không làm cho mã bị che khuất? (Bản năng đầu tiên của tôi là ghi đè NSDateFormatter bằng một phiên bản sẽ đặt ngôn ngữ trong phương thức init. Yêu cầu thay đổi hai dòng - dòng alloc / init và nhập thêm.)
Thêm
Đây là những gì tôi đã nghĩ ra cho đến nay - dường như hoạt động trong tất cả các tình huống:
@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
Tiền thưởng!
Tôi sẽ trao phần thưởng cho đề xuất / phê bình tốt nhất (hợp pháp) mà tôi thấy vào giữa ngày thứ ba. [Xem bên dưới - thời hạn được gia hạn.]
Cập nhật
Đề xuất của OMZ, đây là những gì tôi đang tìm kiếm -
Đây là phiên bản thể loại - tập tin h:
#import <Foundation/Foundation.h>
@interface NSDateFormatter (Locale)
- (id)initWithSafeLocale;
@end
Tập tin loại 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
Mật mã:
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];
Kết quả:
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)
Điện thoại [làm cho iPod Touch] được đặt thành Vương quốc Anh, với công tắc 12/24 được đặt thành 12. Có sự khác biệt rõ ràng trong hai kết quả và tôi đánh giá phiên bản danh mục là sai. Lưu ý rằng nhật ký trong phiên bản danh mục IS đang được thực thi (và các điểm dừng được đặt trong mã được nhấn), do đó, đây không chỉ là trường hợp mã không được sử dụng.
Cập nhật tiền thưởng:
Vì tôi chưa nhận được bất kỳ câu trả lời thích hợp nào nên tôi sẽ gia hạn thời hạn tiền thưởng thêm một hoặc hai ngày nữa.
Tiền thưởng kết thúc sau 21 giờ - nó sẽ đến với bất cứ ai nỗ lực nhất để giúp đỡ, ngay cả khi câu trả lời không thực sự hữu ích trong trường hợp của tôi.
Một quan sát tò mò
Sửa đổi việc thực hiện danh mục một chút:
#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
Về cơ bản chỉ cần thay đổi tên của biến cục bộ tĩnh (trong trường hợp có một số xung đột với khai báo tĩnh trong lớp con) và thêm NSLog bổ sung. Nhưng hãy nhìn những gì NSLog in:
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
Như bạn có thể thấy, setLocale đơn giản là không. Vị trí của trình định dạng vẫn là en_GB. Dường như có một cái gì đó "lạ" về một phương thức init trong một thể loại.
Câu trả lời cuối cùng
Xem câu trả lời được chấp nhận dưới đây.
- (NSDateFormatterBehavior)formatterBehavior
?