Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strange Date Transformation behavior #698

Closed
liltimtim opened this issue Dec 14, 2016 · 3 comments
Closed

Strange Date Transformation behavior #698

liltimtim opened this issue Dec 14, 2016 · 3 comments

Comments

@liltimtim
Copy link

liltimtim commented Dec 14, 2016

Hello,

Before this library used to just transform dates without having to specify a date transform function (at least this is the behavior I saw).

So for example

public private(set) var myDate:Date?

public fund mapping(map: Map) {
  myDate <- map["my_date"]
}

Given the date is of format "2016-12-09T13:37:27.262Z", it would transform this date properly without me having to specify that it was indeed a date.

My current model is failing to parse the date correctly for some reason. I've tried both the example given on the read-me, I've looked at the "closed" issues regarding date formatting and I've tried to use their examples as well...still no luck.

Ive tried these date transforms

  1. DateTransform()
  2. ISO Date transform function

My unit test...

class TripTests: XCTestCase {
    func testInflateTestObjectFromJSON() {
        var tripObj = [String:AnyObject]()
        tripObj["_id"] = "123" as AnyObject?
        tripObj["dropoff_time"] = "2016-12-09T13:37:27.262Z" as AnyObject?
        let trip = Trip(JSON: tripObj)
        XCTAssertNotNil(trip?.id)
        XCTAssertNotNil(trip?.dropoffTime)
        print(trip?.pickupTime)
        print(trip?.dropoffTime)
        dump(trip?.toJSONString())
    }
}

which produces...

Optional(1970-01-01 00:33:36 +0000)
Optional(1970-01-01 00:33:36 +0000)
▿ Optional("{\"dropoff_time\":2016,\"pickup_time\":2016,\"_id\":\"123\"}")

Clearly, the date I'm giving it isn't 1970...and the above date is indeed an ISO formatted date. The server I'm running is Express/Mongo and I'm simply using the Date.now javascript call to generate a date. Also, the Schema on the Mongo model is of type 'Date'.

Here is my Trip model

import Foundation
import ObjectMapper

public class Trip : Mappable {
    public private(set) var id: String?
    public var pickupTime:Date?
    public var dropoffTime:Date?
    public var completed:Bool?
    public private(set) var createdAt:Date?
    public private(set) var updatedAt:Date?

    
    public init(captain: User?, passenger: User?) {
        self.captain = captain
        self.passenger = passenger
    }
    
    public required init?(map: Map) {

    }
    
    public func mapping(map: Map) {
        id <- map["_id"]
        pickupTime <- (map["pickup_time"], DateTransform())
        dropoffTime <- (map["dropoff_time"], DateTransform())
        completed <- map["completed"]
        updatedAt <- (map["updated_at"], DateTransform())
        createdAt <- (map["created_at"], DateTransform())
    }
}

Again, as stated above, I've tried using both the DateTransform() and the ISO8601DateTransform().

If I use the DateTransform function, my unit test will "pass" because the date property will no longer be nil however it will be the 1970 date which isn't correct.

If I use the ISO8601DateTransform, the property is nil and the unit test will fail because it was expecting the date to not be nil.

Before I would just specify that the property was a "date" and it would transform everything correctly without me having to specifically set a DateTransform tuple for the mapping. I don't know exactly what I am doing incorrectly here.

==== Updated just to make it look prettier =====

@liltimtim
Copy link
Author

liltimtim commented Dec 14, 2016

So I believe I may have solved my own issue...

I still do not know why the built in ISO date formatter doesn't work however I created my own

import Foundation
import ObjectMapper
open class ISODateTransform: TransformType {
    public typealias Object = Date
    public typealias JSON = String
    
    public init() {}
    
    public func transformFromJSON(_ value: Any?) -> Date? {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
        
        guard let strValue = value as? String else { return nil }
        return formatter.date(from: strValue)
    }
    
    public func transformToJSON(_ value: Date?) -> String? {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
        guard value != nil else { return nil }
        return formatter.string(from: value!)
    }}

this seems to work just fine, unit tests are passing with valid dates now.

@ebbe-minecraft
Copy link

Just to add to this. I couldn't get the solution above to work but it did steer me into the right directions so much appreciated. I made some tweaks and this works for me.

//
//  ISODateTransform.swift
//

import Foundation
import ObjectMapper

open class ISODateTransform: TransformType {
    public typealias Object = Date
    public typealias JSON = String
    
    public init() {}
    
    public func transformFromJSON (_ value: Any?) -> Date? {
        guard let datestring = value as? String else { return nil }
        let isoFormatter = ISO8601DateFormatter()
        let date = isoFormatter.date(from: datestring)!
        
        return date
    }

    public func transformToJSON(_ value: Date?) -> String? {
        let isoFormatter = ISO8601DateFormatter()
        let string = isoFormatter.string(from: value!)
        
        return string
    }
}

@ghost
Copy link

ghost commented Jun 3, 2020

Another Fix:
https://forums.swift.org/t/iso8601dateformatter-fails-to-parse-a-valid-iso-8601-date/22999/12

open class ISODateTransform: TransformType {
public typealias Object = Date
public typealias JSON = String

public init() {}

public func transformFromJSON (_ value: Any?) -> Date? {
    guard let datestring = value as? String else { return nil }
    let isoFormatter = ISO8601DateFormatter()
    //Critical Fix
    isoFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
    let date = isoFormatter.date(from: datestring)!
    
    return date
}

public func transformToJSON(_ value: Date?) -> String? {
    let isoFormatter = ISO8601DateFormatter()
    //Critical Fix
    isoFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
    let string = isoFormatter.string(from: value!)
    return string
}

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants