teachMeSenpai
teachMeSenpai

Reputation: 236

Using DateFormatter to parse this string into a Date?

I'm hitting a webservice that is returning a string in the following format:

"yyyy-MM-dd'T'HH:mmZ"

It's very close to the standard UTC format, but just without the ss at the end. My issue is that my dateFormatter is always returning nil...and I have tried to make sure that locale and everything else is setup properly.

Here is an example of an actual string:

2019-12-26T00:00Z

Here is the code that creates the DF:

extension DateFormatter {
    @objc static func defaultDateFormat(_ format: String) -> DateFormatter {
        let formatter = DateFormatter()
        formatter.locale = Locale(identifier: "US")
        formatter.dateFormat = format
        return formatter
    }

    func date(from string: String?) -> Date? {
        if let string = string {
            return self.date(from: string)
        } else {
            return nil
        }
    }

    func string(fromOptional date: Date?) -> String? {
        if let date = date {
            return self.string(from: date)
        } else {
            return nil
        }
    }

    func string(fromOptional date: Date?, defaultStr: String) -> String {
        return self.string(fromOptional: date) ?? defaultStr
    }
}

let df = DateFormatter.defaultDateFormat("yyyy-MM-dd'T'HH:mmZ")
let date: Date? = df.date(from: __dateString__) // always nil

Upvotes: 1

Views: 76

Answers (1)

Rob
Rob

Reputation: 437432

A few observations:

  1. You want to use a locale of en_US_POSIX, an invariant locale that always works for ISO 8601 / RFC 3339 date strings. See Technical Q&A 1480.

  2. If you want to use this formatter to convert a date back to a string like 2019-12-26T00:00Z, you will want to:

    • Use X (or ZZZZZ or XXXXX) in your format string, not Z (see the “zone” section in the table at Date Format Patterns and you’ll see how these various time zone patterns, e.g. Z, ZZZZZ, and X, are interpreted); and
    • Set the timeZone of the formatter to use Zulu/GMT/UTC.

Thus:

@objc static func defaultDateFormat(_ format: String) -> DateFormatter {
    let formatter = DateFormatter()
    formatter.locale = Locale(identifier: "en_US_POSIX")
    formatter.timeZone = TimeZone(secondsFromGMT: 0)
    formatter.dateFormat = format
    return formatter
}

And

let df = DateFormatter.defaultDateFormat("yyyy-MM-dd'T'HH:mmX")
let date = df.date(from: "2019-12-26T00:00Z")

Or

let string = df.string(from: Date())

Upvotes: 4

Related Questions