Znajdź różnicę w sekundach między NSDates jako liczbami całkowitymi przy użyciu języka Swift

98

Piszę fragment kodu, w którym chcę określić czas, jak długo przycisk był wciśnięty. Aby to zrobić, nagrałem NSDate()moment naciśnięcia przycisku i spróbowałem użyć timeIntervalSinceDatefunkcji, gdy przycisk został zwolniony. Wygląda na to, że działa, ale nie mogę znaleźć sposobu na wydrukowanie wyniku lub przełączenie go na liczbę całkowitą.

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

Widziałem kilka podobnych pytań, ale nie znam C, więc ciężko mi było zrozumieć udzielone odpowiedzi. Jeśli istnieje skuteczniejszy sposób sprawdzenia, jak długo przycisk był wciśnięty, jestem otwarty na sugestie. Z góry dziękuję.

Erik
źródło

Odpowiedzi:

214

Twoja próba obliczenia elapsedTimejest nieprawidłowa. W Swift 3 byłoby to:

let elapsed = Date().timeIntervalSince(timeAtPress)

Zwróć uwagę ()na Dateodwołanie. Date()Tworzy nową instancję obiektu Date, a następnie timeIntervalSincezwraca różnicę czasu między tym a timeAtPress. To zwróci wartość zmiennoprzecinkową (technicznie a TimeInterval).

Jeśli chcesz, aby było to obcięte do Intwartości, możesz po prostu użyć:

let duration = Int(elapsed)

A tak przy okazji, twoja definicja timeAtPresszmiennej nie musi tworzyć instancji Dateobiektu. Zakładam, że zamierzałeś:

var timeAtPress: Date!

To definiuje zmienną jako Datezmienną (niejawnie nieopakowaną), ale prawdopodobnie odroczyłbyś rzeczywistą instancję tej zmiennej do momentu pressedwywołania.


Alternatywnie często używam CFAbsoluteTimeGetCurrent()np.

var start: CFAbsoluteTime!

A kiedy chcę ustawić startTime, wykonuję następujące czynności:

start = CFAbsoluteTimeGetCurrent()

A kiedy chcę obliczyć liczbę sekund, które upłynęły, wykonuję następujące czynności:

let elapsed = CFAbsoluteTimeGetCurrent() - start

Warto zaznaczyć, że CFAbsoluteTimeGetCurrentdokumentacja ostrzega nas:

Wielokrotne wywołania tej funkcji nie gwarantują monotonnie rosnących wyników. Czas systemowy może ulec skróceniu z powodu synchronizacji z zewnętrznymi odniesieniami czasu lub z powodu jawnej zmiany zegara przez użytkownika.

Oznacza to, że jeśli masz nieszczęście mierzyć czas, który upłynął, gdy ma miejsce jedna z tych korekt, możesz skończyć z niepoprawnym obliczeniem czasu, który upłynął. Dotyczy to również NSDate/ Dateobliczeń. Najbezpieczniej jest skorzystać z mach_absolute_timeobliczeń opartych (najłatwiej zrobić za pomocą CACurrentMediaTime):

let start = CACurrentMediaTime()

i

let elapsed = CACurrentMediaTime() - start

Używa mach_absolute_time, ale pozwala uniknąć niektórych zawiłości opisanych w pytaniach technicznych QA1398 .

Pamiętaj jednak, że CACurrentMediaTime/ mach_absolute_timezostanie zresetowany po ponownym uruchomieniu urządzenia. Podsumowując, jeśli potrzebujesz dokładnych obliczeń czasu, który upłynął, gdy aplikacja jest uruchomiona, użyj CACurrentMediaTime. Ale jeśli zamierzasz zapisać ten czas rozpoczęcia w trwałej pamięci, którą możesz sobie przypomnieć, gdy aplikacja zostanie ponownie uruchomiona w przyszłości, musisz użyć Datelub CFAbsoluteTimeGetCurrenti po prostu żyć z wszelkimi niedokładnościami, które mogą się z tym wiązać.

Obrabować
źródło
4
Wow, dzięki Rob! Twoja odpowiedź była niezwykle pomocna i łatwa do zrozumienia. Naprawdę doceniam wskazówkę dotyczącą CFAbsoluteTime. Zdecydowanie z tego skorzystam!
Erik
jaki jest wymiar timeIntervalSinceDate?
Eugene
Zwraca wartość a TimeInterval, która jest mierzona w sekundach.
Rob
22

NSDate () i NSCalendar () brzmią jak dobry wybór. Użyj kalendarza i pozostaw rzeczywistą część matematyczną ramom. Oto szybki przykład określania sekund między dwomaNSDate()

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
źródło
Z jakiegoś powodu zawsze zwraca to dla mnie 0, mimo że daty są oddalone o godzinę.
Markymark
10

Zgodnie z odpowiedzią Freddy'ego jest to funkcja w języku 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))
Andres Paladines
źródło
1
Dzięki @LagMaster. Cieszę się, że szybki znosi prefiks NS.
Freddy
4

Szybki 5

let differenceInSeconds = Int(endDate.timeIntervalSince(startDate))
iKK
źródło
0

W ten sposób możesz uzyskać różnicę w najnowszej wersji 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

Odniesienie: Uzyskanie różnicy między dwiema datami NSD w (miesiące / dni / godziny / minuty / sekundy)

Rujoota Shah
źródło
-1

Szybki 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
źródło
2
Nie zapewnia to różnicy w sekundach w kodzie, ale tylko wtedy, czy początek jest większy, czy nie.
Arun K
-6

Dla Swift 3 sekundy między 2 razy w „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

}

Stosowanie

var sec1 = secondsIn(shuttleTime)
var sec2 = secondsIn(dateToString(Date()))
print(sec1-sec2)
Rishabh Dugar
źródło
Ta odpowiedź nie ma znaczenia dla odpowiedzi op.
Tomasz Nazarenko