Swift 日历日期通过将小时设置为 0 更改日期

Swift Calendar Date By Setting Hour To 0 Changes Day

如果我运行下面的代码:

let date = Date()
let midnight = Calendar.current.date(bySetting: .hour, value: 0, of: date)!
let difference = Int64(midnight.timeIntervalSince(date))
print(String(difference))

差异是大约 13 小时的正值(因为现在当地时间大约是上午 11 点)。但是,我希望差异为负 11 小时;因为我将 .hour 值设置为 0 我希望时间会倒退,而不是前进。

我预计明天必须使用此代码找到午夜:

let midnight = Calendar.current.date(bySetting: .hour, value: 0, of:
   Calendar.current.date(byAdding: .day, value: 1, to: date)!)!

但是这给出了 +37 小时而不是 +13。

现在的行为其实就是我想要的行为(我想知道到明天午夜的时间)。但是,我想了解为什么会发生这种情况,特别是我想确保这种寻找明天午夜的方法无论时区如何都能奏效。谢谢!

编辑:请注意,我只关心午夜之前的时间,这就是为什么我在找到午夜时不更改分钟或秒值的原因。

date(bySetting:value:of) 做出了一个最佳猜测,即 "implementation-defined" 根据新参数创建一个新的 Date。通过将 hour 设置为 0 - 有时这会在同一日历日创建一个 Date 并相应地设置 hour ,有时新的 Date 会是明天。听起来这不会为您提供所需的可靠性,但希望它能回答您的问题。

文档更深入:

https://developer.apple.com/documentation/foundation/calendar/2292915-date

我认为这是预期的,正如 documentation

中所说

The algorithm will try to produce a result which is in the next-larger component to the one given (there’s a table of this mapping at the top of this document). So for the “set to Thursday” example, find the Thursday in the Week in which the given date resides (which could be a forwards or backwards move, and not necessarily the nearest Thursday). For more control over the exact behavior, use nextDate(after:matching:matchingPolicy:behavior:direction:).

使用 nextDate(after date: Date, matching components: DateComponents, matchingPolicy: Calendar.MatchingPolicy, repeatedTimePolicy: Calendar.RepeatedTimePolicy = default, direction: Calendar.SearchDirection = default) -> Date? 会产生您所期望的正确结果。

示例在这里,

let calendar = Calendar.current
var hourComponent = DateComponents()
hourComponent.hour = 0

let midnightSameDay = calendar.nextDate(after: date,
                                        matching: hourComponent,
                                        matchingPolicy: .nextTime,
                                        direction: .backward)
print(mightnightSameDay) // 2018-04-19 00:00:00 +0000

let midnightNextDay = calendar.nextDate(after: date,
                                        matching: hourComponent,
                                        matchingPolicy: .nextTime,
                                        direction: .forward)
print(mightnightNextDay) // 2018-04-20 00:00:00 +0000

您还可以使用另一种方法,它使用搜索方向和匹配策略,

let midnightSameDay = calendar.date(bySettingHour: 0,
                                    minute: 0,
                                    second: 0,
                                    of: date,
                                    direction: .backward)