Ios NSDate在与NSString转换后不相等
我正在尝试在JSON中存储和检索日期。从相同字符串创建的NSDATE失败Ios NSDate在与NSString转换后不相等,ios,objective-c,Ios,Objective C,我正在尝试在JSON中存储和检索日期。从相同字符串创建的NSDATE失败isEqualToDate:。这当然是由于浮点精度问题,但我不确定如何解决它 给dateFromString:给定两个相同的输入字符串,得到的NSDate对象应该相等: NSDate *date1 = [NSDate date]; NSString *string1 = [dateFormatter stringFromDate:date1]; NSDate *dateA = [dateFormatter dateFromS
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]);
…但是,实际上,由于浮点精度问题引入了随机积垢,结果日期对象幸运地相等(而且很少相等):
(lldb) p [dateA timeIntervalSinceReferenceDate]
(NSTimeInterval) $4 = 560455653.79073596
(lldb) p [dateB timeIntervalSinceReferenceDate]
(NSTimeInterval) $5 = 560455653.79099989
那么,有人遇到这种情况并解决了它吗?我想到的唯一选择是编写自己的isEquals:
,但这并不理想
编辑: 具体来说,我要寻找的是一种将日期的字符串表示形式转换回日期对象的方法,对于相同的输入字符串,该对象将被视为相等 <代码>(Netrase<代码> >存储在浮点数中的内部状态是不相关的,因为在给定相同输入时,基础应该提供一种机制来实现输出日期的奇偶性(即相同的字符串应该产生相等的对象)。两个基金会都提供了这一点,我很怀念(希望这样的社区知道一些关于基金会的事情我不知道),或者基金会是BGGY(在这种情况下),我正在寻找这样一个社区,我还没有考虑过这个问题。 编辑2: 对不起,我的问题,正如最初问的,是胡说八道。为了简化这篇文章的问题,我无意中对两个不可能相等的数字进行了比较 原版胡说八道帖子,面向子孙: 我正在尝试在JSON中存储和检索日期。存储到JSON中的
NSDate
I在从存储字符串重新创建的NSDate
对象上失败isEqualToDate:
。这当然是由于浮点精度问题,但我不确定如何解决它。
具体而言:
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
,我们看到了区别:
(lldb) p [date1 timeIntervalSinceReferenceDate]
560363055.21521103
(lldb) p [date2 timeIntervalSinceReferenceDate]
560363055.21499991
(注意第千位)
NSDate
的isEqual:
(和variant)几乎肯定是在比较
实例的时间偏移,因此失败
我已尝试为存储的字符串添加更高的精度(即。
.SSSSSS
)但这似乎没有影响
那么,有人遇到这种情况并解决了它吗?我唯一的选择
我的想法是写我自己的isEquals:
,但这并不理想
tl;dr-您正在尝试将纳秒与毫秒进行比较。这些结果将不一样 使用
[NSDate date]创建NSDate
时代码>得到的值包括小数秒,精度为微秒,甚至纳秒
将日期转换为格式为yyyy-MM-dd'T'HH:MM:ss.SSS
的字符串时,创建的字符串正好有3位小数(毫秒)。然后,当您将该字符串转换回一个NSDate
时,您将得到一个浮点数,该浮点数尽可能接近这些毫秒
因此,原始日期的精度为微秒或纳秒,而第二个日期的精度仅为毫秒。当然,由于精度不同,这两个日期会有所不同。这与浮点数无关。即使您有完美的浮点数,您也将100.123456789与100.123进行比较。他们不是同一个数字
您声明您尝试使用SSSSSS
而不是SSS
,但是NSDateFormatter
不支持超过三个小数位数的内容,因此SSS
之外的内容都是白费力气
有了这个解释,你有什么办法来比较你的两次约会
一种是将两个日期仅与小数点后三位进行比较。下面是一个有用的小NSDate
category方法,它可以:
@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
与:
您将得到正确的结果。因为底层存储的NSDates是一个浮点数,我认为没有任何方法可以在不损失精度的情况下使用NSDateFormatter。如果希望能够使用isEqualToDate:可以尝试使用timeIntervalSinceReferenceDate(或timeIntervalSince1970)将日期存储为浮动。但问题是isEqualToDate:只能告诉你,如果两个日期足够接近,任何差值都小于浮点数所表示的差值,这真的是你想要将其视为相等的,还是如果两个日期相距小于一秒或一毫秒,你更愿意将其视为相等的,我可以想象,在某些情况下,您确实希望使用isEqualToDate:但是,您应该使用timeIntervalSinceReferenceDate而不是NSDateFormatter,这是一种解析和生成人类可读字符串的方法,而不是以有损格式存储数据。出于平等考虑,比较无效,从系统时钟创建的NSDate
,以及以这种方式从字符串重构的NSDate
。这就像问“为什么一个浮点数不保存为字符串,保留到小数点后3位,并转换回与原始浮点数相等的浮点数?”你不应该对重新组合的日期和时钟派生的日期执行相等性测试。它本质上就像任何其他基于浮点的比较一样。您的方法无法按预期工作。两个浮点值之间的间距可以小于1/1000,但在不同方向上仍然是圆的。使用fabsf(a-b)<0.001
。您能否引用您对NSDateFormatter
不尊重额外精度的评论?我看到苹果的文档引用了这个文档,它为s
格式说明符的数量提供了1-n
(意味着没有限制)。是的,我知道我可以实现我自己的isEqua
XCTAssertTrue([date1 isEqualToDate:date2]);
XCTAssertTrue([date1 isEqualToDateMilliseconds:date2]);