为什么NSDateFormatter在巴西时区19/10/2014返回null?

gui*_*ini 12 objective-c nsdateformatter ios

NSString *dateString = @"19/10/2014";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"dd/MM/yyyy"];
NSDate *myDate = [dateFormatter dateFromString:dateString];
Run Code Online (Sandbox Code Playgroud)

为什么myDate这个特定日期为空(2014年10月19日)?

如果我更改dateString@"25/10/2014",请dateFormatter正确返回日期...我的代码有什么问题?

*当我的iPhone时区为"Brasilia,Brasil"时,此代码返回null.例如,当我的时区是"华盛顿特区,EUA"时,代码会返回正确的日期.

rob*_*off 23

我们可以通过将时区明确设置为"Brazil/East"来重现您的问题:

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        NSString *dateString = @"19/10/2014";
        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
        dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"Brazil/East"];
        [dateFormatter setDateFormat:@"dd/MM/yyyy"];
        NSDate *myDate = [dateFormatter dateFromString:dateString];
        NSLog(@"myDate = %@", myDate);
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这是输出:

2014-06-06 14:22:28.254 commandLine[31169:303] myDate = (null)
Run Code Online (Sandbox Code Playgroud)

由于你没有在你的时间dateString,系统假设午夜.但巴西时区不存在该日期的午夜.

巴西于2014年10月19日从BRT(夏令时区)变为BRST(非夏令时区),直接从"18/10/2014"的最后一刻跳至"19/10/2014 01" :00:00" .

由于"19/10/2014 00:00:00"不存在,NSDateFormatter退货nil.我认为这是不好的行为NSDateFormatter,但我们必须处理它. -[NSDateFormatter dateFromString:]最终调用CFDateFormatterGetAbsoluteTimeFromString,它使用udat_parseCalendar函数Unicode的国际组件(ICU)库来解析日期.

您可以通过使解析器使用正午而不是午夜作为默认时间来解决此问题.中午时区的夏令时间没有变化.让我们编写一个辅助函数,它返回给定时区中某个任意日期的正午:

static NSDate *someDateWithNoonWithTimeZone(NSTimeZone *timeZone) {
    NSDateComponents *components = [[NSDateComponents alloc] init];
    components.timeZone = timeZone;
    components.era = 1;
    components.year = 2001;
    components.month = 1;
    components.day = 1;
    components.hour = 12;
    components.minute = 0;
    components.second = 0;
    return [[NSCalendar autoupdatingCurrentCalendar] dateFromComponents:components];
}
Run Code Online (Sandbox Code Playgroud)

然后我们将日期格式化程序设置defaultDate为此中午日期:

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        NSString *dateString = @"19/10/2014";
        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
        dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"Brazil/East"];
        dateFormatter.dateFormat = @"dd/MM/yyyy";
        dateFormatter.defaultDate = someDateWithNoonWithTimeZone(dateFormatter.timeZone);
        NSDate *myDate = [dateFormatter dateFromString:dateString];
        NSLog(@"myDate = %@", myDate);
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这是输出:

2014-06-06 14:52:31.939 commandLine[31982:303] myDate = 2014-10-19 14:00:00 +0000
Run Code Online (Sandbox Code Playgroud)