With daylight savings time being a few days old now for 2019 I thought I would put together a small tutorial on how to convert dates by timezone in Swift. There are two approaches that I generally use when converting dates, the first is to use a Foundation's DateFormatter, and the second is to perform an Epoch calculation based upon your current timezone offset. The advantage of using the DateFormatter approach is that dates can easily be displayed or evaluated with other like dates, just keep in mind that the timezone offset will be displayed at the end of the date with a + or - and then the hour offset to GMT. For example, my timezone offset is -0500 for America/Chicago at the time of writing this tutorial. This means I am minus 5 hours from GMT. The DateFormatter approach is also inline with how you will see most code written out in the macOS / iOS ecosystem, so there is consistency there in using this approach. The advantage of using the Epoch calculation approach is for performing a lot of date calculations that are all at 0-GMT, or zero GMT. An example of this might be dates coming in from the server. To avoid timezone confusion dates from the server are often set to 0-GMT and can be computed this way against other Epoch dates in your program. Once the data has been computed it can be converted to local datetimes for display purposes. Just remember, that unlike the DateFormatter approach, Epoch calculation dates are computed at +0000, or zero GMT. More on this in a bit, let's dive into the two approaches with some code!
Standard Approach, using a DateFormatter() 🗓
As mentioned, the DateFormatter approach set's up the timezone, set's up the string format for the date, and then uses the formatter to provide the string from Foundation's date object! Looking at this a bit more in-depth, notice that the timeZone on the formatter is set to the .current timeZone. This will be set to .current by default, but it is important to note in case you need to set anything other that the current timeZone that you exist in. Also notice that the date format being set has the 'T' and Z characters in it. This tells the DateFormatter to include timeZone offset in hours. So, in the case of this post, the Z will represent -0500 at the end of the date format.
var currentDate = Date() // 1) Create a DateFormatter() object. let format = DateFormatter() // 2) Set the current timezone to .current, or America/Chicago. format.timeZone = .current // 3) Set the format of the altered date. format.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ" // 4) Set the current date, altered by timezone. let dateString = format.string(from: currentDate)
Alternative Approach using Epoch Calculation. 📅
The Epoch calculation approach subtracts the total timezone offset in seconds from the Date() object given by Foundation. This calculation will result in an Epoch date that can be converted to a Date object using the timeIntervalSince1970 API. The key difference between the DateFormatter version and the Epoch calculation is that the Epoch calculation provides the date format as +0000 instead of -0500. Which means nothing for display purposes, but for evaluation purposes, it's a key difference because this means you local date is at 0-GMT.
var currentDate = Date() // 1) Get the current TimeZone's seconds from GMT. Since I am in Chicago this will be: 60*60*5 (18000) let timezoneOffset = TimeZone.current.secondsFromGMT() // 2) Get the current date (GMT) in seconds since 1970. Epoch datetime. let epochDate = currentDate.timeIntervalSince1970 // 3) Perform a calculation with timezoneOffset + epochDate to get the total seconds for the // local date since 1970. // This may look a bit strange, but since timezoneOffset is given as -18000.0, adding epochDate and timezoneOffset // calculates correctly. let timezoneEpochOffset = (epochDate + Double(timezoneOffset)) // 4) Finally, create a date using the seconds offset since 1970 for the local date. let timeZoneOffsetDate = Date(timeIntervalSince1970: timezoneEpochOffset)
In Summary ⌛️
I hoped you have learned more about performing date calculations in your application using Swift. If you are new to this topic I would absolutely use the DateFormatter approach first and then try out the Epoch calculation approach, only if needed. Just remember that when dates are calculated, it is crucial to always pay attention to the +0000 or -0500 at the end of the date. This will tell you the timeZone offset and let you know why you are seeing something you may not be expecting when you compare or evaluate two dates. I hope you enjoyed reading this, please leave a comment if you have any questions, comments, or concerns.