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


96

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

Відповіді:


211

Ваша спроба обчислити 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. Радий бачити, як стрімко покінчив із префіксом NS.
Freddy

4

Швидкий 5

let differenceInSeconds = Int(endDate.timeIntervalSince(startDate))

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

Довідково: Отримання різниці між двома датами NSD (місяці / дні / години / хвилини / секунди)


-1

Швидкий 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

Протягом 3 секунд у режимі "hh: mm"

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)

Ця відповідь не має відношення до відповіді ор.
Томаш Назаренко
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.