我正在尝试存储和检索JSON的日期.从相同的字符串创建的NSDates失败isEqualToDate:
.这当然是由于浮点精度问题,但我不知道如何解决它.
给定两个相同的输入字符串dateFromString:
,结果NSDate
对象应该相等:
NSDate *date1 = [NSDate date];
NSString *string1 = [dateFormatter stringFromDate:date1];
NSDate *dateA = [dateFormatter dateFromString:string1];
NSDate *dateB = [dateFormatter dateFromString:string1];
XCTAssertTrue([dateA isEqualToDate:dateB]);
Run Code Online (Sandbox Code Playgroud)
...但是,实际上生成的日期对象很幸运是相同的(很少是),因为由于浮点精度问题引入了随机残差:
(lldb) p [dateA timeIntervalSinceReferenceDate]
(NSTimeInterval) $4 = 560455653.79073596
(lldb) p [dateB timeIntervalSinceReferenceDate]
(NSTimeInterval) $5 = 560455653.79099989
Run Code Online (Sandbox Code Playgroud)
那么,任何人都会遇到这种情况并解决它吗?我想到的唯一选择就是自己编写,isEquals:
但这并不理想.
编辑:
具体来说,我正在寻找的是一种将日期的字符串表示转换回日期对象的方法,对于相同的输入字符串,该日期对象将被视为相等.
NSDate
将其内部状态存储在浮点数中的(明显)事实是无关紧要的,因为基金会应该提供一种机制来在给定相同输入时实现输出日期的奇偶校验(即相同的字符串应该产生相等的对象).基金会提供这个并且我错过了它(并且希望SO社区知道关于基金会我不知道的事情),或者基金会是错误的(在这种情况下)并且我正在寻找SO社区的解决方法我没有已经考虑过了.
编辑2:
道歉,我的问题,最初的问题,是无稽之谈.为了简化这篇文章的问题,我引入了两个不可能相等的数字之间的意外比较.
原始废话帖子,为子孙后代:
我正在尝试存储和检索JSON的日期.在
NSDate
我店为JSON失败isEqualToDate:
上NSDate
我从存储的字符串重新创建对象.这当然是由于浮点精度问题,但我不知道如何解决它.特别:Run Code Online (Sandbox Code Playgroud)NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; dateFormatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0]; dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; dateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; NSDate *date1 = [NSDate date]; NSString *string1 = [dateFormatter stringFromDate:date1]; NSDate *date2 = [dateFormatter dateFromString:string1]; NSString *string2 = [dateFormatter stringFromDate:date2]; // This test passes XCTAssertTrue([string1 isEqualToString:string2]); // This test fails XCTAssertTrue([date1 isEqualToDate:date2]); // This test fails XCTAssertTrue([date1 isEqual:date2]);
查看
date1
和date2
调试器中我们看到了差异:Run Code Online (Sandbox Code Playgroud)(lldb) p [date1 timeIntervalSinceReferenceDate] 560363055.21521103 (lldb) p [date2 timeIntervalSinceReferenceDate] 560363055.21499991
(注意千分之一的地方)
NSDate
的isEqual:
(和变体)几乎可以肯定地比较实例的时间偏移,从而失败.我已经尝试为存储的字符串添加更多精度(即
.SSSSSS
),但这似乎没有影响.那么,任何人都会遇到这种情况并解决它吗?我想到的唯一选择就是自己编写,
isEquals:
但这并不理想.
tl; dr - 你试图比较纳秒到毫秒.那些结果将不一样.
当你创建一个NSDate
with时,[NSDate date];
你得到一个包含小数秒的值,精确到微秒,甚至可能是纳秒.
将日期转换为具有格式的字符串时,yyyy-MM-dd'T'HH:mm:ss.SSS
您将创建一个精确到3位小数(毫秒)的字符串.然后,当您将该字符串转换回a时NSDate
,您会得到一个浮点数,该数字近似于可以表示的最佳毫秒数.
因此,原始日期的精度为微秒或纳秒,第二个日期仅为毫秒.当然,由于精度不同,两个日期会有所不同.这与浮点数无关.即使您有完美的浮点数,您也要将100.123456789与100.123进行比较.它们的数量不一样.
你说,你尝试使用SSSSSS
替代SSS
,但NSDateFormatter
这样任何超越不接受任何超过三个小数位SSS
是无用功.
有了这个解释,你有什么解决方案来比较你的两个日期?
一种是将两个日期仅比较三个小数位.这是一个有用的小NSDate
类别方法,它可以做到这一点:
@interface NSDate (extra)
- (BOOL)isEqualToDateMilliseconds:(NSDate *)otherDate;
@end
@implementation NSDate (extra)
- (BOOL)isEqualToDateMilliseconds:(NSDate *)otherDate {
TimeInterval secs1 = [self timeIntervalSinceReferenceDate];
TimeInterval secs2 = [self timeIntervalSinceReferenceDate];
return abs(secs1 - secs2) < 0.001;
}
@end
Run Code Online (Sandbox Code Playgroud)
如果您自己的代码,请使用更好的类别名称.
现在你可以替换:
XCTAssertTrue([date1 isEqualToDate:date2]);
Run Code Online (Sandbox Code Playgroud)
有:
XCTAssertTrue([date1 isEqualToDateMilliseconds:date2]);
Run Code Online (Sandbox Code Playgroud)
你会得到正确的结果.
归档时间: |
|
查看次数: |
118 次 |
最近记录: |