当使用.backward作为方向时,Calendar.nextDate()表现得非常奇怪。 仅适用于本月的最后一天

在我的应用程序中,我需要获取前一个凌晨4点,而不是当前日期的凌晨4点。
例如:

  • 如果它是March 05, 10:00 am那么我应该期待回来: March 05, 4:00 am
  • 如果它是March 05, 02:00 am那么我应该期待回来: March 04, 4:00 am

为了实现这一点,我正在使用Calendar.nextDate 。 除了每个月的最后一天,它适用于本月的每日。

这是一个快乐路径的例子,它按预期工作:

 let components = DateComponents(hour: 4, minute: 0, second: 0) let date = Calendar.current.date(from: DateComponents(year: 2018, month: 03, day: 05, hour: 13, minute: 25, second: 0))! let result = Calendar.current.nextDate(after: date, matching: components, matchingPolicy: .nextTime, direction: .backward) 

输出:

 date = "Mar 5, 2018 at 1:25 PM" result = "Mar 5, 2018 at 4:00 AM" 

这是一个黑暗悲伤路径的例子,它没有按预期行事:

 let components = DateComponents(hour: 4, minute: 0, second: 0) let date = Calendar.current.date(from: DateComponents(year: 2018, month: 03, day: 31, hour: 13, minute: 25, second: 0))! let result = Calendar.current.nextDate(after: date, matching: components, matchingPolicy: .nextTime, direction: .backward) 

输出:

 date = "Mar 31, 2018 at 1:25 PM" result = "Mar 30, 2018 at 4:00 AM" // it should give me this instead: "Mar 31, 2018 at 4:00 AM" 

知道为什么会这样吗? 它是Apple的代码中的错误,我应该报告吗? 或者我使用这个错误?
如果它是Apple的bug,那么在此期间还有另一种方法可以实现我需要的东西吗?

更新:

在查看了一些Swift源代码之后,我注意到问题不在于Calendar.nextDate()函数。 nextDate()使用Calendar.enumerateDates() ,这就是真正的问题所在。 我找不到该function的源代码。 这是使用Calendar.enumerateDates()的相同错误:

 let components = DateComponents(hour: 4, minute: 0, second: 0) let date = Calendar.current.date(from: DateComponents(year: 2018, month: 03, day: 31, hour: 13, minute: 25, second: 0))! Calendar.current.enumerateDates(startingAfter: inputDate, matching: components, matchingPolicy: .nextTime, direction: .backward) { (date, exactMatch, stop) in let result = date // result = "Mar 30, 2018 at 4:00 AM" stop = true } 

此外,这是一个类似的问题: Swift的Calendar.enumerateDates在2月开始时给出不正确的结果

这似乎是一个应该向Apple报告的错误。 确保您包含一个可运行的测试应用程序来演示该问题。 请注意 ,此错误仅出现在iOS中。 在macOS(至少是一个macOS playground)中,代码按预期工作。

与此同时,有一个相当简单的解决方法。

将代码更改为使用.forward而不是.backward 。 这将给出下一个日期而不是上一个日期。 似乎没有任何错误朝那个方向发展。 然后使用:

 Calendar.current.date(byAdding: .day, value: -1, date: result) 

通过回去一天得到你想要的结果。