Jak przekonwertować NSTimeInterval (sekundy) na minuty

104

Mam pewną kwotę, secondsktóra przeszła z pewnego wydarzenia. Jest przechowywany w NSTimeIntervaltypie danych.

Chcę go przekonwertować na minutesi seconds.

Na przykład mam: „326,4” sekund i chcę zamienić to na następujący ciąg: „5:26”.

Jaki jest najlepszy sposób na osiągnięcie tego celu?

Dzięki.

Ilya Suzdalnitski
źródło

Odpowiedzi:

147

pseudo kod:

minutes = floor(326.4/60)
seconds = round(326.4 - minutes * 60)
Brian Ramsay
źródło
90
Myślę, że warto również wspomnieć, że NSTimerInterval to tylko definicja typu double.
Armentage,
4
Zobacz odpowiedź Albaregara - jest to lepszy sposób na zrobienie tego (więcej kodu, ale bardziej elastyczny,
łatwy w
1
Ten kod jest jednak bardzo drogi. Ta odpowiedź jest lepsza w przypadku szybkiej konwersji czasu trwania w sekundach.
SpacyRicochet
2
Pamiętaj, że ta odpowiedź da ci rzeczy takie jak 1:60. Spójrz na odpowiedź StratFana, która jest bliższa prawdy. Ale usuń podłogę i okrągłą, a powinieneś być w domu.
InvulgoSoft
Odpowiedź Micka MacCalluma poniżej w momencie pisania tego komentarza wydaje się być najbardziej zaktualizowana i wykonana przy użyciu natywnego API.
Tomasz Nazarenko
183

Krótki opis

  1. Odpowiedź Briana Ramsaya jest wygodniejsza, jeśli chcesz przeliczyć tylko minuty.
  2. Jeśli chcesz, aby Cocoa API zrób to za Ciebie i przekonwertuj NSTimeInterval nie tylko na minuty, ale także na dni, miesiące, tygodnie itp., Myślę, że jest to bardziej ogólne podejście
  3. Użyj metody NSCalendar:

    • (NSDateComponents *)components:(NSUInteger)unitFlags fromDate:(NSDate *)startingDate toDate:(NSDate *)resultDate options:(NSUInteger)opts

    • „Zwraca, jako obiekt NSDateComponents przy użyciu określonych składników, różnicę między dwiema podanymi datami”. Z dokumentacji API.

  4. Utwórz 2 NSDate, których różnicą jest NSTimeInterval, który chcesz przekonwertować. (Jeśli twój NSTimeInterval pochodzi z porównania 2 NSDate, nie musisz robić tego kroku, a nawet nie potrzebujesz NSTimeInterval).

  5. Uzyskaj oferty od NSDateComponents

Przykładowy kod

// The time interval 
NSTimeInterval theTimeInterval = 326.4;

// Get the system calendar
NSCalendar *sysCalendar = [NSCalendar currentCalendar];

// Create the NSDates
NSDate *date1 = [[NSDate alloc] init];
NSDate *date2 = [[NSDate alloc] initWithTimeInterval:theTimeInterval sinceDate:date1]; 

// Get conversion to months, days, hours, minutes
unsigned int unitFlags = NSHourCalendarUnit | NSMinuteCalendarUnit | NSDayCalendarUnit | NSMonthCalendarUnit;

NSDateComponents *conversionInfo = [sysCalendar components:unitFlags fromDate:date1  toDate:date2  options:0];

NSLog(@"Conversion: %dmin %dhours %ddays %dmoths",[conversionInfo minute], [conversionInfo hour], [conversionInfo day], [conversionInfo month]);

[date1 release];
[date2 release];

Znane problemy

  • Za dużo jak na samą konwersję, masz rację, ale tak działa API.
  • Moja sugestia: jeśli przyzwyczaisz się do zarządzania danymi dotyczącymi czasu za pomocą NSDate i NSCalendar, API wykona za Ciebie ciężką pracę.
Albaregar
źródło
4
Zdecydowanie jest dużo obejścia, aby dokonać niewielkiej konwersji, ale wydaje się to wygodne, modułowe i naprawdę elastyczne, zagłosuj na ten przykładowy kod @Albaregar.
Rigo Vides
2
+1 Aby uzyskać dobrą, dokładną odpowiedź, ten kod jest jednak dość drogi.
Nick Weaver
1
+1 ... jedno zastrzeżenie. Zachowaj ostrożność, używając tego stylu kodu, jeśli chcesz zaokrąglić ułamki sekund w górę. Domyślne zachowanie - [komponenty NSCalendar: fromDate: toDate: opcje:] może zepsuć sytuację, w której składnik toDate jest (na przykład) o 31,5 sekundy przed fromDate - zwrócone składniki będą miały 31 w polu sekund. Istnieje opcjonalny parametr NSWrapCalendarComponents, ale z (ograniczonych) eksperymentów, które przeprowadziłem z tym, zawija się do najbliższej sekundy zamiast zaokrąglania w górę lub w dół. Twój przebieg może się różnić.
David Doyle
%ldjeśli jesteś na komputerze 64-bitowym.
Anoop Vaidya,
5
Osoby, które to znajdą (np. Nick Weaver), pomyślą, że kod wygląda na powolny. Tak nie jest. Robię aplikację czasową i właśnie przetestowałem wersję Albaregara z czymś w stylu Briana Ramseya (i innych) ... i, co zaskakujące, nawet odpytywanie 100 razy na sekundę (co jest ogromną przesadą) na stosunkowo wolnym urządzeniu (4S) ) była mniejsza niż 1% różnica w wykorzystaniu procesora.
mmc
42

