Search code examples
iosjsonswiftodatansdateformatter

Swift dateFormat for variable dateType strings


I am trying to parse some json which is the result of an oData connection and I am getting the following response from the server:

"Task_ID":24,"Equipment_ID":3,"Owner_ID":2,"Priority":5,"Date_Due":
"2015-04-08T19:37:56.913","Time_Complete":"2015-04-09T19:37:56","Task_Description"

I am actually interested at the two different date fields I am receiving:

"Date_Due":"2015-04-08T19:37:56.913"


and

"Time_Complete":"2015-04-09T19:37:56"

As we can see, one has the millisecond timestamp and the other one does not.

By looking at the DB, this happens because the millisecond is actually .000 in the database (MS SQL Server) and for whatever reason, the result I receive in my json has this part truncated.

I am not interested in the milliseconds but I would like to have a dateFormat function that can handle both scenarios.

Now I have an obvious answer which is (pre)parse every date field, remove the milliseconds if they are there and then use the following code to format them:

let SQLDateFormatter: NSDateFormatter = {
    let formatter = NSDateFormatter()
    formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
    formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
    formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)
    return formatter
}()

However I would like to know if we can build a formatter that can solve this issue without pre-parsing, something that would be able to take both:

formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"

and

formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS"

and automatically do the formatting properly.

I have been checking for this issue but could not find anything out there, thanks in advance...


Solution

  • extension Formatter {
        static let iso8601: DateFormatter = {
            let formatter = DateFormatter()
            formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
            formatter.locale = Locale(identifier: "en_US_POSIX")
            formatter.timeZone = TimeZone(secondsFromGMT: 0)
            return formatter
        }()
        static let iso8601withFractionalSeconds: DateFormatter = {
            let formatter = DateFormatter()
            formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS"
            formatter.locale = Locale(identifier: "en_US_POSIX")
            formatter.timeZone = TimeZone(secondsFromGMT: 0)
            return formatter
        }()
    }
    

    extension String {
        var date: Date? {
           return Formatter.iso8601withFractionalSeconds.date(from: self) ??
                Formatter.iso8601.date(from: self)
        }
    }
    

    "2015-04-08T19:37:56.913".date  // "Apr 8, 2015, 4:37 PM"
    "2015-04-09T19:37:56".date      // "Apr 9, 2015, 4:37 PM"