Zin Win Htet
Zin Win Htet

Reputation: 2585

How to convert Server UTC Time to local time in Swift 4?

I've tried some similar questions and answers but still not working. I'm trying to convert 2019-09-30T09:10:32.537244Z

func serverToLocal(date:String) -> Date? {
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "yyyy-MM-ddTHH:mm:ss.SSSSSSZ"
    dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
    let localDate = dateFormatter.date(from: date)

    return localDate
}

Above method always return nil. What's wrong with my date format?

enter image description here

Upvotes: 0

Views: 291

Answers (1)

Rob
Rob

Reputation: 438437

Obviously, the key issue is the absence of the quotes around the T.

But you probably don’t want to instantiate a new date formatter every time you call this routine (because this is a notoriously computationally expensive process). So you should save your date formatter as a property. This way you don’t need to instantiate a new formatter for every string you want to convert to a Date. Likewise this formatter can be used to convert dates back to strings in the format of 2019-09-30T09:10:32.537244Z.

As such, contrary to advice provided elsewhere, I would suggest setting the timeZone of the formatter. It’s not needed when converting from strings to dates (because the date string contains the time zone qualifier), but when going back from dates to strings, you really do need the date formatter to specify the time zone, or else the string representation of a date will be in the device’s local timezone. This way, your formatter still works for both converting strings to dates, as well as back to strings.

Likewise, I’d suggest replacing the Z with either ZZZZZ or just X. Again, this is only critical if the date formatter is also being used to convert dates back to strings (otherwise, the resulting string will have +0000 rather than Z in it). Bottom line, I find using X/ZZZZZ means that I just never have to worry about it, it works when the formatter is converting 2019-09-30T09:10:32.537244Z to a Date object, or vice versa.

Thus:

let iso8601DateFormatter: DateFormatter = {
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSX"
    formatter.timeZone = TimeZone(secondsFromGMT: 0)
    formatter.locale = Locale(identifier: "en_US_POSIX")
    return formatter
}()

func serverToLocal(string: String) -> Date? {
    return iso8601DateFormatter.date(from: string)
}

func localToServer(date: Date) -> String {
    return iso8601DateFormatter.string(from: date)
}

By the way, you talk about “server” date strings. Are you exchanging data via JSON? If you are parsing strings in JSON with JSONEncoder and JSONDecoder, you might use your formatter in the encoder's dateEncodingStrategy or the decoder's dateDecodingStrategy. That way, your underlying model objects can just be Date properties, and the JSON encoder/decoder will take care of converting the date strings in the JSON to Date objects (and back). And then you don’t need these serverToLocal and localToServer methods at all.


FWIW, for more information about quoting the T, setting the locale, etc., please see Apple’s Technical Q&A 1480. It’s old doc and is focused on Objective-C, but it talks about the concepts outlined here.

Upvotes: 3

Related Questions