From ba2a7202e60120de8c3b9bb696c1ce37ba83aba4 Mon Sep 17 00:00:00 2001 From: Simon Evans Date: Sun, 5 May 2019 16:53:17 +0100 Subject: [PATCH] SR-10619: Order in which DateFormatter settings are set up matters on Linux - Ensure the setting of .dateStyle and .timeStyle isnt dependant on the current setting of .locale. (cherry picked from commit 3ceecb1cdce941d5bfd57f86b6dcc017db1a03e3) --- Foundation/DateFormatter.swift | 10 +---- TestFoundation/TestDateFormatter.swift | 61 ++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 8 deletions(-) diff --git a/Foundation/DateFormatter.swift b/Foundation/DateFormatter.swift index 9629e68b81..3f8afa2fb3 100644 --- a/Foundation/DateFormatter.swift +++ b/Foundation/DateFormatter.swift @@ -21,7 +21,7 @@ open class DateFormatter : Formatter { let dateStyle = CFDateFormatterStyle(self.dateStyle.rawValue) let timeStyle = CFDateFormatterStyle(self.timeStyle.rawValue) #endif - + let obj = CFDateFormatterCreate(kCFAllocatorSystemDefault, locale._cfObject, dateStyle, timeStyle)! _setFormatterAttributes(obj) if let dateFormat = _dateFormat { @@ -139,7 +139,7 @@ open class DateFormatter : Formatter { open var dateFormat: String! { get { guard let format = _dateFormat else { - return __cfObject.map { CFDateFormatterGetFormat($0)._swiftObject } ?? "" + return CFDateFormatterGetFormat(_cfObject)._swiftObject } return format } @@ -152,18 +152,12 @@ open class DateFormatter : Formatter { willSet { _dateFormat = nil } - didSet { - _dateFormat = CFDateFormatterGetFormat(_cfObject)._swiftObject - } } open var timeStyle: Style = .none { willSet { _dateFormat = nil } - didSet { - _dateFormat = CFDateFormatterGetFormat(_cfObject)._swiftObject - } } /*@NSCopying*/ internal var _locale: Locale? { willSet { _reset() } } diff --git a/TestFoundation/TestDateFormatter.swift b/TestFoundation/TestDateFormatter.swift index bc44b5c13f..bf92133187 100644 --- a/TestFoundation/TestDateFormatter.swift +++ b/TestFoundation/TestDateFormatter.swift @@ -28,6 +28,7 @@ class TestDateFormatter: XCTestCase { ("test_expectedTimeZone", test_expectedTimeZone), ("test_dateFrom", test_dateFrom), ("test_dateParseAndFormatWithJapaneseCalendar", test_dateParseAndFormatWithJapaneseCalendar), + ("test_orderOfPropertySetters", test_orderOfPropertySetters), ] } @@ -443,4 +444,64 @@ class TestDateFormatter: XCTestCase { let dateString = formatter.string(from: Date(timeIntervalSince1970: 1556633400)) // April 30, 2019, 11:10 PM (JST) XCTAssertEqual(dateString, "平成31年4月30日 23:10") } + + func test_orderOfPropertySetters() throws { + + // This produces a .count factorial number of arrays + func combinations(of a: [T]) -> [[T]] { + precondition(!a.isEmpty) + if a.count == 1 { return [a] } + if a.count == 2 { return [ [a[0], a[1]], [ a[1], a[0]] ] } + + var result: [[T]] = [] + + for idx in a.startIndex.. Void)] = + [(".timeZone", { + $0.timeZone = TimeZone(identifier: "Europe/Oslo") + }), + (".calendar", { + $0.calendar = Calendar(identifier: .gregorian) + }), + (".locale", { + $0.locale = Locale(identifier: "nb") + }), + (".dateStyle", { + $0.dateStyle = .medium + }), + (".timeStyle", { + $0.timeStyle = .medium + }) + ] + + // Test all of the combinations of setting the properties produces the same output + let expected = "5. mai 2019, 12:52:10" + for settings in combinations(of: applySettings) { + let f = DateFormatter() + settings.forEach { $0.1(f) } + XCTAssertEqual(f.dateFormat, "d. MMM y, HH:mm:ss") + let formattedString = f.string(from: date) + if formattedString != expected { + let applied = settings.map { $0.0 }.joined(separator: ",") + XCTFail("\(formattedString) != \(expected) using settings applied in order \(applied)") + } + } + } }