So konvertieren Sie ein NSTimeInterval (Sekunden) in Minuten

104

Ich habe eine Menge davon secondsvon einem bestimmten Ereignis übergeben. Es ist in einem NSTimeIntervalDatentyp gespeichert .

Ich möchte es in minutesund umwandeln seconds.

Zum Beispiel habe ich: "326.4" Sekunden und möchte es in die folgende Zeichenfolge konvertieren: "5:26".

Was ist der beste Weg, um dieses Ziel zu erreichen?

Vielen Dank.

Ilya Suzdalnitski
quelle

Antworten:

147

Pseudocode:

minutes = floor(326.4/60)
seconds = round(326.4 - minutes * 60)
Brian Ramsay
quelle
90
Ich denke, es ist auch erwähnenswert, dass ein NSTimerInterval nur ein Typedef für Double ist.
Armentage
4
Siehe Albaregars Antwort - es ist ein besserer Weg, dies zu tun (mehr Code, aber flexibler, wartbar)
benvolioT
1
Dieser Code ist jedoch sehr teuer. Für eine schnelle Umrechnung einer Dauer in Sekunden ist diese Antwort besser.
SpacyRicochet
2
Bitte beachten Sie, dass diese Antwort Ihnen Dinge wie 1:60 gibt. Schauen Sie sich StratFans Antwort an, die der Wahrheit näher kommt. Aber entfernen Sie Boden und rund und Sie sollten frei zu Hause sein.
InvulgoSoft
Die Antwort von Mick MacCallum zum Zeitpunkt des Schreibens dieses Kommentars scheint am aktuellsten zu sein und mithilfe der nativen API zu erfolgen.
Tomasz Nazarenko
183

Kurze Beschreibung

  1. Die Antwort von Brian Ramsay ist bequemer, wenn Sie nur in Minuten konvertieren möchten.
  2. Wenn Sie möchten, dass die Cocoa-API dies für Sie tut, konvertieren Sie Ihr NSTimeInterval nicht nur in Minuten, sondern auch in Tage, Monate, Wochen usw. Ich denke, dies ist ein allgemeinerer Ansatz
  3. Verwenden Sie die NSCalendar-Methode:

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

    • "Gibt als NSDateComponents-Objekt unter Verwendung der angegebenen Komponenten die Differenz zwischen zwei angegebenen Daten zurück." Aus der API-Dokumentation.

  4. Erstellen Sie 2 NSDate, deren Unterschied das NSTimeInterval ist, das Sie konvertieren möchten. (Wenn Ihr NSTimeInterval aus dem Vergleich von 2 NSDate stammt, müssen Sie diesen Schritt nicht ausführen, und Sie benötigen nicht einmal das NSTimeInterval.)

  5. Holen Sie sich Ihre Angebote von NSDateComponents

Beispielcode

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

Bekannte Probleme

  • Zu viel für nur eine Konvertierung, Sie haben Recht, aber so funktioniert die API.
  • Mein Vorschlag: Wenn Sie sich daran gewöhnen, Ihre Zeitdaten mit NSDate und NSCalendar zu verwalten, erledigt die API die harte Arbeit für Sie.
Albaregar
quelle
4
Es ist definitiv eine Menge Problemumgehung, nur um eine kleine Konvertierung durchzuführen, aber es fühlt sich bequem, modular und wirklich flexibel an. Stimmen Sie für diesen Beispielcode @Albaregar ab.
Rigo Vides
2
+1 Für eine gute gründliche Antwort ist dieser Code jedoch ziemlich teuer.
Nick Weaver
1
+1 ... eine Einschränkung. Seien Sie vorsichtig mit diesem Codestil, wenn Sie Sekundenbruchteile aufrunden müssen. Das Standardverhalten von - [NSCalendar-Komponenten: fromDate: toDate: options:] kann in dem Szenario, in dem die toDate-Komponente beispielsweise 31,5 Sekunden vor dem fromDate liegt, durcheinander kommen. Die zurückgegebenen Komponenten haben 31 im Sekundenfeld. Es gibt einen optionalen Parameter für NSWrapCalendarComponents, aber nach den (begrenzten) Experimenten, die ich damit durchgeführt habe, wird er auf die nächste Sekunde umgebrochen, anstatt auf- oder abzurunden. Ihr Kilometerstand kann variieren.
David Doyle
%ldWenn Sie sich in einer 64-Bit-Maschine befinden.
Anoop Vaidya
5
Leute, die dies finden (wie Nick Weaver), werden denken, dass Code so aussieht, als wäre er langsam. Ist es nicht. Ich mache eine Timer-App und habe gerade Albaregars Version gegen etwas im Stil von Brian Ramsey (und anderen) getestet ... und überraschenderweise sogar 100-mal pro Sekunde (was ein enormer Overkill ist) auf einem relativ langsamen Gerät (4S) abgefragt ) gab es weniger als 1% Unterschied in der Prozessorauslastung.
mmc
42

All dies sieht komplizierter aus als es sein muss! Hier ist eine kurze und süße Möglichkeit, ein Zeitintervall in Stunden, Minuten und Sekunden umzuwandeln:

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;

Beachten Sie, wenn Sie einen Float in ein Int einfügen, erhalten Sie automatisch floor (), aber Sie können es zu den ersten beiden hinzufügen, wenn Sie sich besser fühlen :-)

