diff --git a/Contentful.xcodeproj/project.pbxproj b/Contentful.xcodeproj/project.pbxproj index 96da5dc3..a311fffc 100644 --- a/Contentful.xcodeproj/project.pbxproj +++ b/Contentful.xcodeproj/project.pbxproj @@ -165,6 +165,10 @@ 6DEB234124E84924009D5879 /* FieldTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEB234024E84924009D5879 /* FieldTests.swift */; }; 6DEB234224E84924009D5879 /* FieldTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEB234024E84924009D5879 /* FieldTests.swift */; }; 6DEB234324E84924009D5879 /* FieldTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEB234024E84924009D5879 /* FieldTests.swift */; }; + 971357602C6FC3A500BD052D /* DateFormatterCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9713575F2C6FC3A500BD052D /* DateFormatterCache.swift */; }; + 971357612C6FC3A500BD052D /* DateFormatterCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9713575F2C6FC3A500BD052D /* DateFormatterCache.swift */; }; + 971357622C6FC3A500BD052D /* DateFormatterCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9713575F2C6FC3A500BD052D /* DateFormatterCache.swift */; }; + 971357632C6FC3A500BD052D /* DateFormatterCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9713575F2C6FC3A500BD052D /* DateFormatterCache.swift */; }; A10FF9D21BBB2E5F001AA4E9 /* JSONDecodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B2E3661BBAD06000814D63 /* JSONDecodingTests.swift */; }; A10FF9D31BBB32FD001AA4E9 /* Asset.swift in Sources */ = {isa = PBXBuildFile; fileRef = A15193AD1BB9236300FB83CD /* Asset.swift */; }; A10FF9D51BBB3676001AA4E9 /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = A10FF9D41BBB3676001AA4E9 /* Error.swift */; }; @@ -353,6 +357,7 @@ 6DEB233724E84365009D5879 /* FieldType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldType.swift; sourceTree = ""; }; 6DEB233C24E843DB009D5879 /* FieldTypeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldTypeTests.swift; sourceTree = ""; }; 6DEB234024E84924009D5879 /* FieldTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldTests.swift; sourceTree = ""; }; + 9713575F2C6FC3A500BD052D /* DateFormatterCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateFormatterCache.swift; sourceTree = ""; }; A10FF9D41BBB3676001AA4E9 /* Error.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = Error.swift; sourceTree = ""; }; A10FF9DB1BBB4692001AA4E9 /* Field.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = Field.swift; sourceTree = ""; }; A114BBBF1C4FD3C300DE6679 /* SyncSpace.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = SyncSpace.swift; sourceTree = ""; }; @@ -590,6 +595,7 @@ ED3CBF191E7AD57100E5B02E /* Sys.swift */, ED5F8F901F8F9EA200C86411 /* TypedQuery.swift */, ED02DC1220E11D0A005EC57B /* Util.swift */, + 9713575F2C6FC3A500BD052D /* DateFormatterCache.swift */, ); path = Contentful; sourceTree = ""; @@ -1143,6 +1149,7 @@ 6D48E75C251F615D0037B278 /* JSONDecoderBuilder.swift in Sources */, 5D52E25D2193375300C88FC9 /* Error.swift in Sources */, 5D52E25E2193375300C88FC9 /* Field.swift in Sources */, + 971357602C6FC3A500BD052D /* DateFormatterCache.swift in Sources */, 5D52E25F2193375300C88FC9 /* ImageOptions.swift in Sources */, 5D52E2612193375300C88FC9 /* Client+UIKit.swift in Sources */, ); @@ -1215,6 +1222,7 @@ 6D48E75A251F615D0037B278 /* JSONDecoderBuilder.swift in Sources */, ED68BD721E6DC47A00939F6D /* Query.swift in Sources */, ED3CBF1F1E7AD58100E5B02E /* Link.swift in Sources */, + 971357632C6FC3A500BD052D /* DateFormatterCache.swift in Sources */, A10FF9D51BBB3676001AA4E9 /* Error.swift in Sources */, ED3CBF1A1E7AD57100E5B02E /* Sys.swift in Sources */, ); @@ -1318,6 +1326,7 @@ 6D48E75B251F615D0037B278 /* JSONDecoderBuilder.swift in Sources */, ED3CBF201E7AD58100E5B02E /* Link.swift in Sources */, ED36B6FA1E3BD052005581FD /* ContentType.swift in Sources */, + 971357622C6FC3A500BD052D /* DateFormatterCache.swift in Sources */, ED91C1411EDCB03900F0FC0A /* ImageOptions.swift in Sources */, ED3CBF1B1E7AD57100E5B02E /* Sys.swift in Sources */, ); @@ -1359,6 +1368,7 @@ 6D48E75D251F615D0037B278 /* JSONDecoderBuilder.swift in Sources */, ED3CBF221E7AD58100E5B02E /* Link.swift in Sources */, ED36B71A1E3BD053005581FD /* ContentType.swift in Sources */, + 971357612C6FC3A500BD052D /* DateFormatterCache.swift in Sources */, ED91C1431EDCB03B00F0FC0A /* ImageOptions.swift in Sources */, ED3CBF1D1E7AD57100E5B02E /* Sys.swift in Sources */, ); diff --git a/Sources/Contentful/Date.swift b/Sources/Contentful/Date.swift index 2b566615..40aa1b6e 100644 --- a/Sources/Contentful/Date.swift +++ b/Sources/Contentful/Date.swift @@ -56,7 +56,7 @@ public extension Date { let formatter = Date.iso8601Formatter(timeZone: timeZone) for format in Date.supportedFormats { - formatter.dateFormat = format + let formatter = DateFormatterCache.shared.get(format, timeZone: timeZone) if let date = formatter.date(from: dateString) { return date } diff --git a/Sources/Contentful/DateFormatterCache.swift b/Sources/Contentful/DateFormatterCache.swift new file mode 100644 index 00000000..e6718f22 --- /dev/null +++ b/Sources/Contentful/DateFormatterCache.swift @@ -0,0 +1,36 @@ +// +// DateFormatterCache.swift +// Contentful +// +// Created by Donny Wals on 05/08/2024. +// + +import Foundation + +class DateFormatterCache { + static let shared = DateFormatterCache() + + private let queue = DispatchQueue(label: "com.contentful.formattercache") + private var cache = [String: DateFormatter]() + + private init() {} + + func get(_ format: String, timeZone: TimeZone? = nil) -> DateFormatter { + return queue.sync { + if let formatter = cache[format] { + return formatter + } + + let formatter = DateFormatter() + formatter.calendar = Calendar(identifier: .iso8601) + // The locale and timezone properties must be exactly as follows to have a true, time-zone agnostic (i.e. offset of 00:00 from UTC) ISO stamp. + formatter.locale = Foundation.Locale(identifier: "en_US_POSIX") + formatter.timeZone = timeZone ?? TimeZone(secondsFromGMT: 0) + formatter.dateFormat = format + + cache[format] = formatter + + return formatter + } + } +}