0

This is what I'm trying to decode:

{"MessageDate":"2017-11-28T05:04:40.9611765"}

I've omitted the rest of the JSON structure.

How do I have JSONDecoder parse that date format into a Date object?

This is what I've tried so far:

extension Formatter
{
    static let dotNetDateTime: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
        return formatter
    }()

    /// https://stackoverflow.com/a/46458771/8462094
    static let dotNetDateTimeISO8601: DateFormatter = {
        let formatter = DateFormatter()
        formatter.calendar = Calendar(identifier: .iso8601)
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.timeZone = TimeZone(secondsFromGMT: 0)
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"
        return formatter
    }()

    /// https://stackoverflow.com/a/46458771/8462094
    static let dotNetDateTimeISO8601NoMS: DateFormatter = {
        let formatter = DateFormatter()
        formatter.calendar = Calendar(identifier: .iso8601)
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.timeZone = TimeZone(secondsFromGMT: 0)
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssXXXXX"
        return formatter
    }()

    static let dotNetDateTimeCustom: DateFormatter = {
        let formatter = DateFormatter()
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSS"
        return formatter
    }()

    static let iso8601Full: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXX"
        formatter.calendar = Calendar(identifier: .iso8601)
        formatter.timeZone = TimeZone(secondsFromGMT: 0)
        formatter.locale = Locale(identifier: "en_US_POSIX")
        return formatter
    }()
}

Some of those have been taken from other Stack Overflow posts.
I've also attempted a lot of other date decoding strategies not listed above.
I've scoured the internet for hours for solutions.
I've looked at the Unicode documentation for date format patterns.
I've enlisted the help of another friend, and he doesn't know either.

I suspect the seven digit float at the end of the date string is the culprit, but I don't know how to tackle that.
Maybe I'm just missing something really small. Another set of eyes would be nice.

Any help is greatly appreciated guys, thanx.

I guess I should include the actual code where I'm parsing:

let attempt1 = JSONDecoder()
attempt1.dateDecodingStrategy = .formatted(Formatter.dotNetDateTime)
let attempt2 = JSONDecoder()
attempt2.dateDecodingStrategy = .formatted(Formatter.dotNetDateTimeISO8601)
//And more attempt initializations
...
print(String(data: data, encoding: .utf8)!)
if let deser = try? attempt1.decode(MessageThreads.self, from: data)
{
    return onDone(deser, nil)
}
if let deser = try? attempt2.decode(MessageThreads.self, from: data)
{
    return onDone(deser, nil)
}
//And more attempts
...
Xavier L.
  • 709
  • 5
  • 21

1 Answers1

4

Got it. Sometimes when you need to debug, use Playgrounds.

extension Formatter
{
    static let dotNetDateTimeWithMilliseconds: DateFormatter = {
        let formatter = DateFormatter()
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.S"
        return formatter
    }()
}

Just one .S will suffice to parse it.

Edit:
@Leo Dabus said I should include the locale, so I added it in. Thanx Leo for your help!

Xavier L.
  • 709
  • 5
  • 21
  • 1
    make sure to set your locale to en_US_POSIX. Another thing is are you sure the date string coming from the server it is not UTC time? – Leo Dabus Nov 28 '17 at 15:27
  • Btw this will discard the rest of the fractional seconds also when parsing the date. If you are the one who is building the API better to use a double and pass the timeIntervalSinceReferenceDate in your json – Leo Dabus Nov 28 '17 at 15:27
  • I don't really understand what the `en_US_POSIX` does. I know it forces the locale to the US, but what does that mean exactly? Do I want to force the locale if I _KNOW_ the server is based in the US? What if the server is in Europe or something, would I have to use a different locale? Also, if I keep adding S's like `.SSSSSSS` the rest of the fractional seconds is still discarded. (I'm not building the API (_but I really wish the api would use milliseconds since UNIX or something_)) – Xavier L. Nov 28 '17 at 15:32
  • 1
    The location of the server doesn't matter. en_US_POSIX it is required to parse your string properly – Leo Dabus Nov 28 '17 at 15:33
  • 1
    The maximum number of fractional seconds is 3 when parsing your date. the rest will be ignored – Leo Dabus Nov 28 '17 at 15:34
  • Again even without the time zone in your string it is probably UTC time. – Leo Dabus Nov 28 '17 at 15:36
  • Thanks for this, this is more useful to me than the unicode.org link I mentioned in my question. – Xavier L. Nov 28 '17 at 15:43