Wszystko to wygląda na bardziej skomplikowane, niż powinno! Oto krótki i przyjemny sposób na zamianę przedziału czasu na godziny, minuty i sekundy:

NSTimeInterval timeInterval = 326.4;
long seconds = lroundf(timeInterval); // Since modulo operator (%) below needs int or long

int hour = seconds / 3600;
int mins = (seconds % 3600) / 60;
int secs = seconds % 60;

Zauważ, że kiedy wstawisz float do int, automatycznie otrzymasz floor (), ale możesz dodać to do pierwszych dwóch, jeśli poczujesz się lepiej :-)

Prasad
źródło
Niesamowite! Wypróbowałem kod Ramsaya, chociaż wydaje się, że zniknął o sekundę.
uplearnedu.com
W kodzie brakuje średnika, ale nie pozwoliłby mi go edytować, aby to naprawić.
Jeef
Myślę, że twoje podejście jest najlepsze - proste, wykonuje swoją pracę i „lekkie” na kleszcze. Idealny.
BonanzaDriver
29

Wybacz mi, że jestem dziewicą stosu ... Nie jestem pewien, jak odpowiedzieć na odpowiedź Briana Ramsaya ...

Użycie rundy nie będzie działać dla drugich wartości między 59,5 a 59,99999. Druga wartość w tym okresie będzie wynosić 60. Zamiast tego użyj obcinania ...

 double progress;

 int minutes = floor(progress/60);
 int seconds = trunc(progress - minutes * 60);
StratFan
źródło
1
Właściwie po prostu całkowicie usuń podłogę i bagażnik / okrągły. :)
InvulgoSoft
@StratFan Czy możesz dodać godziny do swojej odpowiedzi?
Shmidt
27

Jeśli celujesz w system iOS 8 lub OS X 10.10 lub wyższy, stało się to o wiele łatwiejsze. Nowa NSDateComponentsFormatterklasa umożliwia przekonwertowanie podanej NSTimeIntervalwartości z jej wartości w sekundach na zlokalizowany ciąg znaków w celu wyświetlenia użytkownikowi. Na przykład:

Cel C

NSTimeInterval interval = 326.4;

NSDateComponentsFormatter *componentFormatter = [[NSDateComponentsFormatter alloc] init];

componentFormatter.unitsStyle = NSDateComponentsFormatterUnitsStylePositional;
componentFormatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorDropAll;

NSString *formattedString = [componentFormatter stringFromTimeInterval:interval];
NSLog(@"%@",formattedString); // 5:26

Szybki

let interval = 326.4

let componentFormatter = NSDateComponentsFormatter()

componentFormatter.unitsStyle = .Positional
componentFormatter.zeroFormattingBehavior = .DropAll

if let formattedString = componentFormatter.stringFromTimeInterval(interval) {
    print(formattedString) // 5:26
}

NSDateCompnentsFormatterpozwala również na to, aby ten wynik był w dłuższych formach. Więcej informacji można znaleźć w artykule NSHipster's NSFormatter . W zależności od tego, z jakimi klasami już pracujesz (jeśli nie NSTimeInterval), wygodniejsze może być przekazanie programowi formatującemu wystąpienia NSDateComponentslub dwóch NSDateobiektów, co można również wykonać za pomocą następujących metod.

Cel C

