Trova la differenza in secondi tra NSDates come numero intero utilizzando Swift


96

Sto scrivendo un pezzo di codice in cui voglio cronometrare per quanto tempo un pulsante è stato tenuto premuto. Per fare ciò ho registrato un NSDate()momento in cui il pulsante è stato premuto e ho provato a utilizzare la timeIntervalSinceDatefunzione quando il pulsante è stato rilasciato. Sembra funzionare ma non riesco a trovare alcun modo per stampare il risultato o cambiarlo in un numero intero.

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 = ???
}

Ho visto alcune domande simili, ma non conosco C, quindi ho avuto difficoltà a capire le risposte fornite. Se esiste un modo più efficiente per scoprire per quanto tempo è stato tenuto premuto il pulsante, sono aperto a suggerimenti. Grazie in anticipo.

Risposte:


211

Il tuo tentativo di calcolo elapsedTimenon è corretto. In Swift 3, sarebbe:

let elapsed = Date().timeIntervalSince(timeAtPress)

Nota il ()dopo il Dateriferimento. La Date()un'istanza di un nuovo oggetto data, quindi timeIntervalSincerestituisce la differenza di tempo tra questo e timeAtPress. Ciò restituirà un valore in virgola mobile (tecnicamente, aTimeInterval ).

Se vuoi che venga troncato a un Intvalore, puoi semplicemente usare:

let duration = Int(elapsed)

E, BTW, la tua definizione della timeAtPressvariabile non ha bisogno di istanziare un Dateoggetto. Presumo tu intendessi:

var timeAtPress: Date!

Ciò definisce la variabile come una Datevariabile (implicitamente scartata), ma presumibilmente rimanderai l'istanza effettiva di quella variabile fino a quando non pressedverrà chiamata.


In alternativa, uso spesso CFAbsoluteTimeGetCurrent(), ad esempio,

var start: CFAbsoluteTime!

E quando voglio impostare startTime, faccio quanto segue:

start = CFAbsoluteTimeGetCurrent()

E quando voglio calcolare il numero di secondi trascorsi, faccio quanto segue:

let elapsed = CFAbsoluteTimeGetCurrent() - start

Vale la pena notare che la CFAbsoluteTimeGetCurrentdocumentazione ci avverte:

Chiamate ripetute a questa funzione non garantiscono risultati crescenti in modo monotono. L'ora di sistema può diminuire a causa della sincronizzazione con riferimenti temporali esterni oa causa di una modifica esplicita dell'orologio da parte dell'utente.

Ciò significa che se sei abbastanza sfortunato da misurare il tempo trascorso quando si verifica una di queste regolazioni, puoi finire con un calcolo del tempo trascorso errato. Questo vale anche per i calcoli NSDate/ Date. È più sicuro utilizzare un mach_absolute_timecalcolo basato (più facilmente eseguito con CACurrentMediaTime):

let start = CACurrentMediaTime()

e

let elapsed = CACurrentMediaTime() - start

Questo utilizza mach_absolute_time, ma evita alcune delle sue complessità descritte in Domande e risposte tecniche QA1398 .

Ricorda, tuttavia, che CACurrentMediaTime/ mach_absolute_timeverrà ripristinato al riavvio del dispositivo. Quindi, in conclusione, se hai bisogno di calcoli accurati del tempo trascorso mentre un'app è in esecuzione, usa CACurrentMediaTime. Ma se hai intenzione di salvare questa ora di inizio in una memoria persistente che potresti ricordare quando l'app viene riavviata in una data futura, devi usare Dateo CFAbsoluteTimeGetCurrente convivere con eventuali inesattezze che potrebbero comportare.


4
Wow, grazie Rob! La tua risposta è stata estremamente utile e di facile comprensione. Apprezzo molto il suggerimento su CFAbsoluteTime. Lo userò sicuramente!
Erik

qual è la dimensione per timeIntervalSinceDate?
eugene

Restituisce un TimeInterval, che viene misurato in secondi.
Rob il

22

NSDate () e NSCalendar () sembrano una buona scelta. Usa il calcolo del calendario e lascia la parte matematica effettiva al framework. Ecco un rapido esempio di come ottenere i secondi tra dueNSDate()

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)")

Per qualche motivo questo restituisce sempre 0 per me anche se le date sono a un'ora di distanza.
Markymark

10

Secondo la risposta di Freddy, questa è la funzione in 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))

1
Grazie @LagMaster. Felice di vedere che swift sta eliminando il prefisso NS.
Freddy

4

Swift 5

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

0

Ecco come puoi ottenere la differenza nell'ultima versione di 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

Riferimento: ottenere la differenza tra due NSDate in (mesi / giorni / ore / minuti / secondi)


-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
Questo non fornisce la differenza in secondi nel codice, ma solo se l'inizio è maggiore o meno.
Arun K

-6

Per Swift 3 secondi tra 2 volte in "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

}

Utilizzo

var sec1 = secondsIn(shuttleTime)
var sec2 = secondsIn(dateToString(Date()))
print(sec1-sec2)

Questa risposta è irrilevante per la risposta dell'op.
Tomasz Nazarenko
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.