【问题标题】:IOS 6 NSDateFormatterIOS 6 NSDateFormatter
【发布时间】:2012-10-06 03:05:15
【问题描述】:

请帮我处理IOS6上的dateformatter,请看下面的代码

NSString stringDate = @"12/31/9999"; 
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init]; 
[dateFormatter setDateFormat:@"MM/dd/yyyy"]; 
NSDate *dateCheck = [dateFormatter dateFromString:stringDate]; 
NSLog(@"Date = %@", dateCheck);

输出是

Date = 1999-12-31 08:00:00 +0000

这是将字符串日期转换为日期 12/31/9999 时的输出。

从之前版本的IOS6输出是

Date = 9999-12-31 08:00:00 +0000 // Correct

【问题讨论】:

  • 还有其他关于 SO 的报告关于 iOS6 日期格式化程序中可能存在的错误——这似乎是一个错误。格式化程序似乎只能在未来 1500 年内工作 (3512)
  • 哦,但是像 MM-dd-yyyy 这样的不同格式,它不是 1500 年的差距。
  • 我不明白那个评论,它与格式无关,只是你输入的年份——当然 9999 是从现在开始的 1500 多年。如果您尝试 3512,您会发现它有效,而 3513 则无效。

标签: ios ios6 nsdateformatter


【解决方案1】:

我为我公司的企业应用程序解决了这个问题。

它应该为使用已知格式字符串的日期格式化程序解决这个问题(就像我们用来从我们的 sqlite 数据库中解析日期的那些)。

但是,它不会修复:

  1. 将 isLenient 设置为 true 的 NSDateFormatter。
  2. 使用样式而不是格式字符串进行解析的 NSDateFormatter。

它似乎不会对 iOS 5 或 5.1 造成负面影响。在那之前我没有测试过任何东西。但是,我确实有点弄乱了 NSDateFormatter 的内部,所以这可能无法通过 App Store 提交过程。但是,如果您在 Enterprise 程序下编写程序(或仅使用 ad hoc 部署),这应该不是问题。此外,如果您启用了 isLenient,它会尝试让路,但不能保证您不会遇到任何问题。

我想强调这是一个临时解决方案。我没有在所有可能的情况下都对此进行测试,因此您应该自行承担实施此操作的风险。

我创建了以下类别:

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: 的类别,则无法定义此类的效果。

我希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多