NSString *formattedString = [componentFormatter stringFromDate:<#(NSDate *)#> toDate:<#(NSDate *)#>];
NSString *formattedString = [componentFormatter stringFromDateComponents:<#(NSDateComponents *)#>];

Szybki

if let formattedString = componentFormatter.stringFromDate(<#T##startDate: NSDate##NSDate#>, toDate: <#T##NSDate#>) {
    // ...
}

if let formattedString = componentFormatter.stringFromDateComponents(<#T##components: NSDateComponents##NSDateComponents#>) {
    // ...
}
Mick MacCallum
źródło
To jest właściwy sposób na utworzenie ciągu znaków, odpowiednio zlokalizowany
SwiftArchitect
1
Ta odpowiedź jest o wiele bardziej „Objective-C” i użyteczna niż zaakceptowana odpowiedź. Nie potrzebujesz switchani if elseoświadczeń z tym. NSDateComponentsFormatterdba o to wszystko. Godziny, minuty, sekundy drukowane bez obaw.
rustyMagnet
17

Kod Briana Ramsaya, pozbawiony pseudonimu:

- (NSString*)formattedStringForDuration:(NSTimeInterval)duration
{
    NSInteger minutes = floor(duration/60);
    NSInteger seconds = round(duration - minutes * 60);
    return [NSString stringWithFormat:@"%d:%02d", minutes, seconds];
}
Yang Meyer
źródło
To nie lokalizuje
SwiftArchitect
7

Oto wersja Swift:

func durationsBySecond(seconds s: Int) -> (days:Int,hours:Int,minutes:Int,seconds:Int) {
    return (s / (24 * 3600),(s % (24 * 3600)) / 3600, s % 3600 / 60, s % 60)
}

Może być używany w ten sposób:

let (d,h,m,s) = durationsBySecond(seconds: duration)
println("time left: \(d) days \(h) hours \(m) minutes \(s) seconds")
Jochen Bedersdorfer
źródło
6
    NSDate *timeLater = [NSDate dateWithTimeIntervalSinceNow:60*90];

    NSTimeInterval duration = [timeLater  timeIntervalSinceNow];

    NSInteger hours = floor(duration/(60*60));
    NSInteger minutes = floor((duration/60) - hours * 60);
    NSInteger seconds = floor(duration - (minutes * 60) - (hours * 60 * 60));

    NSLog(@"timeLater: %@", [dateFormatter stringFromDate:timeLater]);

    NSLog(@"time left: %d hours %d minutes  %d seconds", hours,minutes,seconds);

Wyjścia:

timeLater: 22:27
timeLeft: 1 hours 29 minutes  59 seconds
polarware
źródło
to naprawdę doskonały przykład na ukrycie daty
ravinder521986
5

Ponieważ jest to zasadniczo podwójne ...

Podziel przez 60.0 i wyodrębnij część całkowitą i część ułamkową.

Integralną częścią będzie cała liczba minut.

Ponownie pomnóż część ułamkową przez 60,0.

Wynikiem będą pozostałe sekundy.


źródło
3

Pamiętaj, że pierwotne pytanie dotyczy wyjścia w postaci łańcucha, a nie pseudokodu lub pojedynczych składników ciągu.

Chcę przekonwertować go na następujący ciąg: „5:26”

W wielu odpowiedziach brakuje kwestii związanych z internacjonalizacją, a większość z nich wykonuje obliczenia matematyczne ręcznie. Wszystko tak XX wieku ...

Nie wykonuj samodzielnie matematyki (Swift 4)

let timeInterval: TimeInterval = 326.4
let dateComponentsFormatter = DateComponentsFormatter()
dateComponentsFormatter.unitsStyle = .positional
if let formatted = dateComponentsFormatter.string(from: timeInterval) {
    print(formatted)
}

5:26


Dźwignia na biblioteki

Jeśli naprawdę potrzebujesz pojedynczych komponentów i przyjemnie czytelnego kodu, sprawdź SwiftDate :

import SwiftDate
...
if let minutes = Int(timeInterval).seconds.in(.minute) {
    print("\(minutes)")
}

5


Kredyty dla @mickmaccallum i @polarwar za odpowiednie wykorzystanie domenyDateComponentsFormatter

SwiftArchitect
źródło
0

Jak to zrobiłem w Swift (w tym formatowanie ciągu, aby pokazać go jako „01:23”):

let totalSeconds: Double = someTimeInterval
let minutes = Int(floor(totalSeconds / 60))
let seconds = Int(round(totalSeconds % 60))        
let timeString = String(format: "%02d:%02d", minutes, seconds)
NSLog(timeString)
SilentDirge
źródło
0

Wersja Swift 2

extension NSTimeInterval {
            func toMM_SS() -> String {
                let interval = self
                let componentFormatter = NSDateComponentsFormatter()

                componentFormatter.unitsStyle = .Positional
                componentFormatter.zeroFormattingBehavior = .Pad
                componentFormatter.allowedUnits = [.Minute, .Second]
                return componentFormatter.stringFromTimeInterval(interval) ?? ""
            }
        }
    let duration = 326.4.toMM_SS()
    print(duration)    //"5:26"
SPatel
źródło