SE-0329: Clock, Instant, Date, and Duration

I have been putting off the evaluation of the proposal to the last minute as I tend to do with all tasks I'm not relishing. I know that lots of work went into putting together the initial pitch, so I'm saddened to have to share that I feel that the proposal in the form in which it has come to review has not adequately reckoned with the concerns laid out during community discussion of that pitch.


First, a point of order on the process of this also—and I do hope the core team will address this in their review summary. During the pitch stage, multiple references were made to the "responsible parties" at Apple who have contributed to the design, such as the following:

To my knowledge, there hasn't been the promised reporting back, but that is not even my top concern here. Rather, I think we need to address the role of proposal authors and their relationship to the proposal.

It has been stated that an expectation is that authors should be available and responsive to the community during the stages of Swift Evolution, and by all measures the named authors have been. However, it has been made clear that several relevant design decisions here have been shaped by "responsible parties" unnamed with design constraints unstated. Their relationship to the proposal text has been just as authorial (in the sense of authorship commonly used in scientific and technical contexts, whether or not they have typed out any of the words contained in the document) as the named authors, as evidenced during the pitch phase when the discussion has turned to those areas over which these parties have exerted authorship and the named authors have become intermediaries promising to confer and report back.

It is obviously not possible fully to engage in a fluent discussion about design tradeoffs in this manner. I do not believe that it is in the spirit of the review process, nor adequate, that named authors should not among them have collective authorial control over all parts of the proposal. Put another way, relevant parties with authorial control were not readily available and engaging with the community during this process.

Some have said here that "decision are made by those who show up"; I think this is an imminently important cornerstone and principle of fairness in an open-source and transparent project. It should not be the case (in my view) that certain people have special dispensation to make decisions without showing up. If it is not possible for whatever organizational reason for "responsible parties" to participate like everyone else here, then I would argue that their proposal isn't ready to come to review or be incorporated into the Swift open-source project.


I agree substantially with @davedelong's feedback and am grateful that he took the time to write it out. I will name some specifics with which I utterly agree:

  • Regarding the presence of .minutes and .hours in Duration, I agree that they are attractive nuisances and would urge (as I did in the pitch phase) dropping them. It is overwhelmingly the natural thing to reach for clock.now + .hours(3) when you want something three hours from now, and it'd be wrong, and for that reason we should not be exposing an API in this form.

  • Enough has been said about Date's naming specifically, with which I agree. I would like to call out some points additionally which I don't believe have been said:

First, while it is certainly acceptable to weigh pros and cons and then come down against renaming or creating a distinct type (though I'd disagree), it is simply incorrect to characterize renaming as "needless churn for no clear advantage" (emphasis mine). Taken at face value, the authors are stating not that they have weighed pros and cons, but that they have dismissed this choice as having no pros, which discards vast swaths of feedback given. This goes back to my overall feedback that this proposal in its current form has not adequately reckoned with the feedback at the pitch phase.

Second, a central con (actually, the only con) listed besides "needless churn" in the proposal text is that having a type with a new name would lead users to have a quandary of "which type should I use." I and others have noted that the possibility of implicit conversion at API boundaries, exactly like CGFloat and an approach both initially mooted for a different type as part of this proposal and explicitly allowed for by the core team's previous guidance in this area, would address the points about both churn and user quandary. This does not seem to have been reckoned with even as an alternative.

As has been noted by all involved, there is going to be some sort of implicit conversion in the proposal as it is, an unavoidable consequence that arises from our general agreement that the underlying storage of the proposed type must be different from that of Foundation.Date. In the present proposal, this issue emerges with serialization behavior. Although I can accept that lossless serialization may not be a sine qua non, we should be careful here to note that the design as proposed injects uncertainty as to whether serialization will be lossless due to mismatches in Swift version. At least for me, reasoning about future and past Swift versions interacting at runtime is significantly more difficult than reasoning about implicit conversion at API boundaries, which is determined at compile time. I think the latter alternative is significantly more within the reasoning capacity (and, therefore, control) of the author at the time they're writing their code.

So, I'd urge consideration of implicit conversion among two distinct types as an alternative even to the "same-type-different-name" approach detailed by @Douglas_Gregor. If there is agreement on both different underlying representation and a different name for our future Date replacement, then for the reasons above I think allowing each type to keep its own serialization behavior and offering seamless conversion at API boundaries may be a better user experience while still addressing the churn-and-quandary problem cited by the authors.


I want to bring up an issue not mentioned by @davedelong or, unless I'm mistaken, anyone else in this review thread. And that's the issue of the design proposed with respect to leap seconds. The proposal states:

It has been considered that Date should account for leap seconds, however after much consideration this is viewed as perhaps too disruptive to the storage and serialization of Date and that it is better suited to leverage calendrical calculations such as those in Foundation to account for leap seconds since that falls in line more so with DateComponents than Date.

Despite the statement that this opinion is the product of "much consideration," it is almost verbatim unchanged from what was first expressed in the pitch thread when the question of leap seconds was brought up, even as much was revealed in the course of that discussion:

Initially, I took it at face value that the issue of leap seconds was purely calendrical based on the claim that Date would represent actual time elapsed since a reference date. If that were the case, then the authors are correct that adjusting dates for leap seconds is purely calendrical, as it would just be about converting seconds and nanoseconds elapsed to local dates and times.

However, it has been later clarified that there is no possibility for an implementation on Apple platforms actually to include leap seconds among the seconds elapsed since a reference date without hitting the file system or network; by necessity, the standard library must elide leap seconds—and, as @lorentey discovered, during the leap second the system's wall clock actually repeats the previous second (or as he put it, "silliness" that isn't even "sort of halfway-sensible").

