I am trying to implement a simple countdown timer in my test app.
I have two dates:
fromDate
- which is current time that I get by Date(), e.g. 2021-08-27 11:07:34 +0000toDate
- is a future date, e.g. 2021-11-17 01:00:00 +0000I am using DateComponents
to get back the difference in days, hours, minutes and seconds.
let components = Calendar.current.dateComponents([.day, .hour, .minute, .second],
from: fromDate,
to: toDate)
Its returning me back the values for days hours minute and second 81, 12, 52, 25
The values for day, minute and second are correct, but the hour is 1 hour less.
I suspect daylight timing has to do something with this but I cannot find anything that can help here.
Kindly help me what I am doing wrong as I have tried many things in past few days but nothing seems to work
I was able to reproduce the behaviour by using:
let from = Date(timeIntervalSince1970: 1630062455)
print(from) // 2021-08-27 11:07:35 +0000
let to = Date(timeIntervalSince1970: 1637110800)
print(to) // 2021-11-17 01:00:00 +0000
var calendar = Calendar(identifier: .gregorian)
calendar.timeZone = TimeZone(identifier: "Europe/London")!
let comp = calendar.dateComponents([.day, .hour, .minute, .second], from: from, to: to)
print(comp.day!, comp.hour!, comp.minute!, comp.second!)
The reason why this happens is because when doing dateComponents(_:from:to:)
, Calendar
takes into account its timezone. After all, without a timezone, (almost) no date components would make sense - you would not be able to tell what hour a Date
is, for example. A Date
just represents an instant in time/n seconds since the epoch.
(In the case of Calendar.current
, the timezone it uses is TimeZone.current
)
Europe/London
would go out of DST at some point between from
and to
. This means the calendar would calculate the difference in date components between:
from: 2021-08-27 12:07:35
to: 2021-11-17 01:00:00
Notice that the first time is 12:07:35, rather than 11:07:35. This is because at 2021-08-27 11:07:35 +0000
, the local date time at Europe/London
really is 2021-08-27 12:07:35
.
To get your desired output, just change the calendar's timeZone
to UTC:
var calendar = Calendar.current
calendar.timeZone = TimeZone(identifier: "UTC")!
let comp = calendar.dateComponents([.day, .hour, .minute, .second], from: from, to: to)