BetterCodable icon indicating copy to clipboard operation
BetterCodable copied to clipboard

Decoding Date?

Open npb12 opened this issue 3 years ago • 4 comments

I have a field updatedON that comes as a nil value from the api, but gets updated in the local DB after an object is updated. Not sure how to handle this. Essentially I'd like to combine ISO8601Strategy and DefaultCodableStrategy

npb12 avatar Mar 06 '22 21:03 npb12

any update?

SajjadKharrazi avatar Sep 07 '22 19:09 SajjadKharrazi

It sounds like you might want something like a @OptionalDateValue?

It's not too much code to implement yourself, but if there's interest I could be persuaded to add it to the library.

marksands avatar Sep 09 '22 05:09 marksands

no no, i dont want optional. for example if i have a model:

struct MyModel: Codable {
    var departureDate: Date
    var returnDate: Date
}

and server send to me a json like this: { "departureDate": "2022-10-10T09:09:09", "returnDate": "2022-11-10T09:09:09" }

// MyModel().departureDate: 2022-10-10 09:09:09 +0000
// MyModel().returnDate: 2022-11-10 09:09:09 +0000

everything is ok

but if server send same json without returnDate , i want set it to my model Today date

{ "departureDate": "2022-10-10T09:09:09", "returnDate": null } { "departureDate": "2022-10-10T09:09:09", "returnDate": 3456765 } { "departureDate": "2022-10-10T09:09:09"}

// MyModel().departureDate: 2022-10-10 09:09:09 +0000
// MyModel().returnDate: Date() function

SajjadKharrazi avatar Sep 09 '22 10:09 SajjadKharrazi

@SajjadKharrazi 👍 Then I suppose my advice only applies to @npb12 😄

In your case, you can use a nested property wrapper to accomplish what you want. It's a little clunky, but it works 🎉!

  enum DefaultToNowTimeStampDateValue: DefaultCodableStrategy {
    static var defaultValue: DateValue<TimestampStrategy> {
      .init(wrappedValue: Date())
    }
  }
    
  struct MyModel: Codable {
    @DefaultCodable<DefaultToNowTimeStampDateValue>
    @DateValue<TimestampStrategy>
    var returnDate: Date
  }
    
  let jsonData1 = #"{ "returnDate": null }"#.data(using: .utf8)!
  let fixture1 = try JSONDecoder().decode(MyModel.self, from: jsonData1)
  XCTAssertEqual(fixture1.returnDate, Date()) // null, Defaults to "Date()"

  let jsonData2 = #"{ }"#.data(using: .utf8)!
  let fixture2 = try JSONDecoder().decode(MyModel.self, from: jsonData2)
  XCTAssertEqual(fixture2.returnDate, Date()) // missing, Defaults to "Date()"

  let jsonData3 = #"{ "returnDate": 0 }"#.data(using: .utf8)!
  let fixture3 = try JSONDecoder().decode(MyModel.self, from: jsonData3)
  XCTAssertEqual(fixture3.returnDate, Date()) // expected, defaults to 1970...

Note that the DateValueCodableStrategy must be the same in your DefaultCodableStrategy as well as your MyModel's variable type. The DefaultCodableStrategy must wrap the DateValue's strategy in the type, since the @DefaultCodable's wrappedValue is of type DateValue<DateValueCodableStrategy>, and not Date.

marksands avatar Sep 13 '22 01:09 marksands