mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
All generic bridgeable types can bridge for all their instantiations now. Removing this ferrets out some now-unnecessary traps that check for unbridgeable parameter types.
322 lines
14 KiB
Swift
322 lines
14 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
@_exported import Foundation // Clang module
|
|
|
|
/**
|
|
`DateComponents` encapsulates the components of a date in an extendable, structured manner.
|
|
|
|
It is used to specify a date by providing the temporal components that make up a date and time in a particular calendar: hour, minutes, seconds, day, month, year, and so on. It can also be used to specify a duration of time, for example, 5 hours and 16 minutes. A `DateComponents` is not required to define all the component fields.
|
|
|
|
When a new instance of `DateComponents` is created, the date components are set to `nil`.
|
|
*/
|
|
public struct DateComponents : ReferenceConvertible, Hashable, Equatable, _MutableBoxing {
|
|
public typealias ReferenceType = NSDateComponents
|
|
|
|
internal var _handle: _MutableHandle<NSDateComponents>
|
|
|
|
/// Initialize a `DateComponents`, optionally specifying values for its fields.
|
|
public init(calendar: Calendar? = nil,
|
|
timeZone: TimeZone? = nil,
|
|
era: Int? = nil,
|
|
year: Int? = nil,
|
|
month: Int? = nil,
|
|
day: Int? = nil,
|
|
hour: Int? = nil,
|
|
minute: Int? = nil,
|
|
second: Int? = nil,
|
|
nanosecond: Int? = nil,
|
|
weekday: Int? = nil,
|
|
weekdayOrdinal: Int? = nil,
|
|
quarter: Int? = nil,
|
|
weekOfMonth: Int? = nil,
|
|
weekOfYear: Int? = nil,
|
|
yearForWeekOfYear: Int? = nil) {
|
|
_handle = _MutableHandle(adoptingReference: NSDateComponents())
|
|
if let _calendar = calendar { self.calendar = _calendar }
|
|
if let _timeZone = timeZone { self.timeZone = _timeZone }
|
|
if let _era = era { self.era = _era }
|
|
if let _year = year { self.year = _year }
|
|
if let _month = month { self.month = _month }
|
|
if let _day = day { self.day = _day }
|
|
if let _hour = hour { self.hour = _hour }
|
|
if let _minute = minute { self.minute = _minute }
|
|
if let _second = second { self.second = _second }
|
|
if let _nanosecond = nanosecond { self.nanosecond = _nanosecond }
|
|
if let _weekday = weekday { self.weekday = _weekday }
|
|
if let _weekdayOrdinal = weekdayOrdinal { self.weekdayOrdinal = _weekdayOrdinal }
|
|
if let _quarter = quarter { self.quarter = _quarter }
|
|
if let _weekOfMonth = weekOfMonth { self.weekOfMonth = _weekOfMonth }
|
|
if let _weekOfYear = weekOfYear { self.weekOfYear = _weekOfYear }
|
|
if let _yearForWeekOfYear = yearForWeekOfYear { self.yearForWeekOfYear = _yearForWeekOfYear }
|
|
}
|
|
|
|
|
|
// MARK: - Properties
|
|
|
|
/// Translate from the NSDateComponentUndefined value into a proper Swift optional
|
|
private func _getter(_ x : Int) -> Int? { return x == NSDateComponentUndefined ? nil : x }
|
|
|
|
/// Translate from the proper Swift optional value into an NSDateComponentUndefined
|
|
private func _setter(_ x : Int?) -> Int { if let xx = x { return xx } else { return NSDateComponentUndefined } }
|
|
|
|
/// The `Calendar` used to interpret the other values in this structure.
|
|
///
|
|
/// - note: API which uses `DateComponents` may have different behavior if this value is `nil`. For example, assuming the current calendar or ignoring certain values.
|
|
public var calendar: Calendar? {
|
|
get { return _handle.map { $0.calendar } }
|
|
set { _applyMutation { $0.calendar = newValue } }
|
|
}
|
|
|
|
/// A time zone.
|
|
/// - note: This value is interpreted in the context of the calendar in which it is used.
|
|
public var timeZone: TimeZone? {
|
|
get { return _handle.map { $0.timeZone } }
|
|
set { _applyMutation { $0.timeZone = newValue } }
|
|
}
|
|
|
|
/// An era or count of eras.
|
|
/// - note: This value is interpreted in the context of the calendar in which it is used.
|
|
public var era: Int? {
|
|
get { return _handle.map { _getter($0.era) } }
|
|
set { _applyMutation { $0.era = _setter(newValue) } }
|
|
}
|
|
|
|
/// A year or count of years.
|
|
/// - note: This value is interpreted in the context of the calendar in which it is used.
|
|
public var year: Int? {
|
|
get { return _handle.map { _getter($0.year) } }
|
|
set { _applyMutation { $0.year = _setter(newValue) } }
|
|
}
|
|
|
|
/// A month or count of months.
|
|
/// - note: This value is interpreted in the context of the calendar in which it is used.
|
|
public var month: Int? {
|
|
get { return _handle.map { _getter($0.month) } }
|
|
set { _applyMutation { $0.month = _setter(newValue) } }
|
|
}
|
|
|
|
/// A day or count of days.
|
|
/// - note: This value is interpreted in the context of the calendar in which it is used.
|
|
public var day: Int? {
|
|
get { return _handle.map { _getter($0.day) } }
|
|
set { _applyMutation { $0.day = _setter(newValue) } }
|
|
}
|
|
|
|
/// An hour or count of hours.
|
|
/// - note: This value is interpreted in the context of the calendar in which it is used.
|
|
public var hour: Int? {
|
|
get { return _handle.map { _getter($0.hour) } }
|
|
set { _applyMutation { $0.hour = _setter(newValue) } }
|
|
}
|
|
|
|
/// A minute or count of minutes.
|
|
/// - note: This value is interpreted in the context of the calendar in which it is used.
|
|
public var minute: Int? {
|
|
get { return _handle.map { _getter($0.minute) } }
|
|
set { _applyMutation { $0.minute = _setter(newValue) } }
|
|
}
|
|
|
|
/// A second or count of seconds.
|
|
/// - note: This value is interpreted in the context of the calendar in which it is used.
|
|
public var second: Int? {
|
|
get { return _handle.map { _getter($0.second) } }
|
|
set { _applyMutation { $0.second = _setter(newValue) } }
|
|
}
|
|
|
|
/// A nanosecond or count of nanoseconds.
|
|
/// - note: This value is interpreted in the context of the calendar in which it is used.
|
|
public var nanosecond: Int? {
|
|
get { return _handle.map { _getter($0.nanosecond) } }
|
|
set { _applyMutation { $0.nanosecond = _setter(newValue) } }
|
|
}
|
|
|
|
/// A weekday or count of weekdays.
|
|
/// - note: This value is interpreted in the context of the calendar in which it is used.
|
|
public var weekday: Int? {
|
|
get { return _handle.map { _getter($0.weekday) } }
|
|
set { _applyMutation { $0.weekday = _setter(newValue) } }
|
|
}
|
|
|
|
/// A weekday ordinal or count of weekday ordinals.
|
|
/// Weekday ordinal units represent the position of the weekday within the next larger calendar unit, such as the month. For example, 2 is the weekday ordinal unit for the second Friday of the month.///
|
|
/// - note: This value is interpreted in the context of the calendar in which it is used.
|
|
public var weekdayOrdinal: Int? {
|
|
get { return _handle.map { _getter($0.weekdayOrdinal) } }
|
|
set { _applyMutation { $0.weekdayOrdinal = _setter(newValue) } }
|
|
}
|
|
|
|
/// A quarter or count of quarters.
|
|
/// - note: This value is interpreted in the context of the calendar in which it is used.
|
|
public var quarter: Int? {
|
|
get { return _handle.map { _getter($0.quarter) } }
|
|
set { _applyMutation { $0.quarter = _setter(newValue) } }
|
|
}
|
|
|
|
/// A week of the month or a count of weeks of the month.
|
|
/// - note: This value is interpreted in the context of the calendar in which it is used.
|
|
public var weekOfMonth: Int? {
|
|
get { return _handle.map { _getter($0.weekOfMonth) } }
|
|
set { _applyMutation { $0.weekOfMonth = _setter(newValue) } }
|
|
}
|
|
|
|
/// A week of the year or count of the weeks of the year.
|
|
/// - note: This value is interpreted in the context of the calendar in which it is used.
|
|
public var weekOfYear: Int? {
|
|
get { return _handle.map { _getter($0.weekOfYear) } }
|
|
set { _applyMutation { $0.weekOfYear = _setter(newValue) } }
|
|
}
|
|
|
|
/// The ISO 8601 week-numbering year of the receiver.
|
|
///
|
|
/// The Gregorian calendar defines a week to have 7 days, and a year to have 356 days, or 366 in a leap year. However, neither 356 or 366 divide evenly into a 7 day week, so it is often the case that the last week of a year ends on a day in the next year, and the first week of a year begins in the preceding year. To reconcile this, ISO 8601 defines a week-numbering year, consisting of either 52 or 53 full weeks (364 or 371 days), such that the first week of a year is designated to be the week containing the first Thursday of the year.
|
|
///
|
|
/// You can use the yearForWeekOfYear property with the weekOfYear and weekday properties to get the date corresponding to a particular weekday of a given week of a year. For example, the 6th day of the 53rd week of the year 2005 (ISO 2005-W53-6) corresponds to Sat 1 January 2005 on the Gregorian calendar.
|
|
/// - note: This value is interpreted in the context of the calendar in which it is used.
|
|
public var yearForWeekOfYear: Int? {
|
|
get { return _handle.map { _getter($0.yearForWeekOfYear) } }
|
|
set { _applyMutation { $0.yearForWeekOfYear = _setter(newValue) } }
|
|
}
|
|
|
|
/// Set to true if these components represent a leap month.
|
|
public var isLeapMonth: Bool? {
|
|
get { return _handle.map { $0.isLeapMonth } }
|
|
set {
|
|
_applyMutation {
|
|
// Technically, the underlying class does not support setting isLeapMonth to nil, but it could - so we leave the API consistent.
|
|
if let b = newValue {
|
|
$0.isLeapMonth = b
|
|
} else {
|
|
$0.isLeapMonth = false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Returns a `Date` calculated from the current components using the `calendar` property.
|
|
public var date: Date? {
|
|
if let d = _handle.map({$0.date}) {
|
|
return d as Date
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// MARK: - Generic Setter/Getters
|
|
|
|
/// Set the value of one of the properties, using an enumeration value instead of a property name.
|
|
///
|
|
/// The calendar and timeZone and isLeapMonth properties cannot be set by this method.
|
|
@available(OSX 10.9, iOS 8.0, *)
|
|
public mutating func setValue(_ value: Int?, for component: Calendar.Component) {
|
|
_applyMutation {
|
|
$0.setValue(_setter(value), forComponent: Calendar._toCalendarUnit([component]))
|
|
}
|
|
}
|
|
|
|
/// Returns the value of one of the properties, using an enumeration value instead of a property name.
|
|
///
|
|
/// The calendar and timeZone and isLeapMonth property values cannot be retrieved by this method.
|
|
@available(OSX 10.9, iOS 8.0, *)
|
|
public func value(for component: Calendar.Component) -> Int? {
|
|
return _handle.map {
|
|
$0.value(forComponent: Calendar._toCalendarUnit([component]))
|
|
}
|
|
}
|
|
|
|
// MARK: -
|
|
|
|
/// Returns true if the combination of properties which have been set in the receiver is a date which exists in the `calendar` property.
|
|
///
|
|
/// This method is not appropriate for use on `DateComponents` values which are specifying relative quantities of calendar components.
|
|
///
|
|
/// Except for some trivial cases (e.g., 'seconds' should be 0 - 59 in any calendar), this method is not necessarily cheap.
|
|
///
|
|
/// If the time zone property is set in the `DateComponents`, it is used.
|
|
///
|
|
/// The calendar property must be set, or the result is always `false`.
|
|
@available(OSX 10.9, iOS 8.0, *)
|
|
public var isValidDate: Bool {
|
|
return _handle.map { $0.isValidDate }
|
|
}
|
|
|
|
/// Returns true if the combination of properties which have been set in the receiver is a date which exists in the specified `Calendar`.
|
|
///
|
|
/// This method is not appropriate for use on `DateComponents` values which are specifying relative quantities of calendar components.
|
|
///
|
|
/// Except for some trivial cases (e.g., 'seconds' should be 0 - 59 in any calendar), this method is not necessarily cheap.
|
|
///
|
|
/// If the time zone property is set in the `DateComponents`, it is used.
|
|
@available(OSX 10.9, iOS 8.0, *)
|
|
public func isValidDate(in calendar: Calendar) -> Bool {
|
|
return _handle.map { $0.isValidDate(in: calendar) }
|
|
}
|
|
|
|
// MARK: -
|
|
|
|
public var hashValue : Int {
|
|
return _handle.map { $0.hash }
|
|
}
|
|
|
|
public var description: String {
|
|
return _handle.map { $0.description }
|
|
}
|
|
|
|
public var debugDescription: String {
|
|
return _handle.map { $0.debugDescription }
|
|
}
|
|
|
|
// MARK: - Bridging Helpers
|
|
|
|
private init(reference: NSDateComponents) {
|
|
_handle = _MutableHandle(reference: reference)
|
|
}
|
|
|
|
public static func ==(lhs : DateComponents, rhs: DateComponents) -> Bool {
|
|
// Don't copy references here; no one should be storing anything
|
|
return lhs._handle._uncopiedReference().isEqual(rhs._handle._uncopiedReference())
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// MARK: - Bridging
|
|
|
|
extension DateComponents : _ObjectiveCBridgeable {
|
|
public static func _getObjectiveCType() -> Any.Type {
|
|
return NSDateComponents.self
|
|
}
|
|
|
|
@_semantics("convertToObjectiveC")
|
|
public func _bridgeToObjectiveC() -> NSDateComponents {
|
|
return _handle._copiedReference()
|
|
}
|
|
|
|
public static func _forceBridgeFromObjectiveC(_ dateComponents: NSDateComponents, result: inout DateComponents?) {
|
|
if !_conditionallyBridgeFromObjectiveC(dateComponents, result: &result) {
|
|
fatalError("Unable to bridge \(_ObjectiveCType.self) to \(self)")
|
|
}
|
|
}
|
|
|
|
public static func _conditionallyBridgeFromObjectiveC(_ dateComponents: NSDateComponents, result: inout DateComponents?) -> Bool {
|
|
result = DateComponents(reference: dateComponents)
|
|
return true
|
|
}
|
|
|
|
public static func _unconditionallyBridgeFromObjectiveC(_ source: NSDateComponents?) -> DateComponents {
|
|
var result: DateComponents? = nil
|
|
_forceBridgeFromObjectiveC(source!, result: &result)
|
|
return result!
|
|
}
|
|
}
|
|
|