Reputation: 4697
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
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
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