roberto tomás
roberto tomás

Reputation: 4697

How can I generate every date between two dates to a given granularity?

How can I generate every date between two dates to a given granularity?

I want to make this extension pad an array of Dates, which all must be at 00m, 15m, 30m, or 45m, so that there are no gaps. Optionally, setting a start and an end date, that were not in the original set (so you can have leading and trailing dates).

extension TimeSeries {
    var earliest: Date? {
        return timeSeries.map { $0.date }.min()
    }
    var latest: Date? {
        return timeSeries.map { $0.date }.max()

    }
    func pad (to repletion: Int, _ component: Calendar.Component, from: Date? = nil, to: Date? = nil) {
        guard let start = from ?? self.earliest else {
            print("no start date given and none available")
            return
        }
        guard let end = to ?? self.latest else {
            print("no end date given and none available")
            return
        }

        // magic happens here...
    }
}

Specifically, given:

[ Date/* 2018-01-16 01:15:00 */, Date/* 2018-01-16 01:45:00 */]

I want the array to become:

[ Date/* 2018-01-16 01:15:00 */,  Date/* 2018-01-16 01:30:00 */, Date/* 2018-01-16 01:45:00 */]

And if it was called like ts.pad(to: 15, .minutes, from: Date/* 2018-01-16 01:00:00 */, to: Date/* 2018-01-16 02:00:00 */ )

I want the array to become:

[ Date/* 2018-01-16 01:00:00 */, Date/* 2018-01-16 01:15:00 */,  Date/* 2018-01-16 01:30:00 */, Date/* 2018-01-16 01:45:00 */, Date/* 2018-01-16 02:00:00 */]

Upvotes: 0

Views: 135

Answers (2)

Robert Dresler
Robert Dresler

Reputation: 11210

Logic could be something like this. Create array with start date as first element. Then append dates with added components to last date until new date should be greater than end date

func pad(to repletion: Int, _ component: Calendar.Component, from: Date? = nil, to: Date? = nil) {

    guard let start = from ?? self.earliest, let end = to ?? self.latest else {
        print("no date given and none available")
        return
    }

    var components = DateComponents()
    components.setValue(repletion, for: component)
    let calendar = Calendar.current

    var dates = [start] // results

    while start < end {
        if let newDate = calendar.date(byAdding: components, to: dates.last!), 
           newDate <= end {
            dates.append(newDate)
        } else { break }
    }

}

Upvotes: 1

Joakim Danielson
Joakim Danielson

Reputation: 52108

Here is my variant, assuming period is given by start and end dates

let quarter: TimeInterval = 15 * 60
let dateInterval = DateInterval(start: start, end: end)

var date = start
var result = [Date]()
while dateInterval.contains(date) {
    result.append(date)
    date = date.addingTimeInterval(quarter)
}

Upvotes: 1

Related Questions