Prasad
quelle
Genial! Ich habe Ramsays Code ausprobiert, obwohl er sekundenschnell aus zu sein scheint.
uplearnedu.com
Sie vermissen ein Semikolon in Ihrem Code, aber ich konnte es nicht bearbeiten, um es zu beheben.
Jeef
Ich denke, Ihr Ansatz ist am besten - einfach, erledigt die Arbeit und "beleuchtet" die Zecken. Perfekt.
BonanzaDriver
29

Verzeih mir, dass ich eine Stack-Jungfrau bin ... Ich bin mir nicht sicher, wie ich auf Brian Ramsays Antwort antworten soll ...

Die Verwendung von round funktioniert nicht für zweite Werte zwischen 59,5 und 59,99999. Der zweite Wert ist in diesem Zeitraum 60. Verwenden Sie stattdessen Trunc ...

 double progress;

 int minutes = floor(progress/60);
 int seconds = trunc(progress - minutes * 60);
StratFan
quelle
1
Eigentlich nur Boden und Kofferraum / Runde komplett entfernen. :)
InvulgoSoft
@StratFan Können Sie Ihrer Antwort bitte Stunden hinzufügen?
Shmidt
27

Wenn Sie auf iOS 8 oder OS X 10.10 oder höher abzielen, ist dies jetzt noch einfacher. Mit der neuen NSDateComponentsFormatterKlasse können Sie eine bestimmte NSTimeIntervalZeichenfolge in Sekundenschnelle in eine lokalisierte Zeichenfolge konvertieren , um sie dem Benutzer anzuzeigen. Beispielsweise:

Ziel 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

Schnell

let interval = 326.4

let componentFormatter = NSDateComponentsFormatter()

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

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

NSDateCompnentsFormatterermöglicht auch, dass diese Ausgabe in längeren Formen vorliegt. Weitere Informationen finden Sie im NSFormatter- Artikel von NSHipster . Abhängig davon, mit welchen Klassen Sie bereits arbeiten (falls nicht NSTimeInterval), ist es möglicherweise bequemer, dem Formatierer eine Instanz NSDateComponentsoder zwei NSDateObjekte zu übergeben, was auch über die folgenden Methoden erfolgen kann.

Ziel c

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

Schnell

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

if let formattedString = componentFormatter.stringFromDateComponents(<#T##components: NSDateComponents##NSDateComponents#>) {
    // ...
}
Mick MacCallum
quelle
Dies ist der richtige Weg, um die Zeichenfolge zu erstellen, ausreichend lokalisiert
SwiftArchitect
1
Diese Antwort ist viel "Objective-C" und nützlicher als die akzeptierte Antwort. Sie brauchen switchoder if elseAussagen damit nicht. NSDateComponentsFormatterkümmert sich um alles. Stunden, Minuten, Sekunden ohne Sorgen gedruckt.
rustyMagnet
17

Brian Ramsays Code, de-pseudofied:

- (NSString*)formattedStringForDuration:(NSTimeInterval)duration
{
    NSInteger minutes = floor(duration/60);
    NSInteger seconds = round(duration - minutes * 60);
    return [NSString stringWithFormat:@"%d:%02d", minutes, seconds];
}
Yang Meyer
quelle
Dies lokalisiert nicht
SwiftArchitect
7

Hier ist eine Swift-Version:

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

Kann so verwendet werden:

let (d,h,m,s) = durationsBySecond(seconds: duration)
println("time left: \(d) days \(h) hours \(m) minutes \(s) seconds")
Jochen Bedersdorfer
quelle
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);

Ausgänge:

timeLater: 22:27
timeLeft: 1 hours 29 minutes  59 seconds
Polarware
quelle
Es ist wirklich ein perfektes Beispiel, um ein Datum zu
verbergen
5

Da es im Wesentlichen ein Doppel ...

Teilen Sie durch 60,0 und extrahieren Sie den Integralteil und den Bruchteil.

Der integrale Bestandteil ist die gesamte Anzahl von Minuten.

Multiplizieren Sie den Bruchteil erneut mit 60,0.

Das Ergebnis sind die verbleibenden Sekunden.


quelle
3

Denken Sie daran, dass es sich bei der ursprünglichen Frage um eine Zeichenfolgenausgabe handelt, nicht um Pseudocode oder einzelne Zeichenfolgenkomponenten.

Ich möchte es in die folgende Zeichenfolge konvertieren: "5:26"

Vielen Antworten fehlen die Internationalisierungsprobleme, und die meisten führen die mathematischen Berechnungen von Hand durch. Alles nur so 20. Jahrhundert ...

Mach die Mathe nicht selbst (Swift 4)

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

5:26


Nutzung von Bibliotheken

Wenn Sie wirklich einzelne Komponenten und angenehm lesbaren Code wünschen , lesen Sie SwiftDate :

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

5


Dank an @mickmaccallum und @polarwar für die angemessene Verwendung vonDateComponentsFormatter

SwiftArchitect
quelle
0

Wie ich das in Swift gemacht habe (einschließlich der String-Formatierung, um es als "01:23" anzuzeigen):

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
quelle
0

Swift 2 Version

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
quelle