Search code examples
iosiphoneswiftdatetimejson-deserialization

EVReflection.setDateFormatter() supporting multiple formats


I have encountered a problem with deserialization of my DateTime strings from JSON in swift.

I have entity containing multiple NSDate values (which are received from .NET WebAPI server). My problem is that some of JSON properties contain date strings formatted like this: "yyyy-MM-ddTHH:mm:ss" and some have miliseconds contained, like this: "yyyy-MM-ddTHH:mm:ss.SSS"

In entity initializer there is statement selecting my NSDateFormatter (without it none of date strings is getting deserialised):

EVReflection.setDateFormatter(NSDateFormatter.isoDateFormatter())

and isoDateFormatter looks like this:

class func isoDateFormatter() -> NSDateFormatter {
    let formatter = NSDateFormatter()
    formatter.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss"
    formatter.locale = NSLocale.currentLocale()
    return formatter
}

After my entity is mapped into an object, NSDate properties containing miliseconds were not mapped to object leaving those properties nil while properties without miliseconds are mapped

Example:

{
"startTime" : "2018-10-05T10:15:00",    // is deserialized
"startTrackingTime" : "2018-10-05T10:14:59.637"    // is not deserialized
}

What I want to accomplish is just to deserialize all date strings into NSDate properties, I even dont need milliseconds part but i don't know how to tell the EVReflection to use more than one NSDateFormatter or more than one date-time format or to just ignore milliseconds part.

EDIT: I can't use NSISO8601DateFormatter because it does not support iOS 9, only iOS 10+


Solution

  • The only solution for this situation I have found is defining custom property converter for properties with different Date format.

    This is example of one custom property converter I have used.

    key: "startTrackingTime",
    decodeConverter: {
        let formatter = NSDateFormatter.isoMilisecondsDateFormatter()
        self.startTrackingTime = formatter.dateFromString($0 as! String)
    },
    encodeConverter: {
        let formatter = NSDateFormatter.isoMilisecondsDateFormatter()
        if self.startTrackingTime != nil {
            return formatter.stringFromDate(self.startTrackingTime!)
        } else {
            return ""
        }
    }
    

    Where isoMilisecondsFormatter() is

    class func isoMilisecondsDateFormatter() -> NSDateFormatter {
        let formatter = NSDateFormatter()
        formatter.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.SSS"
        formatter.timeZone = NSTimeZone(abbreviation: "UTC")
        formatter.locale = NSLocale.currentLocale()
        return formatter
    }
    

    So, I had to specify exact formatter for each property that is not received in (let's say) "default" format which seems as a really hacky way to do it, but I did not know better.

    If someone has better solution I would appreciate sharing it with others.