Skip to content

Parity: TimeZone.local, TimeZone.timeZoneDataVersion #2080

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 11, 2019
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
1 change: 1 addition & 0 deletions CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,7 @@ CF_EXPORT _Nullable CFErrorRef CFReadStreamCopyError(CFReadStreamRef _Null_unspe
CF_EXPORT _Nullable CFErrorRef CFWriteStreamCopyError(CFWriteStreamRef _Null_unspecified stream);

CF_CROSS_PLATFORM_EXPORT Boolean _CFBundleSupportsFHSBundles(void);
CF_CROSS_PLATFORM_EXPORT CFStringRef __CFTimeZoneCopyDataVersionString(void);

// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
// Version 0.8
Expand Down
6 changes: 5 additions & 1 deletion CoreFoundation/NumberDate.subproj/CFTimeZone.c
Original file line number Diff line number Diff line change
Expand Up @@ -1537,4 +1537,8 @@ static CFDictionaryRef __CFTimeZoneCopyCompatibilityDictionary(void) {
return dict;
}


CF_CROSS_PLATFORM_EXPORT CFStringRef __CFTimeZoneCopyDataVersionString(void) {
UErrorCode err = U_ZERO_ERROR;
const char *cstr = ucal_getTZDataVersion(&err);
return (U_SUCCESS(err)) ? CFStringCreateWithCString(kCFAllocatorSystemDefault, cstr, kCFStringEncodingUTF8) : CFRetain(CFSTR(""));
}
64 changes: 57 additions & 7 deletions Foundation/NSTimeZone.swift
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,6 @@ open class NSTimeZone : NSObject, NSCopying, NSSecureCoding, NSCoding {
}
return Date(timeIntervalSinceReferenceDate: CFTimeZoneGetNextDaylightSavingTimeTransition(_cfObject, aDate.timeIntervalSinceReferenceDate))
}
}

