1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2020 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
//
//===----------------------------------------------------------------------===//
#if canImport(FoundationEssentials)
import FoundationEssentials
#endif
extension Date {
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
public struct IntervalFormatStyle : Codable, Hashable, Sendable {
public typealias DateStyle = Date.FormatStyle.DateStyle
public typealias TimeStyle = Date.FormatStyle.TimeStyle
public var locale: Locale
public var timeZone: TimeZone
public var calendar: Calendar
// Internal
internal var symbols = Date.FormatStyle.DateFieldCollection()
/// Creates a new `FormatStyle` with the given configurations.
/// - Parameters:
/// - date: The style for formatting the date part of the given date pairs. Note that if `.omitted` is specified, but the date interval spans more than one day, a locale-specific fallback will be used.
/// - time: The style for formatting the time part of the given date pairs.
/// - locale: The locale to use when formatting date and time values.
/// - calendar: The calendar to use for date values.
/// - timeZone: The time zone with which to specify date and time values.
/// - Important: Always specify the date length, time length, or the date components to be included in the formatted string with the symbol modifiers. Otherwise, an empty string will be returned when you use the instance to format an object.
/// - Note: If specifying the date fields, and the `DateInterval` range is larger than the specified units, a locale-specific fallback will be used.
/// - Example: for the range 2010-03-04 07:56 - 2010-03-08 16:11 (4 days, 8 hours, 15 minutes), specifying `.hour().minute()` will produce
/// - for en_US, "3/4/2010 7:56 AM - 3/8/2010 4:11 PM"
/// - for en_GB, "4/3/2010 7:56 - 8/3/2010 16:11"
public init(date: DateStyle? = nil, time: TimeStyle? = nil, locale: Locale = .autoupdatingCurrent, calendar: Calendar = .autoupdatingCurrent, timeZone: TimeZone = .autoupdatingCurrent) {
self.locale = locale
self.calendar = calendar
self.timeZone = timeZone
if let dateStyle = date {
self.symbols = self.symbols.collection(date: dateStyle)
}
if let timeStyle = time {
self.symbols = self.symbols.collection(time: timeStyle)
}
}
// MARK: - FormatStyle conformance
public func format(_ v: Range<Date>) -> String {
guard let formatter = ICUDateIntervalFormatter.formatter(for: self), let result = formatter.string(from: v) else {
return "\(v.lowerBound.description) - \(v.upperBound.description)"
}
return result
}
public func locale(_ locale: Locale) -> Self {
var new = self
new.locale = locale
return new
}
}
}
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
extension Date.IntervalFormatStyle : FormatStyle {}
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
extension Date.IntervalFormatStyle {
public typealias Symbol = Date.FormatStyle.Symbol
public func year() -> Self {
var new = self
new.symbols.year = .defaultDigits
return new
}
public func month(_ format: Symbol.Month = .abbreviated) -> Self {
var new = self
new.symbols.month = format.option
return new
}
public func day() -> Self {
var new = self
new.symbols.day = .defaultDigits
return new
}
public func weekday(_ format: Symbol.Weekday = .abbreviated) -> Self {
var new = self
new.symbols.weekday = format.option
return new
}
public func hour(_ format: Symbol.Hour = .defaultDigits(amPM: .abbreviated)) -> Self {
var new = self
new.symbols.hour = format.option
return new
}
public func minute() -> Self {
var new = self
new.symbols.minute = .defaultDigits
return new
}
public func second() -> Self {
var new = self
new.symbols.second = .defaultDigits
return new
}
public func timeZone(_ format: Symbol.TimeZone = .genericName(.short)) -> Self {
var new = self
new.symbols.timeZoneSymbol = format.option
return new
}
}
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
public extension FormatStyle where Self == Date.IntervalFormatStyle {
static var interval: Self {
return Date.IntervalFormatStyle()
}
}
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
extension Range where Bound == Date {
/// Formats the date range as an interval.
public func formatted() -> String {
Date.IntervalFormatStyle().format(self)
}
/// Formats the date range using the specified date and time format styles.
public func formatted(date: Date.IntervalFormatStyle.DateStyle, time: Date.IntervalFormatStyle.TimeStyle) -> String {
Date.IntervalFormatStyle(date: date, time: time).format(self)
}
/// Formats the date range using the specified style.
public func formatted<S>(_ style: S) -> S.FormatOutput where S : FormatStyle, S.FormatInput == Range<Date> {
style.format(self)
}
}
|