While it may be true that we just have to accept a discontinuity on Apple platforms at present, during the pitch discussion, we also talked at some length about how this is not the case either for Linux or for Windows. In the case of Linux, clock_adjtime provides the information necessary to distinguish a repeated leap second from the prior second, and on Windows, the system wall clock has been entirely reworked (since some release of Windows 10) not to elide leap seconds.

It's simply not correct that not incurring a discontinuity during leap seconds (where supported by the platform) would be "too disruptive" to the storage and serialization of Date. Without any change in storage or serialization—that is, within the existing design where nanoseconds are stored as a UInt32 and ordinarily normalized to be less than 1 billion—it would be possible to use the range 1_000_000_000..<2_000_000_000 to indicate an inserted leap second based on information available from the Linux system wall clock. This can be deserialized correctly even on Apple platforms where the same value can't be generated, and with a little bit of care in the underlying implementation all operations on it should, to my understanding, just work.

I stress that this idea wasn't invented by me in the moment, but rather it has already been discussed elsewhere on the Internet by folks who have been trying to tackle this problem. It would not have taken much to discover it if the authors would have been moved to look, but nowhere in the text is there evidence that it has been considered. This goes back again to my overall impression that the review has not adequately reckoned with the concerns laid out during community discussion during the pitch phase.

That both Linux and Windows have made changes to mitigate the problem of leap second representation in their system wall clock is, to me, good supporting evidence that this is a relevant issue which needs to be accounted for even in the non-calendrical APIs available in Swift. The bare minimum, in my view, is that a type designed for the future should not be discarding the improvements already made in this area by the underlying system; rather, it should ideally gracefully accommodate them wherever available and in a way that future improvements on other platforms can similarly be incorporated without having to overhaul these types again.

Undoubtedly yes, and for many-faceted reasons.

See above. I share concerns with others regarding the trajectory (e.g., future users versus backwards compatibility) that is inherent to choices regarding sinking Date into the standard library with the design as proposed. Similarly, I have such concerns regarding leap second handling.

I have obviously needed to deal with time, but I do not have as much depth in this area as @davedelong and others. I have studied both the prior art detailed in the proposal text as well as looked at some of these same aspects in JavaScript, but not in enough detail to evaluate comparatively.

I put in some in-depth study in the pitch phase, and then read through the proposal text twice. My intention during this review period was to spend some time to study the proposal design in even greater detail and maybe even "noodle" with some alternatives, and to study up on prior art along the way. However—echoing again my overall appraisal of this proposal—it was extremely discouraging that in those areas where I did study up and put in great effort at feedback during the pitch stage, all of that effort was apparently dismissed in the proposal text without apparent consideration. It was sufficient to raise questions as to whether any further effort along these lines would be to any effect.

42 Likes