-
-
Save Amzd/8c60d01ade230197cd922d91434c2ac6 to your computer and use it in GitHub Desktop.
Rounding of date and time
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
extension Date { | |
/// Returns date where **-component** is rounded to its closest | |
/// multiple of **-amount**. Warning: month and day start at 1 | |
/// so round(to: 6, .month) will either return month 1 or 7! | |
func round(to amount: Int, _ component: Calendar.Component) -> Date { | |
let cal = Calendar.current | |
var value = cal.component(component, from: self) | |
if [.month, .day].contains(component) { | |
// Months and days start at 1, time/year starts at 0 | |
value -= 1 | |
} | |
// Compute nearest multiple of amount | |
let fraction = Double(value) / Double(amount) | |
let roundedValue = Int(fraction.rounded()) * amount | |
let newDate = cal.date(byAdding: component, value: roundedValue - value, to: self)! | |
return newDate.floorAllComponents(before: component) | |
} | |
/// Returns date where all components before paramater are set to | |
/// their beginning value; day and month to 1 and everything else | |
/// to 0 | |
func floorAllComponents(before component: Calendar.Component) -> Date { | |
// All components to round ordered by length | |
let components = [Calendar.Component.year, .month, .day, .hour, .minute, .second, .nanosecond] | |
guard let index = components.firstIndex(of: component) else { | |
assertionFailure("Unsupported component") | |
return self | |
} | |
let cal = Calendar.current | |
var date = self | |
components.suffix(from: index + 1).reversed().forEach { roundComponent in | |
var value = cal.component(roundComponent, from: date) * -1 | |
if [.month, .day].contains(roundComponent) { | |
// Months and days start at 1, time/year starts at 0 | |
value += 1 | |
} | |
date = cal.date(byAdding: roundComponent, value: value, to: date)! | |
} | |
return date | |
} | |
init?(_ string: String, format: String) { | |
guard let date = DateFormatter(format).date(from: string) else { | |
return nil | |
} | |
self = date | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extension DateFormatter { | |
convenience init(_ dateFormat: String) { | |
self.init() | |
self.dateFormat = dateFormat | |
timeZone = Calendar.current.timeZone | |
locale = Calendar.current.locale | |
} | |
convenience init(date: Style, time: Style) { | |
self.init() | |
dateStyle = date | |
timeStyle = time | |
timeZone = Calendar.current.timeZone | |
locale = Calendar.current.locale | |
} | |
} | |
let f = DateFormatter("yyyy-MM-dd HH:mm:ss") | |
let date = f.date(from: "2018-2-5 16:30:15")! | |
var floorDates = [Date]() | |
floorDates.append(date.floorAllComponents(before: .second)) // 2018-02-05 16:30:15 | |
floorDates.append(date.floorAllComponents(before: .minute)) // 2018-02-05 16:30:00 | |
floorDates.append(date.floorAllComponents(before: .hour)) // 2018-02-05 16:00:00 | |
floorDates.append(date.floorAllComponents(before: .day)) // 2018-02-05 00:00:00 | |
floorDates.append(date.floorAllComponents(before: .month)) // 2018-02-01 00:00:00 | |
floorDates.append(date.floorAllComponents(before: .year)) // 2018-01-01 00:00:00 | |
print("Floor") | |
floorDates.forEach { date in | |
print(f.string(from: date)) | |
} | |
var roundDates = [Date]() | |
roundDates.append(f.date(from: "2018-2-1 16:30:15")!.round(to: 30, .second)) // 2018-02-01 16:30:30 | |
roundDates.append(f.date(from: "2018-2-1 16:30:14")!.round(to: 30, .second)) // 2018-02-01 16:30:00 | |
roundDates.append(f.date(from: "2018-2-1 16:30:15")!.round(to: 20, .minute)) // 2018-02-01 16:40:00 | |
roundDates.append(f.date(from: "2018-2-1 16:29:15")!.round(to: 20, .minute)) // 2018-02-01 16:20:00 | |
roundDates.append(f.date(from: "2018-3-1 16:30:15")!.round(to: 6, .month)) // 2018-01-01 00:00:00 | |
roundDates.append(f.date(from: "2018-4-1 16:30:15")!.round(to: 6, .month)) // 2018-07-01 00:00:00 | |
roundDates.append(f.date(from: "2018-2-5 16:30:15")!.round(to: 10, .day)) // 2018-01-01 00:00:00 | |
roundDates.append(f.date(from: "2018-2-6 16:30:15")!.round(to: 10, .day)) // 2017-11-01 00:00:00 | |
roundDates.append(f.date(from: "2018-2-1 16:30:15")!.round(to: 10, .year)) // 2020-01-01 00:00:00 | |
roundDates.append(f.date(from: "2018-2-1 16:30:15")!.round(to: 9, .hour)) // 2018-02-01 18:00:00 | |
print("Round") | |
roundDates.forEach { date in | |
print(f.string(from: date)) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment