Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 31 additions & 3 deletions Sources/OpenAPIRuntime/Conversion/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,37 @@ public protocol DateTranscoder: Sendable {
}

/// A transcoder for dates encoded as an ISO-8601 string (in RFC 3339 format).
public struct ISO8601DateTranscoder: DateTranscoder {
public struct ISO8601DateTranscoder: DateTranscoder, @unchecked Sendable {

/// The lock protecting the formatter.
private let lock: NSLock

/// The underlying date formatter.
private let locked_formatter: ISO8601DateFormatter

/// Creates a new transcoder with the provided options.
/// - Parameter options: Options to override the default ones. If you provide nil here, the default options
/// are used.
public init(options: ISO8601DateFormatter.Options? = nil) {
let formatter = ISO8601DateFormatter()
if let options { formatter.formatOptions = options }
lock = NSLock()
lock.name = "com.apple.swift-openapi-generator.runtime.ISO8601DateTranscoder"
locked_formatter = formatter
}

/// Creates and returns an ISO 8601 formatted string representation of the specified date.
public func encode(_ date: Date) throws -> String { ISO8601DateFormatter().string(from: date) }
public func encode(_ date: Date) throws -> String {
lock.lock()
defer { lock.unlock() }
return locked_formatter.string(from: date)
}

/// Creates and returns a date object from the specified ISO 8601 formatted string representation.
public func decode(_ dateString: String) throws -> Date {
guard let date = ISO8601DateFormatter().date(from: dateString) else {
lock.lock()
defer { lock.unlock() }
guard let date = locked_formatter.date(from: dateString) else {
throw DecodingError.dataCorrupted(
.init(codingPath: [], debugDescription: "Expected date string to be ISO8601-formatted.")
)
Expand All @@ -44,6 +67,11 @@ public struct ISO8601DateTranscoder: DateTranscoder {
extension DateTranscoder where Self == ISO8601DateTranscoder {
/// A transcoder that transcodes dates as ISO-8601–formatted string (in RFC 3339 format).
public static var iso8601: Self { ISO8601DateTranscoder() }

/// A transcoder that transcodes dates as ISO-8601–formatted string (in RFC 3339 format) with fractional seconds.
public static var iso8601WithFractionalSeconds: Self {
ISO8601DateTranscoder(options: [.withInternetDateTime, .withFractionalSeconds])
}
}

extension JSONEncoder.DateEncodingStrategy {
Expand Down
30 changes: 30 additions & 0 deletions Tests/OpenAPIRuntimeTests/Conversion/Test_Configuration.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftOpenAPIGenerator open source project
//
// Copyright (c) 2023 Apple Inc. and the SwiftOpenAPIGenerator project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftOpenAPIGenerator project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
import XCTest
@_spi(Generated) import OpenAPIRuntime

final class Test_Configuration: Test_Runtime {

func testDateTranscoder_iso8601() throws {
let transcoder: any DateTranscoder = .iso8601
XCTAssertEqual(try transcoder.encode(testDate), testDateString)
XCTAssertEqual(testDate, try transcoder.decode(testDateString))
}

func testDateTranscoder_iso8601WithFractionalSeconds() throws {
let transcoder: any DateTranscoder = .iso8601WithFractionalSeconds
XCTAssertEqual(try transcoder.encode(testDateWithFractionalSeconds), testDateWithFractionalSecondsString)
XCTAssertEqual(testDateWithFractionalSeconds, try transcoder.decode(testDateWithFractionalSecondsString))
}
}
4 changes: 4 additions & 0 deletions Tests/OpenAPIRuntimeTests/Test_Runtime.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ class Test_Runtime: XCTestCase {

var testDateString: String { "2023-01-18T10:04:11Z" }

var testDateWithFractionalSeconds: Date { Date(timeIntervalSince1970: 1_674_036_251.123) }

var testDateWithFractionalSecondsString: String { "2023-01-18T10:04:11.123Z" }

var testDateEscapedString: String { "2023-01-18T10%3A04%3A11Z" }

var testDateStringData: Data { Data(testDateString.utf8) }
Expand Down