3

Im trying to create a function that receives:

-An StartDate (DATE).

-An EndDate (DATE).

Capable of iterate day by day printing the day in the format yyyy-MM-dd

But I'm getting the following error:

"Cannot invoke 'stride' with an argument list of type '(from: Date, to: Date, by: Int)'"

What have I tried?

My dates are conforming the strideable protocol

extension Date: Strideable {
    public func distance(to other: Date) -> TimeInterval {
        return other.timeIntervalSinceReferenceDate - self.timeIntervalSinceReferenceDate
    }

    public func advanced(by n: TimeInterval) -> Date {
        return self + n
    }
}

So I could use the stride Function

stride(from: <#T##Strideable#>, to: <#T##Strideable#>, by: <#T##Comparable & SignedNumeric#>)

On my ViewDidLoad in trying to run it

override func viewDidLoad() {
        super.viewDidLoad()
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy/MM/dd"
        let startDate = formatter.date(from: "2014/01/01")
        let endDate = formatter.date(from: "2019/03/31")
        let dayDurationInSeconds = 60*60*24

        for date in stride(from: startDate!, to: endDate!, by: dayDurationInSeconds) {
            print(date)
        }
}

What do I expect to see on my console?

2014-01-01
2014-01-02
2014-01-03
.........
2019-03-30
2019-03-31
James
  • 45
  • 7
  • Please read the [documentation](https://developer.apple.com/documentation/swift/strideable). There is an example to handle dates. – vadian Mar 31 '19 at 20:40
  • @vadian The documentation is very misleading. That isn't Foundation.Date. – Rob Napier Mar 31 '19 at 20:41
  • 2
    I wouldn't recommend extending public types with public protocols. Someone else could do the same thing, and it's undefined which of the two protocol conformances is used. You should only extend your own types with public protocols, or public types with your own protocols, which ensures that no one else has the access to do the same. – Alexander Apr 01 '19 at 04:18

2 Answers2

8

Your code doesn't compile because you're striding by integers, but you've defined your Stride to be TimeInterval. It would do most of what you expect if you fix the type of dayDurationInSeconds:

let dayDurationInSeconds: TimeInterval = 60*60*24

But this will give you completely incorrect results, because not every day is 86,400 seconds long. DST alters the day length twice a year in location-dependent ways.

The correct way to perform date math is with Calendar. If you're not using Calendar, you can't use anything that isn't explicitly in seconds.

What you may want is something more like this, which enumerates all the midnights (UTC) between the dates in question. Remember, a Date in Foundation is not a "date." It's a precise instant in time. If you really do want to work with "dates", what you want are DateComponents.

let formatter = DateFormatter()
formatter.dateFormat = "yyyy/MM/dd"
let startDate = formatter.date(from: "2014/01/01")!
let endDate = formatter.date(from: "2019/03/31")!

var calendar = Calendar(identifier: .gregorian)
calendar.timeZone = TimeZone(identifier: "UTC")!

calendar.enumerateDates(startingAfter: startDate,
                        matching: DateComponents(hour: 0, minute: 0, second:0),
                        matchingPolicy: .nextTime) { (date, _, stop) in
                            guard let date = date, date < endDate else {
                                stop = true
                                return
                            }

                            print(date)
}
Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • Awesome, I was missing that to compile. I will consider to perform it now with Calendar, to do it the correct way. Thanks!! – James Mar 31 '19 at 20:44
0

As of 2023 Date is Stridable right from Foundation with Stride = TimeInterval.

let now = Date()
let dayAfterNow = Date().addingTimeInterval(86400)
// You can stride it to an array
let dateArr : [Date] = Array(stride(from: now, to: dayAfterNow, by: 60))
// ... or use striding for a loop directly
for date in stride(from: now, to: dayAfterNow, by: 3600) {
    print(date)
}

But as @Rob said be careful with such kind of date processing because not all days have same number of seconds. And this is not the only issue with dates.

Paul B
  • 3,989
  • 33
  • 46