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.

Odpowiedzi:


147

pseudo kod:

minutes = floor(326.4/60)
seconds = round(326.4 - minutes * 60)

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ę.

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


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

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#>) {
    // ...
}

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];
}

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

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

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.


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


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)

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"
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.