mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Add conformances + unit tests for * CGFloat * AffineTransform * Calendar * CharacterSet * DateComponents * DateInterval * Decimal * IndexPath * IndexSet * Locale * Measurement * NSRange * PersonNameComponents * TimeZone * URL * UUID along with some unit tests for each.
302 lines
12 KiB
Swift
302 lines
12 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
@_exported import Foundation // Clang module
|
|
import _SwiftFoundationOverlayShims
|
|
|
|
/**
|
|
`TimeZone` defines the behavior of a time zone. Time zone values represent geopolitical regions. Consequently, these values have names for these regions. Time zone values also represent a temporal offset, either plus or minus, from Greenwich Mean Time (GMT) and an abbreviation (such as PST for Pacific Standard Time).
|
|
|
|
`TimeZone` provides two static functions to get time zone values: `current` and `autoupdatingCurrent`. The `autoupdatingCurrent` time zone automatically tracks updates made by the user.
|
|
|
|
Note that time zone database entries such as "America/Los_Angeles" are IDs, not names. An example of a time zone name is "Pacific Daylight Time". Although many `TimeZone` functions include the word "name", they refer to IDs.
|
|
|
|
Cocoa does not provide any API to change the time zone of the computer, or of other applications.
|
|
*/
|
|
public struct TimeZone : Hashable, Equatable, ReferenceConvertible {
|
|
public typealias ReferenceType = NSTimeZone
|
|
|
|
fileprivate var _wrapped : NSTimeZone
|
|
private var _autoupdating : Bool
|
|
|
|
/// The time zone currently used by the system.
|
|
public static var current : TimeZone {
|
|
return TimeZone(adoptingReference: __NSTimeZoneCurrent() as! NSTimeZone, autoupdating: false)
|
|
}
|
|
|
|
/// The time zone currently used by the system, automatically updating to the user's current preference.
|
|
///
|
|
/// If this time zone is mutated, then it no longer tracks the system time zone.
|
|
///
|
|
/// The autoupdating time zone only compares equal to itself.
|
|
public static var autoupdatingCurrent : TimeZone {
|
|
return TimeZone(adoptingReference: __NSTimeZoneAutoupdating() as! NSTimeZone, autoupdating: true)
|
|
}
|
|
|
|
// MARK: -
|
|
//
|
|
|
|
/// Returns a time zone initialized with a given identifier.
|
|
///
|
|
/// An example identifier is "America/Los_Angeles".
|
|
///
|
|
/// If `identifier` is an unknown identifier, then returns `nil`.
|
|
public init?(identifier: String) {
|
|
if let r = NSTimeZone(name: identifier) {
|
|
_wrapped = r
|
|
_autoupdating = false
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
@available(*, unavailable, renamed: "init(secondsFromGMT:)")
|
|
public init(forSecondsFromGMT seconds: Int) { fatalError() }
|
|
|
|
/// Returns a time zone initialized with a specific number of seconds from GMT.
|
|
///
|
|
/// Time zones created with this never have daylight savings and the offset is constant no matter the date. The identifier and abbreviation do NOT follow the POSIX convention (of minutes-west).
|
|
///
|
|
/// - parameter seconds: The number of seconds from GMT.
|
|
/// - returns: A time zone, or `nil` if a valid time zone could not be created from `seconds`.
|
|
public init?(secondsFromGMT seconds: Int) {
|
|
if let r = NSTimeZone(forSecondsFromGMT: seconds) as NSTimeZone? {
|
|
_wrapped = r
|
|
_autoupdating = false
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
/// Returns a time zone identified by a given abbreviation.
|
|
///
|
|
/// In general, you are discouraged from using abbreviations except for unique instances such as "GMT". Time Zone abbreviations are not standardized and so a given abbreviation may have multiple meanings--for example, "EST" refers to Eastern Time in both the United States and Australia
|
|
///
|
|
/// - parameter abbreviation: The abbreviation for the time zone.
|
|
/// - returns: A time zone identified by abbreviation determined by resolving the abbreviation to an identifier using the abbreviation dictionary and then returning the time zone for that identifier. Returns `nil` if there is no match for abbreviation.
|
|
public init?(abbreviation: String) {
|
|
if let r = NSTimeZone(abbreviation: abbreviation) {
|
|
_wrapped = r
|
|
_autoupdating = false
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
fileprivate init(reference: NSTimeZone) {
|
|
if __NSTimeZoneIsAutoupdating(reference) {
|
|
// we can't copy this or we lose its auto-ness (27048257)
|
|
// fortunately it's immutable
|
|
_autoupdating = true
|
|
_wrapped = reference
|
|
} else {
|
|
_autoupdating = false
|
|
_wrapped = reference.copy() as! NSTimeZone
|
|
}
|
|
}
|
|
|
|
private 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
|
|
}
|
|
|
|
// MARK: -
|
|
//
|
|
|
|
@available(*, unavailable, renamed: "identifier")
|
|
public var name: String { fatalError() }
|
|
|
|
/// The geopolitical region identifier that identifies the time zone.
|
|
public var identifier: String {
|
|
return _wrapped.name
|
|
}
|
|
|
|
@available(*, unavailable, message: "use the identifier instead")
|
|
public var data: Data { fatalError() }
|
|
|
|
/// The current difference in seconds between the time zone and Greenwich Mean Time.
|
|
///
|
|
/// - parameter date: The date to use for the calculation. The default value is the current date.
|
|
public func secondsFromGMT(for date: Date = Date()) -> Int {
|
|
return _wrapped.secondsFromGMT(for: date)
|
|
}
|
|
|
|
/// Returns the abbreviation for the time zone at a given date.
|
|
///
|
|
/// Note that the abbreviation may be different at different dates. For example, during daylight saving time the US/Eastern time zone has an abbreviation of "EDT." At other times, its abbreviation is "EST."
|
|
/// - parameter date: The date to use for the calculation. The default value is the current date.
|
|
public func abbreviation(for date: Date = Date()) -> String? {
|
|
return _wrapped.abbreviation(for: date)
|
|
}
|
|
|
|
/// Returns a Boolean value that indicates whether the receiver uses daylight saving time at a given date.
|
|
///
|
|
/// - parameter date: The date to use for the calculation. The default value is the current date.
|
|
public func isDaylightSavingTime(for date: Date = Date()) -> Bool {
|
|
return _wrapped.isDaylightSavingTime(for: date)
|
|
}
|
|
|
|
/// Returns the daylight saving time offset for a given date.
|
|
///
|
|
/// - parameter date: The date to use for the calculation. The default value is the current date.
|
|
public func daylightSavingTimeOffset(for date: Date = Date()) -> TimeInterval {
|
|
return _wrapped.daylightSavingTimeOffset(for: date)
|
|
}
|
|
|
|
/// Returns the next daylight saving time transition after a given date.
|
|
///
|
|
/// - parameter date: A date.
|
|
/// - returns: The next daylight saving time transition after `date`. Depending on the time zone, this function may return a change of the time zone's offset from GMT. Returns `nil` if the time zone of the receiver does not observe daylight savings time as of `date`.
|
|
public func nextDaylightSavingTimeTransition(after date: Date) -> Date? {
|
|
return _wrapped.nextDaylightSavingTimeTransition(after: date)
|
|
}
|
|
|
|
/// Returns an array of strings listing the identifier of all the time zones known to the system.
|
|
public static var knownTimeZoneIdentifiers : [String] {
|
|
return NSTimeZone.knownTimeZoneNames
|
|
}
|
|
|
|
/// Returns the mapping of abbreviations to time zone identifiers.
|
|
public static var abbreviationDictionary : [String : String] {
|
|
get {
|
|
return NSTimeZone.abbreviationDictionary
|
|
}
|
|
set {
|
|
NSTimeZone.abbreviationDictionary = newValue
|
|
}
|
|
}
|
|
|
|
/// Returns the time zone data version.
|
|
public static var timeZoneDataVersion : String {
|
|
return NSTimeZone.timeZoneDataVersion
|
|
}
|
|
|
|
/// Returns the date of the next (after the current instant) daylight saving time transition for the time zone. Depending on the time zone, the value of this property may represent a change of the time zone's offset from GMT. Returns `nil` if the time zone does not currently observe daylight saving time.
|
|
public var nextDaylightSavingTimeTransition: Date? {
|
|
return _wrapped.nextDaylightSavingTimeTransition
|
|
}
|
|
|
|
@available(*, unavailable, renamed: "localizedName(for:locale:)")
|
|
public func localizedName(_ style: NSTimeZone.NameStyle, locale: Locale?) -> String? { fatalError() }
|
|
|
|
/// Returns the name of the receiver localized for a given locale.
|
|
public func localizedName(for style: NSTimeZone.NameStyle, locale: Locale?) -> String? {
|
|
return _wrapped.localizedName(style, locale: locale)
|
|
}
|
|
|
|
// MARK: -
|
|
|
|
public var hashValue : Int {
|
|
if _autoupdating {
|
|
return 1
|
|
} else {
|
|
return _wrapped.hash
|
|
}
|
|
}
|
|
|
|
public static func ==(lhs: TimeZone, rhs: TimeZone) -> Bool {
|
|
if lhs._autoupdating || rhs._autoupdating {
|
|
return lhs._autoupdating == rhs._autoupdating
|
|
} else {
|
|
return lhs._wrapped.isEqual(rhs._wrapped)
|
|
}
|
|
}
|
|
}
|
|
|
|
extension TimeZone : CustomStringConvertible, CustomDebugStringConvertible, CustomReflectable {
|
|
private var _kindDescription : String {
|
|
if self == TimeZone.autoupdatingCurrent {
|
|
return "autoupdatingCurrent"
|
|
} else if self == TimeZone.current {
|
|
return "current"
|
|
} else {
|
|
return "fixed"
|
|
}
|
|
}
|
|
|
|
public var customMirror : Mirror {
|
|
let c: [(label: String?, value: Any)] = [
|
|
("identifier", identifier),
|
|
("kind", _kindDescription),
|
|
("abbreviation", abbreviation() as Any),
|
|
("secondsFromGMT", secondsFromGMT()),
|
|
("isDaylightSavingTime", isDaylightSavingTime()),
|
|
]
|
|
return Mirror(self, children: c, displayStyle: Mirror.DisplayStyle.struct)
|
|
}
|
|
|
|
public var description: String {
|
|
return "\(identifier) (\(_kindDescription))"
|
|
}
|
|
|
|
public var debugDescription : String {
|
|
return "\(identifier) (\(_kindDescription))"
|
|
}
|
|
}
|
|
|
|
extension TimeZone : _ObjectiveCBridgeable {
|
|
@_semantics("convertToObjectiveC")
|
|
public func _bridgeToObjectiveC() -> NSTimeZone {
|
|
// _wrapped is immutable
|
|
return _wrapped
|
|
}
|
|
|
|
public static func _forceBridgeFromObjectiveC(_ input: NSTimeZone, result: inout TimeZone?) {
|
|
if !_conditionallyBridgeFromObjectiveC(input, result: &result) {
|
|
fatalError("Unable to bridge \(_ObjectiveCType.self) to \(self)")
|
|
}
|
|
}
|
|
|
|
public static func _conditionallyBridgeFromObjectiveC(_ input: NSTimeZone, result: inout TimeZone?) -> Bool {
|
|
result = TimeZone(reference: input)
|
|
return true
|
|
}
|
|
|
|
public static func _unconditionallyBridgeFromObjectiveC(_ source: NSTimeZone?) -> TimeZone {
|
|
var result: TimeZone?
|
|
_forceBridgeFromObjectiveC(source!, result: &result)
|
|
return result!
|
|
}
|
|
}
|
|
|
|
extension NSTimeZone : _HasCustomAnyHashableRepresentation {
|
|
// Must be @nonobjc to avoid infinite recursion during bridging.
|
|
@nonobjc
|
|
public func _toCustomAnyHashable() -> AnyHashable? {
|
|
return AnyHashable(self as TimeZone)
|
|
}
|
|
}
|
|
|
|
extension TimeZone : Codable {
|
|
private enum CodingKeys : Int, CodingKey {
|
|
case identifier
|
|
}
|
|
|
|
public init(from decoder: Decoder) throws {
|
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
let identifier = try container.decode(String.self, forKey: .identifier)
|
|
|
|
guard let timeZone = TimeZone(identifier: identifier) else {
|
|
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath,
|
|
debugDescription: "Invalid TimeZone identifier."))
|
|
}
|
|
|
|
self = timeZone
|
|
}
|
|
|
|
public func encode(to encoder: Encoder) throws {
|
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
try container.encode(self.identifier, forKey: .identifier)
|
|
}
|
|
}
|