Skip to content

Commit f8e58b1

Browse files
committed
Parity: TimeZone.local, TimeZone.timeZoneDataVersion
Add __NSLocalTimeZone; the name is chosen so as to be NSCoding-compatible with Darwin. Make sure NSTimeZone.local and TimeZone.autoupdatingCurrent return it. Implement .timeZoneDataVersion the same way as it is in Darwin. Re-enable the setter for .abbreviationDictionary.
1 parent 7337331 commit f8e58b1

File tree

5 files changed

+134
-38
lines changed

5 files changed

+134
-38
lines changed

Diff for: CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h

+1
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,7 @@ CF_EXPORT _Nullable CFErrorRef CFReadStreamCopyError(CFReadStreamRef _Null_unspe
392392
CF_EXPORT _Nullable CFErrorRef CFWriteStreamCopyError(CFWriteStreamRef _Null_unspecified stream);
393393

394394
CF_CROSS_PLATFORM_EXPORT Boolean _CFBundleSupportsFHSBundles(void);
395+
CF_CROSS_PLATFORM_EXPORT CFStringRef __CFTimeZoneCopyDataVersionString(void);
395396

396397
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
397398
// Version 0.8

Diff for: CoreFoundation/NumberDate.subproj/CFTimeZone.c

+5-1
Original file line numberDiff line numberDiff line change
@@ -1537,4 +1537,8 @@ static CFDictionaryRef __CFTimeZoneCopyCompatibilityDictionary(void) {
15371537
return dict;
15381538
}
15391539

1540-
1540+
CF_CROSS_PLATFORM_EXPORT CFStringRef __CFTimeZoneCopyDataVersionString(void) {
1541+
UErrorCode err = U_ZERO_ERROR;
1542+
const char *cstr = ucal_getTZDataVersion(&err);
1543+
return (U_SUCCESS(err)) ? CFStringCreateWithCString(kCFAllocatorSystemDefault, cstr, kCFStringEncodingUTF8) : CFRetain(CFSTR(""));
1544+
}

Diff for: Foundation/NSTimeZone.swift

+61-7
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,6 @@ open class NSTimeZone : NSObject, NSCopying, NSSecureCoding, NSCoding {
178178
}
179179
return Date(timeIntervalSinceReferenceDate: CFTimeZoneGetNextDaylightSavingTimeTransition(_cfObject, aDate.timeIntervalSinceReferenceDate))
180180
}
181-
}
182-
183-
extension NSTimeZone {
184181

185182
open class var system: TimeZone {
186183
return CFTimeZoneCopySystem()._swiftObject
@@ -199,7 +196,9 @@ extension NSTimeZone {
199196
}
200197
}
201198

202-
open class var local: TimeZone { NSUnimplemented() }
199+
open class var local: TimeZone {
200+
return TimeZone(adoptingReference: __NSLocalTimeZone.shared, autoupdating: true)
201+
}
203202

204203
open class var knownTimeZoneNames: [String] {
205204
guard let knownNames = CFTimeZoneCopyKnownNames() else { return [] }
@@ -212,12 +211,17 @@ extension NSTimeZone {
212211
return dictionary._nsObject._bridgeToSwift() as! [String : String]
213212
}
214213
set {
215-
// CFTimeZoneSetAbbreviationDictionary(newValue._cfObject)
216-
NSUnimplemented()
214+
CFTimeZoneSetAbbreviationDictionary(newValue._cfObject)
217215
}
218216
}
219217

220-
open class var timeZoneDataVersion: String { NSUnimplemented() }
218+
open class var timeZoneDataVersion: String {
219+
#if os(Windows)
220+
return "" // We do not source timezone data from ICU. The empty string is what Darwin would return if ICU isn't able to give a time zone data version.
221+
#else
222+
return __CFTimeZoneCopyDataVersionString()._swiftObject
223+
#endif
224+
}
221225

222226
open var secondsFromGMT: Int {
223227
let currentDate = Date()
@@ -296,3 +300,53 @@ extension NSTimeZone {
296300
extension NSNotification.Name {
297301
public static let NSSystemTimeZoneDidChange = NSNotification.Name(rawValue: kCFTimeZoneSystemTimeZoneDidChangeNotification._swiftObject)
298302
}
303+
304+
internal class __NSLocalTimeZone: NSTimeZone {
305+
static var shared = __NSLocalTimeZone()
306+
307+
private init() {
308+
super.init(_name: "GMT+0000")
309+
}
310+
311+
public convenience required init?(coder aDecoder: NSCoder) {
312+
// We do not encode details of the local time zone, merely the placeholder object.
313+
self.init()
314+
}
315+
316+
override func encode(with aCoder: NSCoder) {
317+
// We do not encode details of the local time zone, merely the placeholder object.
318+
}
319+
320+
private var system: NSTimeZone {
321+
return NSTimeZone.system._nsObject
322+
}
323+
324+
override var name: String { return system.name }
325+
override var data: Data { return system.data }
326+
override func secondsFromGMT(for aDate: Date) -> Int {
327+
return system.secondsFromGMT(for: aDate)
328+
}
329+
override func abbreviation(for aDate: Date) -> String? {
330+
return system.abbreviation(for: aDate)
331+
}
332+
override func isDaylightSavingTime(for aDate: Date) -> Bool {
333+
return system.isDaylightSavingTime(for: aDate)
334+
}
335+
override func daylightSavingTimeOffset(for aDate: Date) -> TimeInterval {
336+
return system.daylightSavingTimeOffset(for: aDate)
337+
338+
}
339+
override func nextDaylightSavingTimeTransition(after aDate: Date) -> Date? {
340+
return system.nextDaylightSavingTimeTransition(after: aDate)
341+
}
342+
override func localizedName(_ style: NSTimeZone.NameStyle, locale: Locale?) -> String? {
343+
return system.localizedName(style, locale: locale)
344+
}
345+
override var description: String {
346+
return "Local Time Zone (\(system.description))"
347+
}
348+
349+
override func copy(with zone: NSZone? = nil) -> Any {
350+
return self
351+
}
352+
}

Diff for: Foundation/TimeZone.swift

+2-3
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,7 @@ public struct TimeZone : Hashable, Equatable, ReferenceConvertible {
4949
///
5050
/// The autoupdating time zone only compares equal to itself.
5151
public static var autoupdatingCurrent : TimeZone {
52-
// swift-corelibs-foundation does not yet support autoupdating, but we can return the current time zone (which will not change).
53-
return TimeZone(adoptingReference: __NSTimeZoneAutoupdating(), autoupdating: true)
52+
return NSTimeZone.local
5453
}
5554

5655
// MARK: -
@@ -118,7 +117,7 @@ public struct TimeZone : Hashable, Equatable, ReferenceConvertible {
118117
}
119118
}
120119

121-
private init(adoptingReference reference: NSTimeZone, autoupdating: Bool) {
120+
internal init(adoptingReference reference: NSTimeZone, autoupdating: Bool) {
122121
// this path is only used for types we do not need to copy (we are adopting the ref)
123122
_wrapped = reference
124123
_autoupdating = autoupdating

Diff for: TestFoundation/TestTimeZone.swift

+65-27
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,19 @@
1010
import CoreFoundation
1111

1212
class TestTimeZone: XCTestCase {
13-
14-
static var allTests: [(String, (TestTimeZone) -> () throws -> Void)] {
15-
var tests: [(String, (TestTimeZone) -> () throws -> Void)] = [
16-
("test_abbreviation", test_abbreviation),
17-
18-
// Disabled because `CFTimeZoneSetAbbreviationDictionary()` attempts
19-
// to release non-CF objects while removing values from
20-
// `__CFTimeZoneCache`
21-
// ("test_abbreviationDictionary", test_abbreviationDictionary),
22-
23-
("test_changingDefaultTimeZone", test_changingDefaultTimeZone),
24-
("test_computedPropertiesMatchMethodReturnValues", test_computedPropertiesMatchMethodReturnValues),
25-
("test_initializingTimeZoneWithOffset", test_initializingTimeZoneWithOffset),
26-
("test_initializingTimeZoneWithAbbreviation", test_initializingTimeZoneWithAbbreviation),
27-
("test_localizedName", test_localizedName),
28-
("test_customMirror", test_tz_customMirror),
29-
("test_knownTimeZones", test_knownTimeZones),
30-
("test_systemTimeZoneName", test_systemTimeZoneName),
31-
]
32-
33-
#if !os(Windows)
34-
tests.append(contentsOf: [
35-
("test_systemTimeZoneUsesSystemTime", test_systemTimeZoneUsesSystemTime),
36-
])
37-
#endif
38-
39-
return tests
13+
14+
var initialDefaultTimeZone: TimeZone?
15+
16+
override func setUp() {
17+
initialDefaultTimeZone = NSTimeZone.default
18+
super.setUp()
19+
}
20+
21+
override func tearDown() {
22+
super.tearDown()
23+
if let tz = initialDefaultTimeZone {
24+
NSTimeZone.default = tz
25+
}
4026
}
4127

4228
func test_abbreviation() {
@@ -220,4 +206,56 @@ class TestTimeZone: XCTestCase {
220206
XCTAssertEqual(CFStringGetLength(timeZoneName), TimeZone.current.identifier.count)
221207
XCTAssertEqual(CFStringGetLength(timeZoneName), createdTimeZone.identifier.count)
222208
}
209+
210+
func test_autoupdatingTimeZone() {
211+
let system = NSTimeZone.system
212+
let date = Date()
213+
214+
for zone in [NSTimeZone.local, TimeZone.autoupdatingCurrent] {
215+
XCTAssertEqual(zone.identifier, system.identifier)
216+
XCTAssertEqual(zone.secondsFromGMT(for: date), system.secondsFromGMT(for: date))
217+
XCTAssertEqual(zone.abbreviation(for: date), system.abbreviation(for: date))
218+
XCTAssertEqual(zone.isDaylightSavingTime(for: date), system.isDaylightSavingTime(for: date))
219+
XCTAssertEqual(zone.daylightSavingTimeOffset(for: date), system.daylightSavingTimeOffset(for: date))
220+
XCTAssertEqual(zone.nextDaylightSavingTimeTransition(after: date), system.nextDaylightSavingTimeTransition(after: date))
221+
222+
for style in [NSTimeZone.NameStyle.standard,
223+
NSTimeZone.NameStyle.shortStandard,
224+
NSTimeZone.NameStyle.daylightSaving,
225+
NSTimeZone.NameStyle.shortDaylightSaving,
226+
NSTimeZone.NameStyle.generic,
227+
NSTimeZone.NameStyle.shortGeneric,] {
228+
XCTAssertEqual(zone.localizedName(for: style, locale: NSLocale.system), system.localizedName(for: style, locale: NSLocale.system), "For style: \(style)")
229+
}
230+
}
231+
}
232+
233+
static var allTests: [(String, (TestTimeZone) -> () throws -> Void)] {
234+
var tests: [(String, (TestTimeZone) -> () throws -> Void)] = [
235+
("test_abbreviation", test_abbreviation),
236+
237+
// Disabled because `CFTimeZoneSetAbbreviationDictionary()` attempts
238+
// to release non-CF objects while removing values from
239+
// `__CFTimeZoneCache`
240+
// ("test_abbreviationDictionary", test_abbreviationDictionary),
241+
242+
("test_changingDefaultTimeZone", test_changingDefaultTimeZone),
243+
("test_computedPropertiesMatchMethodReturnValues", test_computedPropertiesMatchMethodReturnValues),
244+
("test_initializingTimeZoneWithOffset", test_initializingTimeZoneWithOffset),
245+
("test_initializingTimeZoneWithAbbreviation", test_initializingTimeZoneWithAbbreviation),
246+
("test_localizedName", test_localizedName),
247+
("test_customMirror", test_tz_customMirror),
248+
("test_knownTimeZones", test_knownTimeZones),
249+
("test_systemTimeZoneName", test_systemTimeZoneName),
250+
("test_autoupdatingTimeZone", test_autoupdatingTimeZone),
251+
]
252+
253+
#if !os(Windows)
254+
tests.append(contentsOf: [
255+
("test_systemTimeZoneUsesSystemTime", test_systemTimeZoneUsesSystemTime),
256+
])
257+
#endif
258+
259+
return tests
260+
}
223261
}

0 commit comments

Comments
 (0)