回合时间到最近的30秒

时间:2017-06-24 13:34:33

标签: swift

我有一个应用程序,显示每30秒到期的数据(确切地说,在h / m / s 11:30:00,11:30:30,11:31:00等)。

我可以获得当前时间,但我不确定如何计算从现在到最近的30秒之间的时间。

我发现的任何内容都在Objective-C中,而且我无法转换它。

这是我尝试的内容:

func nearestThirtySeconds() -> Date? {
        var components = NSCalendar.current.dateComponents([.second], from: self)
        let second = components.second ?? 30
        components.second = second >= 30 ? 60 - second : -second
        return Calendar.current.date(byAdding: components, to: self)
    }

但这会返回最近的分钟(我想,它总是会返回一分钟)

有什么想法吗?

4 个答案:

答案 0 :(得分:7)

您可以将秒数舍入到最接近的30的倍数, 然后添加圆角和原始之间的差异 价值到日期:

extension Date {
    func nearestThirtySeconds() -> Date {
        let cal = Calendar.current
        let seconds = cal.component(.second, from: self)
        // Compute nearest multiple of 30:
        let roundedSeconds = lrint(Double(seconds) / 30) * 30
        return cal.date(byAdding: .second, value: roundedSeconds - seconds, to: self)!
    }
}

这应该足以显示圆形时间,但它 不准确:Date也包括小数秒,所以 例如“11:30:10.123”将变为“11:30:00.123”而不是“11:30:00.000”。这是解决该问题的另一种方法:

extension Date {
    func nearestThirtySeconds() -> Date {
        let cal = Calendar.current
        let startOfMinute = cal.dateInterval(of: .minute, for: self)!.start
        var seconds = self.timeIntervalSince(startOfMinute)
        seconds = (seconds / 30).rounded() * 30
        return startOfMinute.addingTimeInterval(seconds)
    }
}

现在seconds是自当前分钟开始以来的时间间隔 (包括小数秒)。该间隔四舍五入到最近 30的倍数,并添加到分钟的开头。

答案 1 :(得分:5)

我用Martin R的答案写了一个更通用的版本,可以在任何时间段取整。

答案已过时,只能随着时间的流逝,请检查要点以获取最新版本。

https://gist.github.com/casperzandbergenyaacomm/83c6a585073fd7da2e1fbb97c9bcd38a

extension Date {

    func rounded(on amount: Int, _ component: Calendar.Component) -> Date {
        let cal = Calendar.current
        let value = cal.component(component, from: self)

        // Compute nearest multiple of amount:
        let roundedValue = lrint(Double(value) / Double(amount)) * amount
        let newDate = cal.date(byAdding: component, value: roundedValue - value, to: self)!

        return newDate.floorAllComponents(before: component)
    }

    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).forEach { roundComponent in
            let value = cal.component(roundComponent, from: date) * -1
            date = cal.date(byAdding: roundComponent, value: value, to: date)!
        }

        return date
    }
}

要舍入到x分钟,您还需要对秒进行下限,因此它也包含我编写的下限方法。

使用方法:

let date: Date = Date() // 10:16:34
let roundedDate0 = date.rounded(on: 30, .second) // 10:16:30
let roundedDate1 = date.rounded(on: 15, .minute) // 10:15:00 
let roundedDate2 = date.rounded(on: 1, .hour)    // 10:00:00 

答案 2 :(得分:0)

let now = Date()
var timeInterval = now.timeIntervalSinceReferenceDate
timeInterval += 30 - timeInterval.truncatingRemainder(dividingBy: 30)
let rounded = Date(timeIntervalSinceReferenceDate: timeInterval)
print("\(now) rounded to nearest 30 seconds is \(rounded)")

答案 3 :(得分:-1)

有一个名为'SwiftDate'的Cocoapod,非常适合可以应用于Date()实例的日期格式和操作。

如何使用日期舍入方法的示例:

let date = Date()                       // 2018-10-01 23:05:29
date.dateRoundedAt(at: .toFloor5Mins)   // 2018-10-01 23:05:00
date.dateRoundedAt(at: .toCeil5Mins)    // 2018-10-01 23:10:00
date.dateRoundedAt(at: .toFloorMins(1)) // 2018-10-01 23:05:00
date.dateRoundedAt(at: .toCeilMins(1))  // 2018-10-01 23:06:00

(作为参考,请查看https://cocoapods.org/pods/SwiftDate上的文档)