@@ -25,42 +25,85 @@ public protocol DateTranscoder: Sendable {
2525}
2626
2727/// A transcoder for dates encoded as an ISO-8601 string (in RFC 3339 format).
28- public struct ISO8601DateTranscoder : DateTranscoder , @unchecked Sendable {
28+ public struct ISO8601DateTranscoder : DateTranscoder {
29+ /// A transcoder using `ISO8601DateFormatter` for encoding and decoding.
30+ private struct DateFormatterTranscoder : DateTranscoder , @unchecked Sendable {
31+ /// The lock protecting the formatter.
32+ private let lock : NSLock
33+
34+ /// The underlying date formatter.
35+ private let locked_formatter : ISO8601DateFormatter
36+
37+ init ( options: ISO8601DateFormatter . Options ? = nil ) {
38+ let formatter = ISO8601DateFormatter ( )
39+ if let options { formatter. formatOptions = options }
40+ lock = NSLock ( )
41+ lock. name = " com.apple.swift-openapi-generator.runtime.ISO8601DateTranscoder "
42+ locked_formatter = formatter
43+ }
44+
45+ func encode( _ date: Date ) throws -> String {
46+ lock. lock ( )
47+ defer { lock. unlock ( ) }
48+ return locked_formatter. string ( from: date)
49+ }
50+
51+ func decode( _ dateString: String ) throws -> Date {
52+ lock. lock ( )
53+ defer { lock. unlock ( ) }
54+ guard let date = locked_formatter. date ( from: dateString) else {
55+ throw DecodingError . dataCorrupted (
56+ . init( codingPath: [ ] , debugDescription: " Expected date string to be ISO8601-formatted. " )
57+ )
58+ }
59+ return date
60+ }
61+ }
2962
30- /// The lock protecting the formatter.
31- private let lock : NSLock
63+ @available ( macOS 12 , * )
64+ /// A transcoder using `Date.ISO8601FormatStyle` for encoding and decoding which
65+ /// is significantly faster than `DateFormatterTranscoder`.
66+ private struct DateFormatStyleTranscoder : DateTranscoder {
67+ private let formatStyle : Date . ISO8601FormatStyle
3268
33- /// The underlying date formatter.
34- private let locked_formatter : ISO8601DateFormatter
69+ init ( formatStyle: Date . ISO8601FormatStyle ) {
70+ self . formatStyle = formatStyle
71+ }
72+
73+ func encode( _ date: Date ) throws -> String {
74+ date. formatted ( formatStyle)
75+ }
76+
77+ func decode( _ dateString: String ) throws -> Date {
78+ try formatStyle. parse ( dateString)
79+ }
80+ }
81+
82+ private let dateTranscoder : any DateTranscoder
3583
3684 /// Creates a new transcoder with the provided options.
3785 /// - Parameter options: Options to override the default ones. If you provide nil here, the default options
3886 /// are used.
87+ @available ( macOS, deprecated: 12 , message: " Use .init(formatStyle:) instead. " )
3988 public init ( options: ISO8601DateFormatter . Options ? = nil ) {
40- let formatter = ISO8601DateFormatter ( )
41- if let options { formatter. formatOptions = options }
42- lock = NSLock ( )
43- lock. name = " com.apple.swift-openapi-generator.runtime.ISO8601DateTranscoder "
44- locked_formatter = formatter
89+ self . dateTranscoder = DateFormatterTranscoder ( options: options)
90+ }
91+
92+ /// Creates a new transcoder with the given ISO8601 format style.
93+ /// - Parameter formatStyle: The format style for encoding/decoding dates. Defaults to `Date.ISO8601FormatStyle()`.
94+ @available ( macOS 12 . 0 , * )
95+ public init ( formatStyle: Date . ISO8601FormatStyle ) {
96+ self . dateTranscoder = DateFormatStyleTranscoder ( formatStyle: formatStyle)
4597 }
4698
4799 /// Creates and returns an ISO 8601 formatted string representation of the specified date.
48100 public func encode( _ date: Date ) throws -> String {
49- lock. lock ( )
50- defer { lock. unlock ( ) }
51- return locked_formatter. string ( from: date)
101+ try self . dateTranscoder. encode ( date)
52102 }
53103
54104 /// Creates and returns a date object from the specified ISO 8601 formatted string representation.
55105 public func decode( _ dateString: String ) throws -> Date {
56- lock. lock ( )
57- defer { lock. unlock ( ) }
58- guard let date = locked_formatter. date ( from: dateString) else {
59- throw DecodingError . dataCorrupted (
60- . init( codingPath: [ ] , debugDescription: " Expected date string to be ISO8601-formatted. " )
61- )
62- }
63- return date
106+ try self . dateTranscoder. decode ( dateString)
64107 }
65108}
66109
@@ -70,7 +113,17 @@ extension DateTranscoder where Self == ISO8601DateTranscoder {
70113
71114 /// A transcoder that transcodes dates as ISO-8601–formatted string (in RFC 3339 format) with fractional seconds.
72115 public static var iso8601WithFractionalSeconds : Self {
73- ISO8601DateTranscoder ( options: [ . withInternetDateTime, . withFractionalSeconds] )
116+ if #available( macOS 12 , * ) {
117+ let formatStyle = Date . ISO8601FormatStyle (
118+ dateSeparator: . dash,
119+ timeSeparator: . colon,
120+ timeZoneSeparator: . colon,
121+ includingFractionalSeconds: true
122+ )
123+ return ISO8601DateTranscoder ( formatStyle: formatStyle)
124+ } else {
125+ return ISO8601DateTranscoder ( options: [ . withInternetDateTime, . withFractionalSeconds] )
126+ }
74127 }
75128}
76129
0 commit comments