为什么在 UTC 时区比较两个 NSDate 总是失败?
Why comparing two NSDate in UTC timezone always fails?
我正在尝试测试我的一种方法是否可以正确比较两次。它工作正常,除非我按如下方式向我的组件添加时区:
_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];
这些日期是同一天,它必须 return 相同但它 return 是不同的日子?!
您没有设置日历的时区,因此它使用的是设备的时区设置,这可能不是 UTC。这两个 NSDate
值落在许多时区的不同日历日。
这很令人困惑,而且没有很好的记录。
@RobMayoff 告诉你出了什么问题,但还需要进一步解释。
这是我对其工作原理的理解。您创建 NSDateComponents
并给他们一个时区。然后将它们转换为 NSDates,它会丢弃时区信息并将这些日期表示为与 iOS 纪元时间的偏移量,始终采用 UTC。 (NSDate
物体没有时区 它们代表地球上任何地方的瞬间。)
最后,您要求一个日历对象比较这两个日期。日历对象在进行比较之前将提供的日期转换为其时区。如果这 2 个日期落在日历当前时区的不同日期,您将得到不相等的天数。
解决方法是创建一个日历并将其时区设置为 UTC,然后再进行比较。
所以只需在您发布的代码中添加第二行:
_calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
_calendar.timeZone = [NSTimeZone timeZoneWithName:@"UTC"]; //This is the fix
编辑:
正如 rmaddy 在他的评论中指出的那样,不要求您比较 UTC 日期。您只需要确保创建日期并使用相同时区比较它们。由于您使用时区为 UTC 的 NSDateComponents 创建输入日期,因此您需要将它们与也设置为 UTC 的日历进行比较。
我正在尝试测试我的一种方法是否可以正确比较两次。它工作正常,除非我按如下方式向我的组件添加时区:
_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];
这些日期是同一天,它必须 return 相同但它 return 是不同的日子?!
您没有设置日历的时区,因此它使用的是设备的时区设置,这可能不是 UTC。这两个 NSDate
值落在许多时区的不同日历日。
这很令人困惑,而且没有很好的记录。
@RobMayoff 告诉你出了什么问题,但还需要进一步解释。
这是我对其工作原理的理解。您创建 NSDateComponents
并给他们一个时区。然后将它们转换为 NSDates,它会丢弃时区信息并将这些日期表示为与 iOS 纪元时间的偏移量,始终采用 UTC。 (NSDate
物体没有时区 它们代表地球上任何地方的瞬间。)
最后,您要求一个日历对象比较这两个日期。日历对象在进行比较之前将提供的日期转换为其时区。如果这 2 个日期落在日历当前时区的不同日期,您将得到不相等的天数。
解决方法是创建一个日历并将其时区设置为 UTC,然后再进行比较。
所以只需在您发布的代码中添加第二行:
_calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
_calendar.timeZone = [NSTimeZone timeZoneWithName:@"UTC"]; //This is the fix
编辑:
正如 rmaddy 在他的评论中指出的那样,不要求您比较 UTC 日期。您只需要确保创建日期并使用相同时区比较它们。由于您使用时区为 UTC 的 NSDateComponents 创建输入日期,因此您需要将它们与也设置为 UTC 的日历进行比较。