【问题标题】:Calendar: get date components, weird case日历:获取日期组件,奇怪的情况
【发布时间】:2018-04-23 15:49:31
【问题描述】:

我正试图找出为什么这段代码如此奇怪。您可以在下面找到详细信息:

let nowDate = Date()
let threeDayBeforeNowDate_t1 = Date(timeIntervalSinceNow: -60 * 60 * 24 * 3)
let oneDayAfterNowDate = Date(timeIntervalSinceNow: 60 * 60 * 24 * 1)
let threeDayBeforeNowDate_t2 = Date(timeIntervalSinceNow: -60 * 60 * 24 * 3)
let threeDayBeforeNowDate = nowDate.addingTimeInterval(-60 * 60 * 24 * 3)

let diff_1 = threeDayBeforeNowDate_t1.timeIntervalSince(nowDate) - threeDayBeforeNowDate.timeIntervalSince(nowDate) // about 0.009357
let diff_2 = threeDayBeforeNowDate_t2.timeIntervalSince(nowDate) - threeDayBeforeNowDate.timeIntervalSince(nowDate) // about 0.010063
let diff_3 = threeDayBeforeNowDate_t2.timeIntervalSince(nowDate) - threeDayBeforeNowDate_t1.timeIntervalSince(nowDate) // about 0.000416

let calendar = Calendar.current
calendar.dateComponents(Set([Calendar.Component.day]), from: threeDayBeforeNowDate, to: oneDayAfterNowDate) // result = "day: 4 isLeapMonth: false"
calendar.dateComponents(Set([Calendar.Component.day]), from: threeDayBeforeNowDate_t1, to: oneDayAfterNowDate) // day: 4 isLeapMonth: false
calendar.dateComponents(Set([Calendar.Component.day]), from: threeDayBeforeNowDate_t2, to: oneDayAfterNowDate) // day: 3 isLeapMonth: false 

我不明白,为什么我得到的结果如此不同,而日期 (threeDayBeforeNow...) 相差不到一秒。

【问题讨论】:

  • 从不使用60 * 60 * 24作为一天的持续时间。想想夏令时转换,一天可以有 23、24 或 25 小时。使用正确的日历方法。
  • 马丁,我明白了,这只是为了测试。
  • “我得到了如此不同的结果,而日期相差不到一秒” – 在最后一种情况下,日期相差(一点点)小于 b> 超过 4 天,因此结果为 3。如果您打印所有日期组件,那么您会更清楚地看到它。
  • 我打印了组件。所以,得到:imgur.com/a/bibMZ

标签: ios swift date calendar foundation


【解决方案1】:

问题是在创建nowDate 和您使用Date(timeIntervalSinceNow:)initializer 的其他变量之间需要一段时间。

Date()Date(timeIntervalSinceNow:) 都使用系统时间来获取执行到达该特定变量时的当前时间。无论多小,对系统时间的不同调用之间总会有一些小的延迟,因此即使您在两行连续代码中使用Date() 创建两个Date 对象,它们也不会代表完全相同的点及时。

在 Playground 中运行,以下代码显示了这种行为:

let now1 = Date()
let now2 = Date()
now1.timeIntervalSince(now2) //-0.0002049803733825684

如果您想要一致的 Date 对象,请创建一个变量,在其中存储创建日期,使用 Date() 就像您目前对 nowDate 所做的那样,然后使用相同的变量来创建您的另一个Date 对象使用 nowDate.addingTimeInterval(),就像您目前对 threeDayBeforeNowDate 所做的那样。

【讨论】:

  • 我知道这一点,但如果日期没有显着差异,所以我希望日差相同。
  • 嗯,这是一个边缘情况,但正是这种微小的差异使得 daycomponents 为两者返回不同的结果。正如 @MartinR 在 cmets 中建议的那样,不要使用 timeIntervalSince 手动计算日期来计算日期。使用正确的日历方法。
  • 如果是边缘情况,会在一个小时内重复吗?
【解决方案2】:

作为Dávid already explained,问题是各种日期 在不同的时间点计算,因此差异不是 正好4天。特别是之间的区别 threeDayBeforeNowDate_t2oneDayAfterNowDate 小于 4 天,这就是为什么 .day 的差异部分是 3

这是一个演示问题的简化示例(在 Playground 中):

let nowDate = Date()
let date1 = Date(timeIntervalSinceNow: -60 * 60 * 24 * 4)
let date2 = nowDate.addingTimeInterval(-60 * 60 * 24 * 4)

let calendar = Calendar.current
calendar.dateComponents([.day, .hour, .minute, .second, .nanosecond], from: date1, to: nowDate)
// day: 3 hour: 23 minute: 59 second: 59 nanosecond: 994143066 isLeapMonth: false

calendar.dateComponents([.day, .hour, .minute, .second, .nanosecond], from: date2, to: nowDate)
// day: 4 hour: 0 minute: 0 second: 0 nanosecond: 0 isLeapMonth: false

date2nowDate 相差 4 天,但 date1nowDate 相差一点点小于 4 天(假设没有 此时间跨度的夏令时转换)。

【讨论】:

  • @G.Veronika:threeDayBeforeNowDate_t1 和 oneDayAfterNowDate 之间的差异大于 4天。
  • 好的,我明白了。这是代码中的一个错误。谢谢!我以为是'let oneDayAfterNowDate = nowDate.addingTimeInterval(60 * 60 * 24 * 1)',但现在我明白了...谢谢:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多