Encuentre la diferencia en segundos entre NSDates como entero usando Swift

96

Estoy escribiendo un fragmento de código en el que quiero cronometrar cuánto tiempo se mantuvo presionado un botón. Para hacer eso, grabé un NSDate()cuando se presionó el botón e intenté usar la timeIntervalSinceDatefunción cuando se soltó el botón. Eso parece funcionar, pero no puedo encontrar ninguna forma de imprimir el resultado o cambiarlo a un número entero.

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

He visto algunas preguntas similares, pero no sé C, por lo que me costó entender las respuestas dadas. Si hay una forma más eficiente de averiguar cuánto tiempo se mantuvo presionado el botón, estoy abierto a sugerencias. Gracias por adelantado.

Erik
fuente

Respuestas:

211

Tu intento de calcular elapsedTimees incorrecto. En Swift 3, sería:

let elapsed = Date().timeIntervalSince(timeAtPress)

Tenga en cuenta el ()después de la Datereferencia. La Date()instancia un nuevo objeto de fecha y, a continuación, timeIntervalSincedevuelve la diferencia de tiempo entre eso y timeAtPress. Eso devolverá un valor de punto flotante (técnicamente, a TimeInterval).

Si desea que se trunque a un Intvalor, puede usar:

let duration = Int(elapsed)

Y, por cierto, su definición de la timeAtPressvariable no necesita instanciar un Dateobjeto. Supongo que pretendías:

var timeAtPress: Date!

Eso define la variable como una Datevariable (una implícitamente desenvuelta), pero presumiblemente aplazaría la instanciación real de esa variable hasta que pressedse llame.


Alternativamente, a menudo uso CFAbsoluteTimeGetCurrent(), por ejemplo,

var start: CFAbsoluteTime!

Y cuando quiero configurar startTime, hago lo siguiente:

start = CFAbsoluteTimeGetCurrent()

Y cuando quiero calcular la cantidad de segundos transcurridos, hago lo siguiente:

let elapsed = CFAbsoluteTimeGetCurrent() - start

Vale la pena señalar que la CFAbsoluteTimeGetCurrentdocumentación nos advierte:

Las llamadas repetidas a esta función no garantizan resultados que aumenten monótonamente. La hora del sistema puede disminuir debido a la sincronización con referencias de tiempo externas o debido a un cambio explícito del reloj por parte del usuario.

Esto significa que si tiene la mala suerte de medir el tiempo transcurrido cuando se realiza uno de estos ajustes, puede terminar con un cálculo incorrecto del tiempo transcurrido. Esto también es cierto para los cálculos NSDate/ Date. Es más seguro utilizar un mach_absolute_timecálculo basado (se hace más fácil con CACurrentMediaTime):

let start = CACurrentMediaTime()

y

let elapsed = CACurrentMediaTime() - start

Esto utiliza mach_absolute_time, pero evita algunas de sus complejidades descritas en Preguntas y respuestas técnicas QA1398 .

Sin embargo, recuerde que CACurrentMediaTime/ mach_absolute_timese restablecerá cuando se reinicie el dispositivo. Entonces, en resumen, si necesita cálculos precisos del tiempo transcurrido mientras se ejecuta una aplicación, use CACurrentMediaTime. Pero si va a guardar esta hora de inicio en un almacenamiento persistente que podría recordar cuando la aplicación se reinicie en una fecha futura, entonces debe usar Dateo CFAbsoluteTimeGetCurrent, y simplemente vivir con cualquier inexactitud que pueda implicar.

Robar
fuente
4
¡Vaya, gracias Rob! Su respuesta fue extremadamente útil y fácil de entender. Realmente aprecio el consejo sobre CFAbsoluteTime. ¡Definitivamente lo usaré!
Erik
¿Cuál es la dimensión de timeIntervalSinceDate?
Eugene
Devuelve un TimeInterval, que se mide en segundos.
Rob
22

NSDate () y NSCalendar () suenan como una buena opción. Utilice el cálculo del calendario y deje la parte matemática real al marco. Aquí hay un ejemplo rápido de cómo obtener los segundos entre dosNSDate()

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)")
Freddy
fuente
Por alguna razón, esto siempre devuelve 0 para mí, aunque las fechas tengan una hora de diferencia.
Markymark
10

De acuerdo con la respuesta de Freddy, esta es la función en 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))
Andrés Paladines
fuente
1
Gracias @LagMaster. Feliz de ver que Swift está eliminando el prefijo NS.
Freddy
4

Rápido 5

let differenceInSeconds = Int(endDate.timeIntervalSince(startDate))
iKK
fuente
0

Así es como puede obtener la diferencia en la última versión de 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

Referencia: Obtener la diferencia entre dos NSDates en (meses / días / horas / minutos / segundos)

Rujoota Shah
fuente
-1

Rápido 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)")
Ahmed Safadi
fuente
2
Esto no proporciona la diferencia en segundos en el código, solo entonces si el inicio es mayor o no.
Arun K
-6

Para Swift 3 Seconds entre 2 horas en "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

}

Uso

var sec1 = secondsIn(shuttleTime)
var sec2 = secondsIn(dateToString(Date()))
print(sec1-sec2)
Rishabh Dugar
fuente
Esta respuesta es irrelevante para la respuesta de la op.
Tomasz Nazarenko