Ale*_*ler 53 iphone cocoa objective-c
比如我有
NSDate *curDate = [NSDate date];
它的价值是上午9:13.我没有使用curDate的年,月和日部分.
我想得到的是9:15时间值的日期; 如果我有时间价值9:16我想把它推进到9:20,依此类推.
我怎么能用NSDate做到这一点?
mkk*_*kko 56
这是我的解决方案:
NSTimeInterval seconds = round([date timeIntervalSinceReferenceDate]/300.0)*300.0;
NSDate *rounded = [NSDate dateWithTimeIntervalSinceReferenceDate:seconds];
我做了一些测试,它的速度是Voss解决方案的十倍.通过1M迭代,大约需要3.39秒.这一次在0.38秒内完成.J3RM的解决方案耗时0.50秒.内存使用量也应该是最低的.
并不是表现就是一切,但它是一个单行.您还可以使用除法和乘法轻松控制舍入.
编辑:要回答这个问题,您可以使用ceil正确的向上舍入:
NSTimeInterval seconds = ceil([date timeIntervalSinceReferenceDate]/300.0)*300.0;
NSDate *rounded = [NSDate dateWithTimeIntervalSinceReferenceDate:seconds];
编辑: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)
    }
}
Dus*_*oss 54
取分钟值,除以5向上舍入以获得下一个最高的5分钟单位,乘以5以便在几分钟内将其重新计算,并构建一个新的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];
Gre*_*egP 27
基于Chris'和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)
BJ *_*ler 27
Wowsers,我在这里看到了很多答案,但很多很长或很难理解,所以我会尝试投入2美分以防万一.该NSCalendar课程以安全和简洁的方式提供所需的功能.这是一个适合我的解决方案,没有乘以时间间隔秒,舍入或任何东西.NSCalendar考虑到闰日/年,以及其他时间和日期的怪异.(斯威夫特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()
NSDate如果需要,可以将其添加到扩展中,或者作为返回新NSDate实例的自由格式函数,无论您需要什么.希望这可以帮助任何需要它的人.  
Swift 3更新
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()
J3R*_*3RM 13
我认为这是最好的解决方案,但仅限于我的观点,基于之前的海报代码.轮到最近的5分钟标记.此代码应使用比日期组件解决方案少得多的内存.太棒了,谢谢你的指导.
+(NSDate *) dateRoundedDownTo5Minutes:(NSDate *)dt{
    int referenceTimeInterval = (int)[dt timeIntervalSinceReferenceDate];
    int remainingSeconds = referenceTimeInterval % 300;
    int timeRoundedTo5Minutes = referenceTimeInterval - remainingSeconds; 
    if(remainingSeconds>150)
    {/// round up
         timeRoundedTo5Minutes = referenceTimeInterval +(300-remainingSeconds);            
    }
    NSDate *roundedDate = [NSDate dateWithTimeIntervalSinceReferenceDate:(NSTimeInterval)timeRoundedTo5Minutes];
    return roundedDate;
}
小智 7
https://forums.developer.apple.com/thread/92399
请参阅链接以获取Apple员工的完整和详细答案。为了节省您的时间,解决方案:
let original = Date()
let rounded = Date(timeIntervalSinceReferenceDate: 
(original.timeIntervalSinceReferenceDate / 300.0).rounded(.toNearestOrEven) * 300.0)
小智 6
谢谢你的样品.下面我添加了一些代码到最接近的5分钟
 -(NSDate *)roundDateTo5Minutes:(NSDate *)mydate{
    // Get the nearest 5 minute block
    NSDateComponents *time = [[NSCalendar currentCalendar]
                              components:NSHourCalendarUnit | NSMinuteCalendarUnit
                              fromDate:mydate];
    NSInteger minutes = [time minute];
    int remain = minutes % 5;
    // if less then 3 then round down
    if (remain<3){
        // Subtract the remainder of time to the date to round it down evenly
        mydate = [mydate addTimeInterval:-60*(remain)];
    }else{
        // Add the remainder of time to the date to round it up evenly
        mydate = [mydate addTimeInterval:60*(5-remain)];
    }
    return mydate;
}
遗憾的是,这里的大多数回复都不完全正确(即使它们似乎对大多数用户来说效果都很好),因为它们要么依赖当前的活动系统日历作为公历(可能不是这种情况),要么依赖于OS X和iOS不会存在闰秒和/或总是会忽略闰秒.以下代码工作复制和粘贴,保证是正确的,并且没有做出这样的假设(因此,如果Apple改变闰秒支持,将来也不会破坏,因为在这种情况下NSCalendar也必须正确地支持它们):
{
    NSDate * date;
    NSUInteger units;
    NSCalendar * cal;
    NSInteger minutes;
    NSDateComponents * comp;
    // Get current date
    date = [NSDate date];
    // Don't rely that `currentCalendar` is a
    // Gregorian calendar that works the way we are used to.
    cal = [[NSCalendar alloc]
        initWithCalendarIdentifier:NSGregorianCalendar
    ];
    [cal autorelease]; // Delete that line if using ARC
    // Units for the day
    units = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
    // Units for the time (seconds are irrelevant)
    units |= NSHourCalendarUnit | NSMinuteCalendarUnit;
    // Split current date into components
    comp = [cal components:units fromDate:date];
    // Get the minutes,
    // will be a number between 0 and 59.
    minutes = [comp minute];
    // Unless it is a multiple of 5...
    if (minutes % 5) {
        // ... round up to the nearest multiple of 5.
        minutes = ((minutes / 5) + 1) * 5;
    }
    // Set minutes again.
    // Minutes may now be a value between 0 and 60,
    // but don't worry, NSCalendar knows how to treat overflows!
    [comp setMinute:minutes];
    // Convert back to date
    date = [cal dateFromComponents:comp];
}
如果当前时间已经是5分钟的倍数,则代码不会更改它.原始问题没有明确指出这个案例.如果代码总是向上舍入到下一个5分钟的倍数,只需删除测试if (minutes % 5) {,它将始终向上舍入.
@ipje的答案在接下来的 5 分钟内发挥了作用,但我需要更灵活的东西,并且我想摆脱所有神奇的数字。我找到了一个解决方案,感谢类似问题的答案
我的解决方案使用 Swift 5.2 并Measurement避免使用幻数:
extension UnitDuration {
    var upperUnit: Calendar.Component? {
        if self == .nanoseconds {
            return .second
        }
        if self == .seconds {
            return .minute
        }
        if self == .minutes {
            return .hour
        }
        if self == .hours {
            return .day
        }
        return nil
    }
}
extension Date {
    func roundDate(to value: Int, in unit: UnitDuration, using rule: FloatingPointRoundingRule, and calendar: Calendar = Calendar.current) -> Date? {
        guard unit != .picoseconds && unit != .nanoseconds,
            let upperUnit = unit.upperUnit else { return nil }
        let value = Double(value)
        let unitMeasurement = Measurement(value: value, unit: unit)
        let interval = unitMeasurement.converted(to: .seconds).value
        let startOfPeriod = calendar.dateInterval(of: upperUnit, for: self)!.start
        var seconds = self.timeIntervalSince(startOfPeriod)
        seconds = (seconds / interval).rounded(rule) * interval
        return startOfPeriod.addingTimeInterval(seconds)
    }
    func roundDate(toNearest value: Int, in unit: UnitDuration, using calendar: Calendar = Calendar.current) -> Date? {
        return roundDate(to: value, in: unit, using: .toNearestOrEven)
    }
    func roundDate(toNext value: Int, in unit: UnitDuration, using calendar: Calendar = Calendar.current) -> Date? {
        return roundDate(to: value, in: unit, using: .up)
    }
}
在我的操场上:
let calendar = Calendar.current
let date = Calendar.current.date(from: DateComponents(timeZone: TimeZone.current, year: 2020, month: 6, day: 12, hour: 00, minute: 24, second: 17, nanosecond: 577881))! // 12 Jun 2020 at 00:24
var roundedDate = date.roundDate(toNext: 5, in: .seconds)!
//"12 Jun 2020 at 00:24"
calendar.dateComponents([.nanosecond, .second, .minute, .hour, .day, .month], from: roundedDate) 
// month: 6 day: 12 hour: 0 minute: 24 second: 20 nanosecond: 0 isLeapMonth: false 
roundedDate = date.roundDate(toNearest: 5, in: .seconds)!
// "12 Jun 2020 at 00:24"
calendar.dateComponents([.nanosecond, .second, .minute, .hour, .day, .month], from: roundedDate)
// month: 6 day: 12 hour: 0 minute: 24 second: 15 nanosecond: 0 isLeapMonth: false 
roundedDate = date.roundDate(toNext: 5, in: .minutes)!
// "12 Jun 2020 at 00:25"
calendar.dateComponents([.nanosecond, .second, .minute, .hour, .day, .month], from: roundedDate)
// month: 6 day: 12 hour: 0 minute: 25 second: 0 nanosecond: 0 isLeapMonth: false 
roundedDate = date.roundDate(toNearest: 5, in: .minutes)!
// "12 Jun 2020 at 00:25"
calendar.dateComponents([.nanosecond, .second, .minute, .hour, .day, .month], from: roundedDate)
// month: 6 day: 12 hour: 0 minute: 25 second: 0 nanosecond: 0 isLeapMonth: false 
roundedDate = date.roundDate(toNext: 5, in: .hours)!
// "12 Jun 2020 at 05:00"
calendar.dateComponents([.nanosecond, .second, .minute, .hour, .day, .month], from: roundedDate)
// month: 6 day: 12 hour: 5 minute: 0 second: 0 nanosecond: 0 isLeapMonth: false 
roundedDate = date.roundDate(toNearest: 5, in: .hours)!
// "12 Jun 2020 at 00:00"
calendar.dateComponents([.nanosecond, .second, .minute, .hour, .day, .month], from: roundedDate)
// month: 6 day: 12 hour: 0 minute: 0 second: 0 nanosecond: 0 isLeapMonth: false 
| 归档时间: | 
 | 
| 查看次数: | 19717 次 | 
| 最近记录: |