我給這個修復爲我公司的企業應用程序。
它應該使用已知的格式字符串(例如我們用來解析日期從我們的sqlite數據庫)日期格式化程序修復此問題。
但是,它不會修復:
- NSDateFormatters有isLenient設置爲true。
- NSDateFormatters使用樣式而不是格式字符串進行分析。
它似乎不會在iOS 5或5.1上造成負面影響。我還沒有測試過任何東西。但是,我搞砸了NSDateFormatter的內部,所以這可能無法通過App Store提交過程。但是,如果您在Enterprise程序下編寫程序(或者只是使用臨時部署),這應該不成問題。此外,如果您有任何問題,它會盡力避開,但不保證您不會遇到任何問題。
我想強調這是一個臨時解決方案。我沒有在所有可能的情況下對此進行測試,因此您應該自行承擔風險。
我創建了以下類別:
NSDateFormatter + HotFix.h
#import <Foundation/Foundation.h>
@interface NSDateFormatter (HotFix)
- (NSDate*)dateFromString:(NSString *)string;
@end
NSDateFormatter + HotFix.m
#import "NSDateFormatter+HotFix.h"
#import <objc/runtime.h>
@implementation NSDateFormatter (HotFix)
- (NSDate*)dateFromString:(NSString *)string
{
if (!string) return nil;
//HACK: Use the original implementation
void* baseFormatter = nil;
object_getInstanceVariable(self, "_formatter", &baseFormatter);
if (!baseFormatter) return nil;
//Use the underlying CFDateFormatter to parse the string
CFDateRef rawDate = CFDateFormatterCreateDateFromString(kCFAllocatorDefault, (CFDateFormatterRef)baseFormatter, (CFStringRef)string, NULL);
NSDate* source = (NSDate*)rawDate;
//We do not support lenient parsing of dates (or styles), period.
if (source && !self.isLenient && self.dateStyle == NSDateFormatterNoStyle && self.timeStyle == NSDateFormatterNoStyle)
{
//If it worked, then find out if the format string included a year (any cluster of 1 to 5 y characters)
NSString* format = [self dateFormat];
NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:@"y{1,5}" options:NSRegularExpressionCaseInsensitive error:NULL];
NSArray* matches = [regex matchesInString:format options:0 range:NSMakeRange(0, [format length])];
if ([matches count] > 0)
{
for (NSTextCheckingResult* result in matches)
{
//Check for the y grouping being contained within quotes. If so, ignore it
if (result.range.location > 0 && result.range.location + result.range.length < [format length] - 1)
{
if ([format characterAtIndex:result.range.location - 1] == '\'' &&
[format characterAtIndex:result.range.location + result.range.length + 1] == '\'') continue;
}
NSString* possibleYearString = [string substringWithRange:result.range];
NSInteger possibleYear = [possibleYearString integerValue];
if (possibleYear > 3500)
{
NSCalendar* calendar = [NSCalendar currentCalendar];
NSDateComponents* dateComp = [calendar components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit fromDate:source];
dateComp.year = possibleYear;
return [calendar dateFromComponents:dateComp];
}
}
}
}
return [source autorelease];
}
@end
它將取代NSDateFormatter的現有dateFromString方法。它的工作原理是試圖正常解析字符串,然後檢查formatString是否在其中包含一組年份格式化字符。如果確實如此,它會手動拉出年份並檢查它是否大於3500.最後,如果是這種情況,它將重寫輸出以具有正確解析的年份。
只需將其包含在您的項目中即可生效。您不需要將頭文件導入到使用NSDateFormatter的每個文件中,只需將編譯的.m文件修改該類即可。如果您有任何其他類別更改了dateFromString:那麼無法定義此類的效果。
我希望這會有所幫助。
關於iOS中日期格式化程序可能存在的錯誤,還有其他的報告 - 這似乎是一個錯誤。格式化程序似乎只能工作到未來1500年(3512) – rdelmar
哦,但具有不同的格式,如MM-dd-yyyy,它不是1500年的差距。 – dianz
我不明白那個評論,它與格式沒有任何關係,你投入什麼年份 - 當然是9999年,距離現在還有1500多年。如果您嘗試3512,您會看到這是有效的,而3513不會。 – rdelmar