f512d94c74
git-subtree-dir: clients/ds-app git-subtree-mainline:a24e3e6f22git-subtree-split:5206cf3b0c
34 lines
1.7 KiB
Swift
34 lines
1.7 KiB
Swift
import Foundation
|
|
|
|
/// Date parsing for the contract's mixed shapes. Two ISO-8601 datetime shapes (with / without
|
|
/// fractional seconds) coexist with date-only strings in the SAME response (digest), so a single
|
|
/// JSONDecoder.dateDecodingStrategy is impossible. Dates are decoded as `String?` raw and parsed here.
|
|
///
|
|
/// Concurrency (B-1 review): uses value-type `Date.ISO8601FormatStyle` (Sendable) as static lets —
|
|
/// no shared reference formatter, so no `nonisolated(unsafe)`.
|
|
///
|
|
/// Date-only (B-1 r2 review): `digest_date` should be DISPLAYED from its raw string (no Date conversion)
|
|
/// to avoid KST off-by-one; `parse` here fixes date-only to UTC and is for sort/window math only.
|
|
public enum DSDate {
|
|
private static let isoFractional = Date.ISO8601FormatStyle(includingFractionalSeconds: true)
|
|
private static let isoPlain = Date.ISO8601FormatStyle(includingFractionalSeconds: false)
|
|
|
|
public static func parse(_ s: String?) -> Date? {
|
|
guard let s, !s.isEmpty else { return nil }
|
|
if let d = try? isoFractional.parse(s) { return d }
|
|
if let d = try? isoPlain.parse(s) { return d }
|
|
return parseDateOnly(s)
|
|
}
|
|
|
|
/// Date-only "YYYY-MM-DD" fixed to UTC (avoids timezone off-by-one). Value-type Calendar, Sendable-safe.
|
|
private static func parseDateOnly(_ s: String) -> Date? {
|
|
let p = s.split(separator: "-")
|
|
guard p.count == 3, let y = Int(p[0]), let m = Int(p[1]), let d = Int(p[2]) else { return nil }
|
|
var comps = DateComponents()
|
|
comps.year = y; comps.month = m; comps.day = d
|
|
var cal = Calendar(identifier: .gregorian)
|
|
cal.timeZone = TimeZone(identifier: "UTC")!
|
|
return cal.date(from: comps)
|
|
}
|
|
}
|