[Pitch] Make `Date` strideable

Recently I was looking at some Apple sample code that uses Date and it had this:

let oneMinute: TimeInterval = 60
var currentDate = Date()
var entries: [SimpleEntry] = []
        
while currentDate < endDate {
    let relevance = TimelineEntryRelevance(score: Float(selectedCharacter.healthLevel))
    let entry = SimpleEntry(date: currentDate, relevance: relevance, character: selectedCharacter)
            
    currentDate += oneMinute
    entries.append(entry)
}

Which I rewrote as this:

let entries: [SimpleEntry] = stride(from: Date(), to: selectedCharacter.fullHealthDate, by: 60.0).map {
     SimpleEntry(date: $0, character: selectedCharacter, relevance: TimelineEntryRelevance(score: Float(selectedCharacter.healthLevel)))
}

Which I liked a lot better, but it only worked because I added this category:

extension Date : Strideable {
    public dynamic func distance(to other: Self) -> TimeInterval {
        other.timeIntervalSinceReferenceDate - self.timeIntervalSinceReferenceDate
    }
     public dynamic func advanced(by n: TimeInterval) -> Self {
        Date(timeIntervalSinceReferenceDate: self.timeIntervalSinceReferenceDate + n)
    }
}

So, I thought I'd ask, can Date be made Strideable in the Swift stdlib? Because it sure seems neat to me.

I know there are efforts afoot to redo time and stuff, but since Date has been ingrained into the system for so long I figure we might as well make it easier to deal with

-Wil

1 Like

Date is a part of Foundation and not the standard library, with the consequence that it’s not subject to the Swift Evolution process.

As of iOS 13, Apple added conformance of Date to Strideable:

That's odd, on my machine I was getting "Date isn't Strideable" errors. Hrm.

What deployment target were you using?

Foundation.Date has all the requirements of Strideable, but it doesn't conform yet: FB9452917.

The following changes would be needed:

  • move the existing availability (iOS 13, etc.) to each individual requirement.

  • add the new availability (iOS 9999 == Next) and the protocol conformance.

-@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
-extension Date {
 
+@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
+extension Date: Strideable {
 
+    @available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
     public typealias Stride = TimeInterval
 
+    @available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
     public func distance(to: Date) -> TimeInterval
 
+    @available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
     public func advanced(by: TimeInterval) -> Date
 }

Huh, I guess I stand corrected.

Wouldn’t the only change needed be as follows:

+@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
+extension Date: Strideable { }
1 Like

That should work too, but it might be unusual to have the requirements in one extension, and the conformance in another (empty) extension.

The style guide for the standard library doesn't allow inheritance of availability, but Foundation has a different style guide.

Conformance availability was implemented in Swift 5.3 or 5.4, so there should probably be an audit of Foundation (and the standard library) to see which other conformances can be added.