[Idea] Represent a point in time as a Swift immutable scalar type TimePoint


(Steve Weller) #1

Proposal

Represent a point in time as a Swift immutable scalar type TimePoint

Motivation

The representation of time and calculations involving time are fundamental to the correct functioning of all computer systems. If the language can express and manipulate points in time in a consistent and well-defined way, then the user will make fewer programming errors, the reliability and security of the system will be improved, and the scope of applications for that language will increase.

Representing and manipulating points in time has historically been an error-prone endeavor. Problems include:

* Precision: lack of or unknown stored precision, loss during calculations, floating point quirks
* Range: Underflow or overflow during calculation due to unexpectedly small range or unsigned representation
* Lack of built-in representations: distant past and distant future usually require values with special meaning
* Use of inappropriate operators on scalar types that are used to store a representation of a point in time

Proposed Solution

The Swift language should provide an immutable scalar type TimePoint that can represent only a point in time. Additionally it should provide a mutable signed scalar type TimeOffset that can represent only the difference between two TimePoints.

TimePoint is approximated by the following enumeration:

enum TimePoint : Strideable, RawRepresentable, Hashable {
    case DistantPast,
    case DistantFuture,
    case At(Int64, UInt64) // Seconds, nanos
}

TimePoint is similar to NSDate. However, its underying storage strategy is hidden from the user. To access the value, rawValue must be called to get a tuple (seconds: Int64, nanos: UInt64).

TimePoint provides the guarantee that it has sufficient resolution and range for all practical purposes (precision to nanos worst case, range of the order of the age of the universe).

The Stride of a TimePoint is of signed type TimeOffset. TimeOffset is approximated by the following struct:

struct TimeOffset : Comparable, RawRepresentable, Hashable {
    var seconds:Int64
    var nanos: UInt64
}

The compiler is aware of the meaning of .DistantFuture and .DistantPast and can warn of inappropriate or nonsensical use. For example, the following can never be true:

if t > TimePoint.DistantFuture { return }

Since .DistantFuture and .DistantPast are not special values, TimePoint behaves as expected across its entire range.

The underlying storage can be made efficient since it is opaque. Since common, practical points in time are specified to units larger than nanos, and they do not need the full range, many zero or fixed bit values can be encoded into a small space, while rare or impractical points in time can still be faithfuly recorded.

TimePoint and TimeOffset have appropriate initializers, getters, and methods (TBD) to allow them to interoperate with other types.