Value
is perhaps the complicated part of the Time
package. It represents "a value that can be understood as being calendrically significant".
A more colloquial definition might be: "If you can point to it on a calendar or clock, it's a Value
".
In order to accomplish this, Value
defines two generic parameters, called Smallest
and Largest
. These parameters must be Unit
-conforming types, of which there are current 8: Era
, Year
, Month
, Day
, Hour
, Minute
, Second
, Nanosecond
.
For example, a Value<Day, Era>
is value that represents all calendar components in the Day ... Era
range, namely Day
, Month
, Year
, and Era
.
All calendar values that refer to "concrete" dates as humans understand them have an "upper bound" of Era
. Thus, Time
also defines a convenient typealias
to make working with these "absolutely defined" values a bit easier:
public typealias Absolute<U> = Value<U, Era>
When working with the Time
API, you will frequently encounter "Absolute" values. These values simply correspond to one and only one possible position on a calendar. For example, there is one and only one "28 February 2020 CE".
The "best" way to create Values
is via your Clock
. However, apps frequently deal with timestamp values that come from serialized data, such as via a network request or in UserDefaults
and so on.
So, Values
can also be created using certain initializers:
let aDate: Date = ...
// this will create a value representing the "day that contains aDate, according to the provided region"
// in essence, the time components of the Date are discarded
let dayValue = Absolute<Day>(region: .current, date: aDate)
Values
can also be created using DateComponents
, or via individual calendar values:
let components: DateComponents = ...
let dayValue = try Absolute<Day>(region: .current, unsafeDateComponents: components)
This sort of initialization performs a strict initialization. If it is passed DateComponents
of {year: 2020, month: 2, day: 31}
, it will throw an error indicating the date components do not represent a "real" calendar value.
With an Absolute
value, you can retrieve its constituent parts, such as:
let today: Absolute<Day> = myClock.today()
let year = today.year // ex: 2020
let month = today.month // ex: 2
let day = today.day // ex: 28
The generic parameters prevent you from retrieving unrepresented components:
let today: Absolute<Day> = myClock.today()
// will not compile, because "today" does not represent hours
let hour = today.hour
Values
can be mutated to form new values using the adjustment API.
You can find the difference between two values using the difference API.
You can iterate over sub-values using the iteration API.
You can turn a Value
into a human-readable string using the formatting API.