If I run the following code:
let date = Date()
let midnight = Calendar.current.date(bySetting: .hour, value: 0, of: date)!
let difference = Int64(midnight.timeIntervalSince(date))
print(String(difference))
Difference is a positive value of about 13 hours (since the local time is about 11 AM now). However, I would expect that the difference would be negative 11 hours; since I'm setting the .hour
value to 0
I expect that time would move backward, not forward.
I would expect to have to find midnight tomorrow with this code:
let midnight = Calendar.current.date(bySetting: .hour, value: 0, of:
Calendar.current.date(byAdding: .day, value: 1, to: date)!)!
But that gives +37 hours instead of +13.
The current behavior is actually the behavior I want (I want to know the time until midnight tomorrow). But, I would like to understand why this is happening, and in particular I want to make sure that this approach of finding midnight tomorrow will work regardless of time zone. Thanks!
EDIT: Note, I only care about the hours until midnight, which is why I don't change the minute or second value when finding midnight.
I think this is expected as it says in the 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:).
Using nextDate(after date: Date, matching components: DateComponents, matchingPolicy: Calendar.MatchingPolicy, repeatedTimePolicy: Calendar.RepeatedTimePolicy = default, direction: Calendar.SearchDirection = default) -> Date?
yields correct result as you would expect.
Example is here,
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
And there is yet another method that you could use for this which uses search direction and matching policy,
let midnightSameDay = calendar.date(bySettingHour: 0,
minute: 0,
second: 0,
of: date,
direction: .backward)
date(bySetting:value:of)
makes a best guess that is "implementation-defined" towards creating a new Date
based on the new parameters. By setting the hour
to 0
- sometimes this will create a Date
on the same calendar day with the hour
set accordingly, and sometimes the new Date
will be tomorrow. It doesn't sound like that will give you the reliability that you need, but hopefully it answers your question.
The docs go further in depth:
https://developer.apple.com/documentation/foundation/calendar/2292915-date
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With