Skip to content

Instantly share code, notes, and snippets.

@marksands
Created September 11, 2020 15:53
Show Gist options
  • Save marksands/243cc6963aa4cf23a4d12ecc2b51f44a to your computer and use it in GitHub Desktop.
Save marksands/243cc6963aa4cf23a4d12ecc2b51f44a to your computer and use it in GitHub Desktop.

Revisions

  1. marksands created this gist Sep 11, 2020.
    59 changes: 59 additions & 0 deletions OptionalDateValue.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,59 @@

    public protocol OptionalDateValueCodableStrategy {
    associatedtype RawValue: Codable

    static func decode(_ value: RawValue?) throws -> Date?
    static func encode(_ date: Date?) -> RawValue?
    }

    @propertyWrapper
    public struct OptionalDateValue<Formatter: OptionalDateValueCodableStrategy>: Codable {
    private let value: Formatter.RawValue?
    public var wrappedValue: Date?

    public init(wrappedValue: Date?) {
    self.wrappedValue = wrappedValue
    self.value = Formatter.encode(wrappedValue)
    }

    public init(from decoder: Decoder) throws {
    self.value = try? Formatter.RawValue(from: decoder)
    self.wrappedValue = try? Formatter.decode(value)
    }

    public func encode(to encoder: Encoder) throws {
    try value.encode(to: encoder)
    }
    }

    public struct OptionalTimestampStrategy: OptionalDateValueCodableStrategy {
    public static func decode(_ value: TimeInterval?) throws -> Date? {
    return value.map { Date(timeIntervalSince1970: $0) }
    }

    public static func encode(_ date: Date?) -> TimeInterval? {
    return date?.timeIntervalSince1970
    }
    }

    struct Fixture: Codable {
    @OptionalDateValue<OptionalTimestampStrategy> var timestamp: Date?
    }

    func testDecodingTimestamp() {
    let jsonData = #"{"timestamp": 851042397.0}"#.data(using: .utf8)!

    let fixture = try! JSONDecoder().decode(Fixture.self, from: jsonData)
    assert(fixture.timestamp == Date(timeIntervalSince1970: 851042397))
    assert(fixture.timestamp?.timeIntervalSince1970 == 851042397)
    }

    func testDecodingNil() {
    let jsonData = #"{"timestamp": null}"#.data(using: .utf8)!

    let fixture = try! JSONDecoder().decode(Fixture.self, from: jsonData)
    assert(fixture.timestamp == nil)
    }

    testDecodingTimestamp()
    testDecodingNil()