为什么比较UTC时区中的两个NSDate总是失败?

时间:2016-04-27 01:38:15

标签: ios objective-c nsdate

我试图测试我的一种方法可以正确地比较两次。它工作正常,除非我在我的组件中添加一个时区,如下所示:

_calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];

NSDateComponents *components = [[NSDateComponents alloc] init];


components.second = 31;
components.minute = 21;
components.hour = 5;
components.day = 30;
components.month = 3;
components.year = 2016;
components.timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
_mar30_2016Morning = [_calendar  dateFromComponents:components];


components.second = 01;
components.minute = 00;
components.hour = 22;
components.day = 30;
components.month = 3;
components.year = 2016;
components.timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
_mar30_2016Evening = [_calendar  dateFromComponents:components];



//Test two dates are equal
-(void) testCompareWithoutTimeTo
{
    XCTAssertEqual([_mar30_2016Morning compareWithoutTimeTo:_mar30_2016Evening],NSOrderedSame);
}

首先:

-(NSComparisonResult) compareWithoutTimeTo:(NSDate *) otherDate {
    NSDate *this = [self copy];
    NSDate *that = [otherDate copy];
    return [[NSCalendar currentCalendar] compareDate:this toDate:that toUnitGranularity:NSCalendarUnitDay];;
}

第二种方式:

NSCalendar* calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
[[NSCalendar currentCalendar] rangeOfUnit:NSCalendarUnitDay startDate:&this interval:NULL forDate:this];
[[NSCalendar currentCalendar] rangeOfUnit:NSCalendarUnitDay startDate:&that interval:NULL forDate:that];
NSComparisonResult result = [this compare:that];

这些日期是在同一天,它必须返回相同但它返回它是不同的日子?!

2 个答案:

答案 0 :(得分:3)

这很令人困惑,而且没有很好的记录。

@RobMayoff告诉你出了什么问题,但还有进一步的解释。

以下是我对其工作原理的理解。您创建NSDateComponents并为其指定时区。然后将它们转换为NSDates,它会丢弃时区信息,并将这些日期表示为iOS纪元时间的偏移量,总是以UTC格式表示。 (NSDate个对象没有时区它们代表地球上任何时间的瞬间。)

最后,您要求日历对象比较2个日期。日历对象在进行比较之前将提供的日期转换为其时区。如果2个日期落在日历当前时区的不同日期,那么您将获得不平等的日期。

解决方案是在进行比较之前创建日历并将其时区设置为UTC。

只需在您发布的代码中添加第二行:

_calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
_calendar.timeZone = [NSTimeZone timeZoneWithName:@"UTC"];  //This is the fix

编辑:

正如rmaddy在评论中指出的那样,没有要求你比较UTC中的日期。您只需要确保创建日期并使用相同的时区进行比较。由于您使用时区为UTC的NSDateComponents创建输入日期,因此需要将它们与也设置为UTC的日历进行比较。

答案 1 :(得分:1)

您没有设置日历的时区,因此它使用的是设备的时区设置,可能不是UTC。这两个NSDate值落在许多时区的不同日历日。