Skip to content

Commit ab63b51

Browse files
authored
Merge pull request #602 from xwu/time-zone
Swift 3 API parity and new implementations for NSTimeZone
2 parents 6d6057a + 98cf808 commit ab63b51

File tree

4 files changed

+233
-62
lines changed

4 files changed

+233
-62
lines changed

Foundation/NSDateFormatter.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ open class DateFormatter : Formatter {
148148

149149
open var generatesCalendarDates = false { willSet { _reset() } }
150150

151-
/*@NSCopying*/ open var timeZone: TimeZone! = NSTimeZone.systemTimeZone() { willSet { _reset() } }
151+
/*@NSCopying*/ open var timeZone: TimeZone! = NSTimeZone.system { willSet { _reset() } }
152152

153153
/*@NSCopying*/ internal var _calendar: Calendar! { willSet { _reset() } }
154154
open var calendar: Calendar! {

Foundation/NSTimeZone.swift

Lines changed: 88 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,27 @@ open class NSTimeZone : NSObject, NSCopying, NSSecureCoding, NSCoding {
7979
_CFDeinit(self)
8080
}
8181

82+
// `init(forSecondsFromGMT:)` is not a failable initializer, so we need a designated initializer that isn't failable.
83+
internal init(_name tzName: String) {
84+
super.init()
85+
_CFTimeZoneInit(_cfObject, tzName._cfObject, nil)
86+
}
87+
8288
// Time zones created with this never have daylight savings and the
8389
// offset is constant no matter the date; the name and abbreviation
8490
// do NOT follow the POSIX convention (of minutes-west).
85-
public convenience init(forSecondsFromGMT seconds: Int) { NSUnimplemented() }
91+
public convenience init(forSecondsFromGMT seconds: Int) {
92+
let sign = seconds < 0 ? "-" : "+"
93+
let absoluteValue = abs(seconds)
94+
var minutes = absoluteValue / 60
95+
if (absoluteValue % 60) >= 30 { minutes += 1 }
96+
var hours = minutes / 60
97+
minutes %= 60
98+
hours = min(hours, 99) // Two digits only; leave CF to enforce actual max offset.
99+
let mm = minutes < 10 ? "0\(minutes)" : "\(minutes)"
100+
let hh = hours < 10 ? "0\(hours)" : "\(hours)"
101+
self.init(_name: "GMT" + sign + hh + mm)
102+
}
86103

87104
public convenience init?(abbreviation: String) {
88105
let abbr = abbreviation._cfObject
@@ -95,7 +112,7 @@ open class NSTimeZone : NSObject, NSCopying, NSSecureCoding, NSCoding {
95112
open func encode(with aCoder: NSCoder) {
96113
if aCoder.allowsKeyedCoding {
97114
aCoder.encode(self.name._bridgeToObjectiveC(), forKey:"NS.name")
98-
// darwin versions of this method can and will encode mutable data, however it is not required for compatability
115+
// Darwin versions of this method can and will encode mutable data, however it is not required for compatibility
99116
aCoder.encode(self.data._bridgeToObjectiveC(), forKey:"NS.data")
100117
} else {
101118
}
@@ -165,58 +182,47 @@ open class NSTimeZone : NSObject, NSCopying, NSSecureCoding, NSCoding {
165182

166183
extension NSTimeZone {
167184

168-
open class func systemTimeZone() -> TimeZone {
185+
open class var system: TimeZone {
169186
return CFTimeZoneCopySystem()._swiftObject
170187
}
171188

172189
open class func resetSystemTimeZone() {
173190
CFTimeZoneResetSystem()
174191
}
175192

176-
open class func defaultTimeZone() -> TimeZone {
177-
return CFTimeZoneCopyDefault()._swiftObject
178-
}
179-
180-
open class func setDefaultTimeZone(_ aTimeZone: TimeZone) {
181-
CFTimeZoneSetDefault(aTimeZone._cfObject)
193+
open class var `default`: TimeZone {
194+
get {
195+
return CFTimeZoneCopyDefault()._swiftObject
196+
}
197+
set {
198+
CFTimeZoneSetDefault(newValue._cfObject)
199+
}
182200
}
183-
}
184201

185-
extension NSTimeZone: _SwiftBridgable, _CFBridgable {
186-
typealias SwiftType = TimeZone
187-
var _swiftObject: TimeZone { return TimeZone(reference: self) }
188-
}
189-
190-
extension CFTimeZone : _SwiftBridgable, _NSBridgable {
191-
typealias NSType = NSTimeZone
192-
var _nsObject : NSTimeZone { return unsafeBitCast(self, to: NSTimeZone.self) }
193-
var _swiftObject: TimeZone { return _nsObject._swiftObject }
194-
}
202+
open class var local: TimeZone { NSUnimplemented() }
195203

196-
extension TimeZone : _NSBridgable, _CFBridgable {
197-
typealias NSType = NSTimeZone
198-
typealias CFType = CFTimeZone
199-
var _nsObject : NSTimeZone { return _bridgeToObjectiveC() }
200-
var _cfObject : CFTimeZone { return _nsObject._cfObject }
201-
}
204+
open class var knownTimeZoneNames: [String] {
205+
guard let knownNames = CFTimeZoneCopyKnownNames() else { return [] }
206+
return knownNames._nsObject._bridgeToSwift() as! [String]
207+
}
202208

203-
extension NSTimeZone {
204-
open class func localTimeZone() -> TimeZone { NSUnimplemented() }
205-
206-
open class var knownTimeZoneNames: [String] { NSUnimplemented() }
207-
208209
open class var abbreviationDictionary: [String : String] {
209210
get {
210-
NSUnimplemented()
211+
guard let dictionary = CFTimeZoneCopyAbbreviationDictionary() else { return [:] }
212+
return dictionary._nsObject._bridgeToSwift() as! [String : String]
211213
}
212214
set {
215+
// CFTimeZoneSetAbbreviationDictionary(newValue._cfObject)
213216
NSUnimplemented()
214217
}
215218
}
216-
219+
217220
open class var timeZoneDataVersion: String { NSUnimplemented() }
218-
219-
open var secondsFromGMT: Int { NSUnimplemented() }
221+
222+
open var secondsFromGMT: Int {
223+
let currentDate = Date()
224+
return secondsFromGMT(for: currentDate)
225+
}
220226

221227
/// The abbreviation for the receiver, such as "EDT" (Eastern Daylight Time). (read-only)
222228
///
@@ -226,15 +232,52 @@ extension NSTimeZone {
226232
return abbreviation(for: currentDate)
227233
}
228234

229-
open var daylightSavingTime: Bool { NSUnimplemented() }
230-
open var daylightSavingTimeOffset: TimeInterval { NSUnimplemented() }
231-
/*@NSCopying*/ open var nextDaylightSavingTimeTransition: Date? { NSUnimplemented() }
232-
235+
open var isDaylightSavingTime: Bool {
236+
let currentDate = Date()
237+
return isDaylightSavingTime(for: currentDate)
238+
}
239+
240+
open var daylightSavingTimeOffset: TimeInterval {
241+
let currentDate = Date()
242+
return daylightSavingTimeOffset(for: currentDate)
243+
}
244+
245+
/*@NSCopying*/ open var nextDaylightSavingTimeTransition: Date? {
246+
let currentDate = Date()
247+
return nextDaylightSavingTimeTransition(after: currentDate)
248+
}
249+
233250
open func isEqual(to aTimeZone: TimeZone) -> Bool {
234251
return CFEqual(self._cfObject, aTimeZone._cfObject)
235252
}
236-
237-
open func localizedName(_ style: NameStyle, locale: Locale?) -> String? { NSUnimplemented() }
253+
254+
open func localizedName(_ style: NameStyle, locale: Locale?) -> String? {
255+
#if os(OSX) || os(iOS)
256+
let cfStyle = CFTimeZoneNameStyle(rawValue: style.rawValue)!
257+
#else
258+
let cfStyle = CFTimeZoneNameStyle(style.rawValue)
259+
#endif
260+
return CFTimeZoneCopyLocalizedName(self._cfObject, cfStyle, locale?._cfObject ?? CFLocaleCopyCurrent())._swiftObject
261+
}
262+
263+
}
264+
265+
extension NSTimeZone: _SwiftBridgable, _CFBridgable {
266+
typealias SwiftType = TimeZone
267+
var _swiftObject: TimeZone { return TimeZone(reference: self) }
268+
}
269+
270+
extension CFTimeZone : _SwiftBridgable, _NSBridgable {
271+
typealias NSType = NSTimeZone
272+
var _nsObject : NSTimeZone { return unsafeBitCast(self, to: NSTimeZone.self) }
273+
var _swiftObject: TimeZone { return _nsObject._swiftObject }
274+
}
275+
276+
extension TimeZone : _NSBridgable, _CFBridgable {
277+
typealias NSType = NSTimeZone
278+
typealias CFType = CFTimeZone
279+
var _nsObject : NSTimeZone { return _bridgeToObjectiveC() }
280+
var _cfObject : CFTimeZone { return _nsObject._cfObject }
238281
}
239282

240283
extension NSTimeZone {
@@ -249,3 +292,7 @@ extension NSTimeZone {
249292
}
250293

251294
}
295+
296+
extension NSNotification.Name {
297+
public static let NSSystemTimeZoneDidChange = NSNotification.Name(rawValue: "NSSystemTimeZoneDidChangeNotification") // NSUnimplemented
298+
}

Foundation/TimeZone.swift

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,16 @@
1111
//===----------------------------------------------------------------------===//
1212

1313

14-
1514
internal func __NSTimeZoneIsAutoupdating(_ timezone: NSTimeZone) -> Bool {
1615
return false
1716
}
1817

18+
internal func __NSTimeZoneAutoupdating() -> NSTimeZone {
19+
return NSTimeZone.local._nsObject
20+
}
21+
1922
internal func __NSTimeZoneCurrent() -> NSTimeZone {
20-
fatalError()
23+
return NSTimeZone.system._nsObject
2124
}
2225

2326
/**
@@ -29,7 +32,7 @@ internal func __NSTimeZoneCurrent() -> NSTimeZone {
2932

3033
Cocoa does not provide any API to change the time zone of the computer, or of other applications.
3134
*/
32-
public struct TimeZone : CustomStringConvertible, CustomDebugStringConvertible, Hashable, Equatable, ReferenceConvertible {
35+
public struct TimeZone : Hashable, Equatable, ReferenceConvertible {
3336
public typealias ReferenceType = NSTimeZone
3437

3538
internal var _wrapped : NSTimeZone
@@ -39,6 +42,15 @@ public struct TimeZone : CustomStringConvertible, CustomDebugStringConvertible,
3942
public static var current : TimeZone {
4043
return TimeZone(adoptingReference: __NSTimeZoneCurrent(), autoupdating: false)
4144
}
45+
46+
/// The time zone currently used by the system, automatically updating to the user's current preference.
47+
///
48+
/// If this time zone is mutated, then it no longer tracks the application time zone.
49+
///
50+
/// The autoupdating time zone only compares equal to itself.
51+
public static var autoupdatingCurrent : TimeZone {
52+
return TimeZone(adoptingReference: __NSTimeZoneAutoupdating(), autoupdating: true)
53+
}
4254

4355
// MARK: -
4456
//
@@ -194,28 +206,48 @@ public struct TimeZone : CustomStringConvertible, CustomDebugStringConvertible,
194206

195207
// MARK: -
196208

197-
public var description: String {
198-
return _wrapped.description
199-
}
200-
201-
public var debugDescription : String {
202-
return _wrapped.debugDescription
203-
}
204-
205209
public var hashValue : Int {
206210
if _autoupdating {
207211
return 1
208212
} else {
209213
return _wrapped.hash
210214
}
211215
}
216+
217+
public static func ==(lhs: TimeZone, rhs: TimeZone) -> Bool {
218+
if lhs._autoupdating || rhs._autoupdating {
219+
return lhs._autoupdating == rhs._autoupdating
220+
} else {
221+
return lhs._wrapped.isEqual(rhs._wrapped)
222+
}
223+
}
212224
}
213225

214-
public func ==(_ lhs: TimeZone, _ rhs: TimeZone) -> Bool {
215-
if lhs._autoupdating || rhs._autoupdating {
216-
return lhs._autoupdating == rhs._autoupdating
217-
} else {
218-
return lhs._wrapped.isEqual(rhs._wrapped)
226+
extension TimeZone : CustomStringConvertible, CustomDebugStringConvertible, CustomReflectable {
227+
private var _kindDescription : String {
228+
if (self == TimeZone.current) {
229+
return "current"
230+
} else {
231+
return "fixed"
232+
}
233+
}
234+
235+
public var customMirror : Mirror {
236+
var c: [(label: String?, value: Any)] = []
237+
c.append((label: "identifier", value: identifier))
238+
c.append((label: "kind", value: _kindDescription))
239+
c.append((label: "abbreviation", value: abbreviation()))
240+
c.append((label: "secondsFromGMT", value: secondsFromGMT()))
241+
c.append((label: "isDaylightSavingTime", value: isDaylightSavingTime()))
242+
return Mirror(self, children: c, displayStyle: Mirror.DisplayStyle.struct)
243+
}
244+
245+
public var description: String {
246+
return "\(identifier) (\(_kindDescription))"
247+
}
248+
249+
public var debugDescription : String {
250+
return "\(identifier) (\(_kindDescription))"
219251
}
220252
}
221253

@@ -247,4 +279,3 @@ extension TimeZone {
247279
return result!
248280
}
249281
}
250-

0 commit comments

Comments
 (0)