Created
October 30, 2018 10:54
-
-
Save casperzandbergenyaacomm/83c6a585073fd7da2e1fbb97c9bcd38a 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.index(of: component) else { | |
fatalError("Wrong component") | |
} | |
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
Now maintained at https://gist.github.com/Amzd/8c60d01ade230197cd922d91434c2ac6