为什么在 UTC 时区中比较两个 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];

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

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

@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 的日历进行比较。

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

最新更新