Найдите разницу в секундах между NSDates как целое число, используя Swift

Я пишу фрагмент кода, в котором хочу определить время удержания кнопки. Для этого я записал NSDate() при нажатии кнопки и попытался использовать функцию timeIntervalSinceDate при отпускании кнопки. Кажется, это работает, но я не могу найти способ распечатать результат или переключить его на целое число.

var timeAtPress = NSDate() 

@IBAction func pressed(sender: AnyObject) {
    println("pressed")
    timeAtPress = NSDate()
}

@IBAction func released(sender: AnyObject) {
    println("released")
    var elapsedTime = NSDate.timeIntervalSinceDate(timeAtPress)
    duration = ???
}

Я видел несколько похожих вопросов, но я не знаю C, поэтому мне было трудно понять данные ответы. Если есть более эффективный способ узнать, как долго кнопка удерживалась нажатой, я открыт для предложений. Заранее спасибо.


person Erik    schedule 28.10.2014    source источник


Ответы (7)


Ваша попытка вычислить elapsedTime неверна. В Swift 3 это будет:

let elapsed = Date().timeIntervalSince(timeAtPress)

Обратите внимание на () после ссылки Date. Date() создает экземпляр нового объекта даты, а затем timeIntervalSince возвращает разницу во времени между этим и timeAtPress. Это вернет значение с плавающей запятой (технически, TimeInterval).

Если вы хотите, чтобы это значение было усечено до значения Int, вы можете просто использовать:

let duration = Int(elapsed)

И, кстати, ваше определение переменной timeAtPress не требует создания экземпляра объекта Date. Я полагаю, вы намеревались:

var timeAtPress: Date!

Это определяет переменную как переменную Date (неявно развернутую), но вы, вероятно, отложите фактическое создание экземпляра этой переменной до тех пор, пока не будет вызван pressed.


В качестве альтернативы я часто использую CFAbsoluteTimeGetCurrent(), например,

var start: CFAbsoluteTime!

И когда я хочу установить startTime, я делаю следующее:

start = CFAbsoluteTimeGetCurrent()

И когда я хочу рассчитать количество прошедших секунд, я делаю следующее:

let elapsed = CFAbsoluteTimeGetCurrent() - start

Стоит отметить, что документация CFAbsoluteTimeGetCurrent предупреждает нас:

Повторные вызовы этой функции не гарантируют монотонно возрастающих результатов. Системное время может уменьшиться из-за синхронизации с внешними эталонами времени или из-за явного изменения часов пользователем.

Это означает, что если вам не повезло измерить прошедшее время, когда происходит одна из этих корректировок, вы можете получить неправильный расчет прошедшего времени. Это справедливо и для расчетов NSDate/Date. Безопаснее всего использовать расчет на основе mach_absolute_time (наиболее легко сделать с помощью CACurrentMediaTime):

let start = CACurrentMediaTime()

и

let elapsed = CACurrentMediaTime() - start

Здесь используется mach_absolute_time, но избегаются некоторые сложности, описанные в Технические вопросы и ответы QA1398.

Однако помните, что CACurrentMediaTime/mach_absolute_time будут сброшены при перезагрузке устройства. Итак, в итоге, если вам нужны точные расчеты затраченного времени во время работы приложения, используйте CACurrentMediaTime. Но если вы собираетесь сохранить это время запуска в постоянном хранилище, которое вы можете вспомнить, когда приложение будет перезапущено в будущем, вам придется использовать Date или CFAbsoluteTimeGetCurrent и просто смириться с любыми неточностями, которые могут возникнуть.

person Rob    schedule 28.10.2014

NSDate() и NSCalendar() звучат как хороший выбор. Используйте расчет по календарю и оставьте фактическую математическую часть на усмотрение фреймворка. Вот быстрый пример получения секунд между двумя NSDate()

let startDate = NSDate()
let endDate = NSDate()
let calendar = NSCalendar.currentCalendar()
let dateComponents = calendar.components(NSCalendarUnit.CalendarUnitSecond, fromDate: startDate, toDate: endDate, options: nil)
let seconds = dateComponents.second
println("Seconds: \(seconds)")
person Freddy    schedule 28.10.2014
comment
По какой-то причине это всегда возвращает 0 для меня, даже если даты разделены на час. - person Markymark; 30.07.2020

Согласно ответу Фредди, это функция в Swift 3:

let start = Date()
let end = Date(timeIntervalSince1970: 100)
let calendar = Calendar.current
let unitFlags = Set<Calendar.Component>([ .second])
let datecomponents = calendar.dateComponents(unitFlags, from: start, to: end)
let seconds = datecomponents.second
print(String(describing: seconds))
person Andres Paladines    schedule 02.08.2017
comment
Спасибо @LagMaster. Рад видеть, что Swift отказывается от префикса NS. - person Freddy; 23.12.2017

Свифт 5

let differenceInSeconds = Int(endDate.timeIntervalSince(startDate))
person iKK    schedule 30.04.2020
comment
Самый простой. Спасибо. - person Eric; 26.04.2021

Вот как вы можете получить разницу в последней версии Swift 3

let calendar = NSCalendar.current
var compos:Set<Calendar.Component> = Set<Calendar.Component>()
compos.insert(.second)
compos.insert(.minute)
let difference = calendar.dateComponents(compos, from: fromDate, to: toDate)
print("diff in minute=\(difference.minute!)") // difference in minute
print("diff in seconds=\(difference.second!)") // difference in seconds

Ссылка: Получение разницы между двумя NSDates в (месяцы/дни/часы/минуты/секунды)

person Rujoota Shah    schedule 29.07.2017

Свифт 5

    let startDate = Date()
    let endDate = Date()
    let calendar = Calendar.current
    let dateComponents = calendar.compare(startDate, to: endDate, toGranularity: .second)
    let seconds = dateComponents.rawValue
    print("Seconds: \(seconds)")
person Ahmed Safadi    schedule 16.04.2019
comment
Это не дает разницы в секундах в коде, а только тогда, больше ли начало или нет. - person Arun K; 18.01.2020

Для Swift 3 секунды между 2 разами в формате "чч:мм"

func secondsIn(_ str: String)->Int{
    var strArr = str.characters.split{$0 == ":"}.map(String.init)
    var sec = Int(strArr[0])! * 3600
    var sec1 = Int(strArr[1])! * 36
    print("sec")
    print(sec+sec1)
    return sec+sec1

}

использование

var sec1 = secondsIn(shuttleTime)
var sec2 = secondsIn(dateToString(Date()))
print(sec1-sec2)
person Rishabh Dugar    schedule 22.02.2017
comment
Этот ответ не имеет отношения к ответу op. - person Tomasz Nazarenko; 09.04.2017