this repo has no description
1//
2// DateDecodingStrategy.swift
3// URLQueryItemCoder
4//
5// Created by Kyle Hughes on 4/10/23.
6//
7
8import Foundation
9
10/// The strategy to use for decoding `Date` values.
11public enum DateDecodingStrategy {
12 /// Decode the `Date` as a custom value decoded by the given closure.
13 case custom(@Sendable (Decoder) throws -> Date)
14 /// Defer to `Date` for decoding.
15 ///
16 /// This is the default strategy.
17 case deferredToDate
18 /// Decode the `Date` as a string parsed by the given formatter.
19 case formatted(DateFormatter)
20 /// Decode the `Date` as an ISO-8601-formatted string (in RFC 3339 format).
21 case iso8601
22 /// Decode the `Date` as UNIX millisecond timestamp from a number.
23 case millisecondsSince1970
24 /// Decode the `Date` as a UNIX timestamp from a number.
25 case secondsSince1970
26
27 // MARK: Public Static Interface
28
29 /// The default decoding strategy.
30 ///
31 /// Equals `.deferredToDate`.
32 public static let `default`: Self = .deferredToDate
33
34 // MARK: Internal Instance Interface
35
36 internal func decode<PrimitiveValue>(insideOf lowLevelDecoder: LowLevelDecoder<PrimitiveValue>) throws -> Date {
37 switch self {
38 case let .custom(closure):
39 return try closure(lowLevelDecoder)
40 case .deferredToDate:
41 return try Date(from: lowLevelDecoder)
42 case let .formatted(dateFormatter):
43 let singleValueContainer = try lowLevelDecoder.container.expectedSingleValueContainer(
44 at: lowLevelDecoder.codingPath
45 )
46 let stringValue = try singleValueContainer.decode(String.self)
47
48 guard let date = dateFormatter.date(from: stringValue) else {
49 throw DecodingError.dataCorrupted(
50 DecodingError.Context(
51 codingPath: singleValueContainer.codingPath,
52 debugDescription: "Date unable to be decoded from string."
53 )
54 )
55 }
56
57 return date
58 case .iso8601:
59 let singleValueContainer = try lowLevelDecoder.container.expectedSingleValueContainer(
60 at: lowLevelDecoder.codingPath
61 )
62 let dateFormatter = ISO8601DateFormatter()
63 dateFormatter.formatOptions = .withInternetDateTime
64
65 let stringValue = try singleValueContainer.decode(String.self)
66
67 guard let date = dateFormatter.date(from: stringValue) else {
68 throw DecodingError.dataCorrupted(
69 DecodingError.Context(
70 codingPath: singleValueContainer.codingPath,
71 debugDescription: "Date unable to be decoded from string."
72 )
73 )
74 }
75
76 return date
77 case .millisecondsSince1970:
78 let singleValueContainer = try lowLevelDecoder.container.expectedSingleValueContainer(
79 at: lowLevelDecoder.codingPath
80 )
81 let doubleValue = try singleValueContainer.decode(TimeInterval.self) / 1_000
82
83 return Date(timeIntervalSince1970: doubleValue)
84 case .secondsSince1970:
85 let singleValueContainer = try lowLevelDecoder.container.expectedSingleValueContainer(
86 at: lowLevelDecoder.codingPath
87 )
88 let doubleValue = try singleValueContainer.decode(TimeInterval.self)
89
90 return Date(timeIntervalSince1970: doubleValue)
91 }
92 }
93}