extension NSTimeZone {

open class var system: TimeZone {
return CFTimeZoneCopySystem()._swiftObject
Expand All @@ -199,7 +196,9 @@ extension NSTimeZone {
}
}

open class var local: TimeZone { NSUnimplemented() }
open class var local: TimeZone {
return TimeZone(adoptingReference: __NSLocalTimeZone.shared, autoupdating: true)
}

open class var knownTimeZoneNames: [String] {
guard let knownNames = CFTimeZoneCopyKnownNames() else { return [] }
Expand All @@ -212,12 +211,13 @@ extension NSTimeZone {
return dictionary._nsObject._bridgeToSwift() as! [String : String]
}
set {
// CFTimeZoneSetAbbreviationDictionary(newValue._cfObject)
NSUnimplemented()
CFTimeZoneSetAbbreviationDictionary(newValue._cfObject)
}
}

open class var timeZoneDataVersion: String { NSUnimplemented() }
open class var timeZoneDataVersion: String {
return __CFTimeZoneCopyDataVersionString()._swiftObject
}

open var secondsFromGMT: Int {
let currentDate = Date()
Expand Down Expand Up @@ -296,3 +296,53 @@ extension NSTimeZone {
extension NSNotification.Name {
public static let NSSystemTimeZoneDidChange = NSNotification.Name(rawValue: kCFTimeZoneSystemTimeZoneDidChangeNotification._swiftObject)
}

internal class __NSLocalTimeZone: NSTimeZone {
static var shared = __NSLocalTimeZone()

private init() {
super.init(_name: "GMT+0000")
}

public convenience required init?(coder aDecoder: NSCoder) {
// We do not encode details of the local time zone, merely the placeholder object.
self.init()
}

override func encode(with aCoder: NSCoder) {
// We do not encode details of the local time zone, merely the placeholder object.
}

private var system: NSTimeZone {
return NSTimeZone.system._nsObject
}

override var name: String { return system.name }
override var data: Data { return system.data }
override func secondsFromGMT(for aDate: Date) -> Int {
return system.secondsFromGMT(for: aDate)
}
override func abbreviation(for aDate: Date) -> String? {
return system.abbreviation(for: aDate)
}
override func isDaylightSavingTime(for aDate: Date) -> Bool {
return system.isDaylightSavingTime(for: aDate)
}
override func daylightSavingTimeOffset(for aDate: Date) -> TimeInterval {
return system.daylightSavingTimeOffset(for: aDate)

}
override func nextDaylightSavingTimeTransition(after aDate: Date) -> Date? {
return system.nextDaylightSavingTimeTransition(after: aDate)
}
override func localizedName(_ style: NSTimeZone.NameStyle, locale: Locale?) -> String? {
return system.localizedName(style, locale: locale)
}
override var description: String {
return "Local Time Zone (\(system.description))"
}

override func copy(with zone: NSZone? = nil) -> Any {
return self
}
}
5 changes: 2 additions & 3 deletions Foundation/TimeZone.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,7 @@ public struct TimeZone : Hashable, Equatable, ReferenceConvertible {
///
/// The autoupdating time zone only compares equal to itself.
public static var autoupdatingCurrent : TimeZone {
// swift-corelibs-foundation does not yet support autoupdating, but we can return the current time zone (which will not change).
return TimeZone(adoptingReference: __NSTimeZoneAutoupdating(), autoupdating: true)
return NSTimeZone.local
}

// MARK: -
Expand Down Expand Up @@ -118,7 +117,7 @@ public struct TimeZone : Hashable, Equatable, ReferenceConvertible {
}
}

private init(adoptingReference reference: NSTimeZone, autoupdating: Bool) {
internal init(adoptingReference reference: NSTimeZone, autoupdating: Bool) {
// this path is only used for types we do not need to copy (we are adopting the ref)
_wrapped = reference
_autoupdating = autoupdating
Expand Down
92 changes: 65 additions & 27 deletions TestFoundation/TestTimeZone.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,33 +10,19 @@
import CoreFoundation

class TestTimeZone: XCTestCase {

static var allTests: [(String, (TestTimeZone) -> () throws -> Void)] {
var tests: [(String, (TestTimeZone) -> () throws -> Void)] = [
("test_abbreviation", test_abbreviation),

// Disabled because `CFTimeZoneSetAbbreviationDictionary()` attempts
// to release non-CF objects while removing values from
// `__CFTimeZoneCache`
// ("test_abbreviationDictionary", test_abbreviationDictionary),

("test_changingDefaultTimeZone", test_changingDefaultTimeZone),
("test_computedPropertiesMatchMethodReturnValues", test_computedPropertiesMatchMethodReturnValues),
("test_initializingTimeZoneWithOffset", test_initializingTimeZoneWithOffset),
("test_initializingTimeZoneWithAbbreviation", test_initializingTimeZoneWithAbbreviation),
("test_localizedName", test_localizedName),
("test_customMirror", test_tz_customMirror),
("test_knownTimeZones", test_knownTimeZones),
("test_systemTimeZoneName", test_systemTimeZoneName),
]

#if !os(Windows)
tests.append(contentsOf: [
("test_systemTimeZoneUsesSystemTime", test_systemTimeZoneUsesSystemTime),
])
#endif

return tests

var initialDefaultTimeZone: TimeZone?

override func setUp() {
initialDefaultTimeZone = NSTimeZone.default
super.setUp()
}

override func tearDown() {
super.tearDown()
if let tz = initialDefaultTimeZone {
NSTimeZone.default = tz
}
}

func test_abbreviation() {
Expand Down Expand Up @@ -220,4 +206,56 @@ class TestTimeZone: XCTestCase {
XCTAssertEqual(CFStringGetLength(timeZoneName), TimeZone.current.identifier.count)
XCTAssertEqual(CFStringGetLength(timeZoneName), createdTimeZone.identifier.count)
}

func test_autoupdatingTimeZone() {
let system = NSTimeZone.system
let date = Date()

for zone in [NSTimeZone.local, TimeZone.autoupdatingCurrent] {
XCTAssertEqual(zone.identifier, system.identifier)
XCTAssertEqual(zone.secondsFromGMT(for: date), system.secondsFromGMT(for: date))
XCTAssertEqual(zone.abbreviation(for: date), system.abbreviation(for: date))
XCTAssertEqual(zone.isDaylightSavingTime(for: date), system.isDaylightSavingTime(for: date))
XCTAssertEqual(zone.daylightSavingTimeOffset(for: date), system.daylightSavingTimeOffset(for: date))
XCTAssertEqual(zone.nextDaylightSavingTimeTransition(after: date), system.nextDaylightSavingTimeTransition(after: date))

for style in [NSTimeZone.NameStyle.standard,
NSTimeZone.NameStyle.shortStandard,
NSTimeZone.NameStyle.daylightSaving,
NSTimeZone.NameStyle.shortDaylightSaving,
NSTimeZone.NameStyle.generic,
NSTimeZone.NameStyle.shortGeneric,] {
XCTAssertEqual(zone.localizedName(for: style, locale: NSLocale.system), system.localizedName(for: style, locale: NSLocale.system), "For style: \(style)")
}
}
}

static var allTests: [(String, (TestTimeZone) -> () throws -> Void)] {
var tests: [(String, (TestTimeZone) -> () throws -> Void)] = [
("test_abbreviation", test_abbreviation),

// Disabled because `CFTimeZoneSetAbbreviationDictionary()` attempts
// to release non-CF objects while removing values from
// `__CFTimeZoneCache`
// ("test_abbreviationDictionary", test_abbreviationDictionary),

("test_changingDefaultTimeZone", test_changingDefaultTimeZone),
("test_computedPropertiesMatchMethodReturnValues", test_computedPropertiesMatchMethodReturnValues),
("test_initializingTimeZoneWithOffset", test_initializingTimeZoneWithOffset),
("test_initializingTimeZoneWithAbbreviation", test_initializingTimeZoneWithAbbreviation),
("test_localizedName", test_localizedName),
("test_customMirror", test_tz_customMirror),
("test_knownTimeZones", test_knownTimeZones),
("test_systemTimeZoneName", test_systemTimeZoneName),
("test_autoupdatingTimeZone", test_autoupdatingTimeZone),
]

#if !os(Windows)
tests.append(contentsOf: [
("test_systemTimeZoneUsesSystemTime", test_systemTimeZoneUsesSystemTime),
])
#endif

return tests
}
}