Trivial string to date conversion not working

I'm doing what I thought would be simple, converting a string representation of a date to a Date object. I get back nil after trying various things. I suspect my format is wrong but here's my code. I'm using the date in this example "2020-11-25T18:01:55Z". I've tried formats like "yyyy-MM-ddTHH:mm:ss+0000" and "yyyy-MM-dd'T'HH:mm:ss+0000", but they all return nil.

func getDateFromString(strDate: String, format: String = "yyyy-MM-ddTHH:mm:ssZ") -> Date? {
    let formatter = DateFormatter()
    formatter.dateFormat = format
    //formatter.timeZone = TimeZone(abbreviation: "UTC")
    //formatter.locale = .current
    let date = formatter.date(from: strDate)
    return date
}

Use single quotes around T: "yyyy-MM-dd'T'HH:mm:ssZ"

let formatter1 = DateFormatter()
formatter1.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"

let formatter2 = ISO8601DateFormatter()

Don't forget to set the locale, the fist one gives me sometime in the 14th century (ISO8601 uses Gregorian I believe).

Tried that one already still nil.

Could you try again? It works on my machine.

I was replying to eimantas

How do I set the locale for ISO8601DateFormatter. I'm not seeing that property.

I meant that I tried @eimantas string, too.

AFAICT, ISO8601 doesn't need locale. It always uses the Gregorian calendar, and the format string doesn't change with locale. You may still need to set the timezone, though.

You may need it for normal DateFormatter, though.

1 Like

I'm trying it but it's still nil. I've included a screenshot of the entire code hoping it may be more clear.

Right now what I don't understand is why I need both the DateFormatter and the ISO8601DateFormatter. But regardless its not working.

Hmm, I typed the entire code in iOS Playground, and it returns a date just fine. Regardless, that's about as much as I can help since I couldn't reproduce it, nor could I figure out why I couldn't.

It could be that Xcode debugger print erroneous data, but I haven't had that kind of problem for a while.

Either one should be fine. I'm just giving an alternative.

Interesting even hard coding the same string date you gave me returns a nil.

let formatter1 = DateFormatter()
formatter1.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
let formatter2 = ISO8601DateFormatter()
let date = formatter2.date(from: "2020-11-25T18:01:55Z")
return date

Other than Foundation do I need another import?

Only Foundation, you can even just do:

import Foundation

let formatter2 = ISO8601DateFormatter()
formatter2.timeZone = TimeZone(abbreviation: "UTC")
let date = formatter2.date(from: "2020-11-25T18:01:55Z")
print(date)

which prints

Optional(2020-11-25 18:01:55 +0000)

on essentially any platform I could get a hand on; Xcode 12.3 playground, iOS Playground 3.4, and even Swift Online Compiler & Interpreter - Replit. It's weird that it is nil on your end :thinking::thinking::thinking:.

I got it to work but this makes no sense to me. Note I'm on Big Sur 11.1 and XCode 12.3.
If I force unwrap it it works, otherwise it claims its null. (DateUtils is just my helper class). Do you know what the <unavailable try printing ... means?

Do you mean you get nil at call site of getDateFromString()? You don't have to force unwrap since I can see the return type is Date?. Are you sure that strDate always comes in correct format?

The live variable preview thingy doesn't always reliably print out Swift values, especially those backed by implementation magic like tagged pointers, which I suspect is the case here. If you print out the result as part of the program, it would report the correct non-nil result.

3 Likes

Yeah it's on the break point. So when I don't force unwrap its nil, but when I do it's a normal date. And strDate is having a string date and is not empty. Here's an image without the force unwrap.

image

I had a suspition about this.

1 Like

Looks similar to this bug: [SR-13882] oldValue in didSet is reported as nil by debugger · Issue #4326 · apple/llvm-project · GitHub

1 Like

Oh yes it does. Thanks for the tip.