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

99

Я пишу фрагмент кода, где хочу измерить, как долго удерживалась кнопка. Для этого я записал, 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, поэтому мне было трудно понять полученные ответы. Если есть более эффективный способ узнать, как долго удерживалась кнопка, я открыт для предложений. Заранее спасибо.

Эрик
источник

Ответы:

215

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

let elapsed = Date().timeIntervalSince(timeAtPress)

Обратите внимание на ()после Dateссылки. Date()Инициализирует новый объект даты, а затем timeIntervalSinceвозвращает разницу во времени между этим и timeAtPress. Это вернет значение с плавающей запятой (технически a 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и просто жить с любыми неточностями, которые могут повлечь за собой.

Роб
источник
4
Вау, спасибо, Роб! Ваш ответ был чрезвычайно полезным и легким для понимания. Я очень ценю совет о CFAbsoluteTime. Я обязательно воспользуюсь этим!
Эрик
какое измерение для timeIntervalSinceDate?
Евгений
Он возвращает a TimeInterval, который измеряется в секундах.
Роб
22

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)")
Фредди
источник
По какой-то причине это всегда возвращает мне 0, даже если даты разнесены на час.
Markymark
10

Согласно ответу Фредди, это функция в быстром 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))
Андрес Паладинес
источник
1
Спасибо @LagMaster. Рад видеть, что swift отказывается от префикса NS.
Фредди
4

Swift 5

let differenceInSeconds = Int(endDate.timeIntervalSince(startDate))
iKK
источник
0

Вот как вы можете получить разницу в последней версии 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 в (месяцы / дни / часы / минуты / секунды)

Ружута Шах
источник
-1

Swift 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)")
Ахмед Сафади
источник
2
Это не дает разницы в секундах в коде, а только тогда, больше ли начало или нет.
Арун К.
-6

Для 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)
Ришаб Дугар
источник
Этот ответ не имеет отношения к ответу op.
Томаш Назаренко