Nat
Nat

Reputation: 149

DateFormatter returning nil for valid String when decoding JSON

I'm trying to decode a date of the format 2019-11-08T01:26:45+00:00 in Swift. Not sure if this is relevant, but it's a String taken from JSON. I've tried using ISO8601DateFormatter, setting the date format manually, etc., but nothing works. (response.timestamp has the value "2019-11-12T21:37:39+00:00", taken from JSON.)

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
dateFormatter.locale = Locale.current
self.timestamp = dateFormatter.date(from: response.timestamp)

When I build and run the application and set a breakpoint after initializing date, the value is always nil.

Upvotes: 0

Views: 409

Answers (2)

suraj jadhav
suraj jadhav

Reputation: 1

func convertDateString(dateString:String,dateFormat:String = "") -> String {
    if dateString.isEmpty {
        return "" 
    }
    let dateFormatter = DateFormatter()
    let tempLocale = dateFormatter.locale // save locale temporarily
    dateFormatter.locale = Locale(identifier: "en_US_POSIX") // set locale to reliable US_POSIX en_US_POSIX
    dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss+s:s"
    let date = dateFormatter.date(from: dateString)!
    dateFormatter.dateFormat = dateFormat.isEmpty ? "dd-MM-yyyy" : dateFormat
    dateFormatter.locale = tempLocale // reset the locale
    let dateStr = dateFormatter.string(from: date)
    return dateStr
}

usage - your api response date in string format

let time1 = "2019-11-08T01:26:45+00:00"
print(convertDateString(dateString: time1,dateFormat: "EEEE, MMM d, yyyy"))

OUTPUT --->>> Friday, Nov 8, 2019

Upvotes: -1

Rob
Rob

Reputation: 437632

The key observation is to make sure you’re using en_US_POSIX as the locale, as outlined in Working With Fixed Format Date Representations:

let string = "2019-11-12T21:37:39+00:00"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
let date = dateFormatter.date(from: string)

It’s worth noting though, while this formatter will successfully interpret date strings with +00:00, if and when you convert dates back to strings, it will use the literal Z common in ISO 8601/RFC 3339 dates, e.g. "2019-11-12T21:37:39Z". If you really want your resulting strings (if you’re converting dates to strings at all) to use the +00:00 convention, then you’ll want to use xxxxx instead of ZZZZZ. You’ll also want to specify a timeZone for your formatter, too:

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssxxxxx"
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
let string = dateFormatter.string(from: date)            // "2019-11-12T21:37:39+00:00"

So use ZZZZZ if you want the standard "2019-11-12T21:37:39Z", but use xxxxx if you want "2019-11-12T21:37:39+00:00".


By the way, for more information on all the different permutation of Z, ZZZZZ, X, xxxxx, etc., see the time zone section of table at Date Format Patterns.


When I build and run the application and set a breakpoint after initializing date, the value is always nil.

By the way, always print (or PO in lldb) the value. Sometimes the inspector window in Xcode gets out of sync and shows nil when there really is some value there.


As jms said, if you’re using JSONDecoder, you probably shouldn’t use date(from:) or string(from:) at all. Make your property a Date type, and then give your decoder a dateDecodingStrategy:

let json = """
    {"date" : "2019-11-12T21:37:39+00:00"}
    """
let data = json.data(using: .utf8)!

struct ResponseObject: Codable {
    let date: Date
}

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(dateFormatter)

do {
    let object = try decoder.decode(ResponseObject.self, from: data)
} catch {
    print(error)
}

Upvotes: 2

Related Questions