Skip to content

Commit 2ea76c3

Browse files
authored
Add an HTTP format style for both Date and DateComponents (#1127)
* Add an HTTP format style for both `Date` and `DateComponents`. * Correct the comments to properly use DateComponents type * Use default values instead of crashing when formatting date components with missing or invalid fields * Use 59 seconds instead of 0 for leap second of 60 - this results in being off by only 1 second in this case instead of 59. * Address some review feedback
1 parent 4c021b6 commit 2ea76c3

File tree

6 files changed

+807
-175
lines changed

6 files changed

+807
-175
lines changed

Sources/FoundationEssentials/Calendar/Calendar.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,19 @@ public struct Calendar : Hashable, Equatable, Sendable {
681681
return dc
682682
}
683683

684+
/// Same as `dateComponents:from:` but uses the more efficient bitset form of ComponentSet.
685+
/// Prefixed with `_` to avoid ambiguity at call site with the `Set<Component>` method.
686+
internal func _dateComponents(_ components: ComponentSet, from date: Date, in timeZone: TimeZone) -> DateComponents {
687+
var dc = _calendar.dateComponents(components, from: date.capped, in: timeZone)
688+
689+
// Fill out the Calendar field of dateComponents, if requested.
690+
if components.contains(.calendar) {
691+
dc.calendar = self
692+
}
693+
694+
return dc
695+
}
696+
684697
/// Returns all the date components of a date, as if in a given time zone (instead of the `Calendar` time zone).
685698
///
686699
/// The time zone overrides the time zone of the `Calendar` for the purposes of this calculation.

Sources/FoundationEssentials/Calendar/Date+FormatStyle.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,29 @@ extension Date {
5555
}
5656
#endif // FOUNDATION_FRAMEWORK
5757
}
58+
59+
@available(FoundationPreview 6.2, *)
60+
extension DateComponents {
61+
/// Converts `self` to its textual representation.
62+
/// - Parameter format: The format for formatting `self`.
63+
/// - Returns: A representation of `self` using the given `format`. The type of the representation is specified by `FormatStyle.FormatOutput`.
64+
public func formatted<F: FormatStyle>(_ format: F) -> F.FormatOutput where F.FormatInput == DateComponents {
65+
format.format(self)
66+
}
67+
68+
// Parsing
69+
/// Creates a new `DateComponents` by parsing the given representation.
70+
/// - Parameter value: A representation of a date. The type of the representation is specified by `ParseStrategy.ParseInput`.
71+
/// - Parameters:
72+
/// - value: A representation of a date. The type of the representation is specified by `ParseStrategy.ParseInput`.
73+
/// - strategy: The parse strategy to parse `value` whose `ParseOutput` is `DateComponents`.
74+
public init<T: ParseStrategy>(_ value: T.ParseInput, strategy: T) throws where T.ParseOutput == Self {
75+
self = try strategy.parse(value)
76+
}
77+
78+
/// Creates a new `DateComponents` by parsing the given string representation.
79+
@_disfavoredOverload
80+
public init<T: ParseStrategy, Value: StringProtocol>(_ value: Value, strategy: T) throws where T.ParseOutput == Self, T.ParseInput == String {
81+
self = try strategy.parse(String(value))
82+
}
83+
}

0 commit comments

Comments
 (0)