Skip to content

Instantly share code, notes, and snippets.

@Amzd
Forked from casperzandbergenyaacomm/DateRounding.swift
Created June 2, 2021 08:58
Show Gist options
  • Save Amzd/8c60d01ade230197cd922d91434c2ac6 to your computer and use it in GitHub Desktop.
Save Amzd/8c60d01ade230197cd922d91434c2ac6 to your computer and use it in GitHub Desktop.
Rounding of date and time
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
}
}
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