For example I have
NSDate *curDate = [NSDate date];
and its value is 9:13 am. I am not using year, month and day parts of curDate.
What I want to get is date with 9:15 time value; If I have time value 9:16 I want to advance it to 9:20 and so on.
How can I do that with NSDate?
Here's my solution:
NSTimeInterval seconds = round([date timeIntervalSinceReferenceDate]/300.0)*300.0;
NSDate *rounded = [NSDate dateWithTimeIntervalSinceReferenceDate:seconds];
I did some testing and it is about ten times as fast as Voss's solution. With 1M iterations it took about 3.39 seconds. This one performed in 0.38 seconds. J3RM's solution took 0.50 seconds. Memory usage should be the lowest also.
Not that the performance is everything but it's a one-liner. Also you can easily control the rounding with division and multiplication.
EDIT: To answer the question, you can use ceil
to round up properly:
NSTimeInterval seconds = ceil([date timeIntervalSinceReferenceDate]/300.0)*300.0;
NSDate *rounded = [NSDate dateWithTimeIntervalSinceReferenceDate:seconds];
EDIT: An extension in Swift:
public extension Date {
public func round(precision: TimeInterval) -> Date {
return round(precision: precision, rule: .toNearestOrAwayFromZero)
}
public func ceil(precision: TimeInterval) -> Date {
return round(precision: precision, rule: .up)
}
public func floor(precision: TimeInterval) -> Date {
return round(precision: precision, rule: .down)
}
private func round(precision: TimeInterval, rule: FloatingPointRoundingRule) -> Date {
let seconds = (self.timeIntervalSinceReferenceDate / precision).rounded(rule) * precision;
return Date(timeIntervalSinceReferenceDate: seconds)
}
}
Take the minute value, divide by 5 rounding up to get the next highest 5 minute unit, multiply to 5 to get that back into in minutes, and construct a new NSDate.
NSDateComponents *time = [[NSCalendar currentCalendar]
components:NSHourCalendarUnit | NSMinuteCalendarUnit
fromDate:curDate];
NSInteger minutes = [time minute];
float minuteUnit = ceil((float) minutes / 5.0);
minutes = minuteUnit * 5.0;
[time setMinute: minutes];
curDate = [[NSCalendar currentCalendar] dateFromComponents:time];
How about this based on Chris' and swift3
import UIKit
enum DateRoundingType {
case round
case ceil
case floor
}
extension Date {
func rounded(minutes: TimeInterval, rounding: DateRoundingType = .round) -> Date {
return rounded(seconds: minutes * 60, rounding: rounding)
}
func rounded(seconds: TimeInterval, rounding: DateRoundingType = .round) -> Date {
var roundedInterval: TimeInterval = 0
switch rounding {
case .round:
roundedInterval = (timeIntervalSinceReferenceDate / seconds).rounded() * seconds
case .ceil:
roundedInterval = ceil(timeIntervalSinceReferenceDate / seconds) * seconds
case .floor:
roundedInterval = floor(timeIntervalSinceReferenceDate / seconds) * seconds
}
return Date(timeIntervalSinceReferenceDate: roundedInterval)
}
}
// Example
let nextFiveMinuteIntervalDate = Date().rounded(minutes: 5, rounding: .ceil)
print(nextFiveMinuteIntervalDate)
Wowsers, I see a lot of answers here, but many are long or difficult to understand, so I'll try to throw in my 2 cents in case it helps. The NSCalendar
class provides the functionality needed, in a safe and concise manner. Here is a solution that works for me, without multiplying time interval seconds, rounding, or anything. NSCalendar
takes into account leap days/years, and other time and date oddities. (Swift 2.2)
let calendar = NSCalendar.currentCalendar()
let rightNow = NSDate()
let interval = 15
let nextDiff = interval - calendar.component(.Minute, fromDate: rightNow) % interval
let nextDate = calendar.dateByAddingUnit(.Minute, value: nextDiff, toDate: rightNow, options: []) ?? NSDate()
It can be added to an extension on NSDate
if needed, or as a free-form function returning a new NSDate
instance, whatever you need. Hope this helps anyone who needs it.
Swift 3 Update
let calendar = Calendar.current
let rightNow = Date()
let interval = 15
let nextDiff = interval - calendar.component(.minute, from: rightNow) % interval
let nextDate = calendar.date(byAdding: .minute, value: nextDiff, to: rightNow) ?? Date()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With