NSTimeInterval zu HH: mm: ss?

85

Wenn ich ein NSTimeInterval habe, das auf 200.0 eingestellt ist, gibt es eine Möglichkeit, dies in 00:03:20 umzuwandeln. Ich dachte, ich könnte ein NSDate damit initialisieren und dann NSDateFormatter mit HH: mm: ss verwenden. Meine Frage ist, gibt es einen schnellen Weg, dies zu tun, oder muss ich die Nummer selbst auflösen und verwenden [NSString stringWithFormat: %02d:%02d:%02d, myHour, myMin, mySec]?

Fuzzygoat
quelle

Antworten:

198

Keine Notwendigkeit zu verwenden NSDateFormatteroder etwas anderes als Division und Modulo. NSTimeIntervalist nur ein Doppel mit Sekunden.

Schnell

func stringFromTimeInterval(interval: NSTimeInterval) -> String {
    let interval = Int(interval)
    let seconds = interval % 60
    let minutes = (interval / 60) % 60
    let hours = (interval / 3600)
    return String(format: "%02d:%02d:%02d", hours, minutes, seconds)
}

Ziel c

- (NSString *)stringFromTimeInterval:(NSTimeInterval)interval {
    NSInteger ti = (NSInteger)interval;
    NSInteger seconds = ti % 60;
    NSInteger minutes = (ti / 60) % 60;
    NSInteger hours = (ti / 3600);
    return [NSString stringWithFormat:@"%02ld:%02ld:%02ld", (long)hours, (long)minutes, (long)seconds];
}
Matthias Bauch
quelle
Sehr geschätzt, das habe ich mir gedacht, aber ich wollte nur überprüfen, ob mir etwas fehlt, das bereits im iOS SDK enthalten ist.
Fuzzygoat
1
Ich möchte darauf hinweisen, dass ":" nur in Englisch und einigen anderen Sprachen als Trennzeichen funktioniert. Finnisch verwendet zum Beispiel "." - so "15.02.59"
sgosha
@sgosha, genau, normalerweise neigt Apple dazu, Formatierer für diese bereitzustellen. Sollte ich stattdessen eine lokalisierte Zeichenfolge zum Formatieren verwenden?
Gerry Shaw
20
Dies ist die falsche Antwort, da das Trennzeichen nicht lokalisiert wird (wie in anderen Kommentaren erwähnt). Mit NSDateCompomentsFormatter können Sie Ihr Zeitintervall in einer einzigen Zeile korrekt formatieren, z. B. NSDateComponentsFormatter().stringFromTimeInterval(NSTimeInterval(duration))in Swift
Ilias Karim
4
Für die Lokalisierung und Zukunftssicherung besteht die richtige Lösung darin, NSDateComponentsFormatter zu verwenden, wie von @jrc
voidref
101

Verwenden Sie unter iOS 8 NSDateComponentsFormatter.

NSDateComponentsFormatter *dateComponentsFormatter = [[NSDateComponentsFormatter alloc] init];
NSLog(@"%@", [dateComponentsFormatter stringFromTimeInterval:200.0]);

gibt "3:20" aus.

NSDateComponentsFormatter *dateComponentsFormatter = [[NSDateComponentsFormatter alloc] init];
dateComponentsFormatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;
dateComponentsFormatter.allowedUnits = (NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond);
NSLog(@"%@", [dateComponentsFormatter stringFromTimeInterval:200.0]);

gibt "0:03:20" aus.

jrc
quelle
2
Schönes Update. Aber wenn es wirklich nur eine so einfache Berechnung ist, würde die Verwendung dieses Objekts dann keinen großen Aufwand bedeuten (solange kein dynamisches Format beteiligt ist)?
Julian F. Weinert
2
Sie benötigen die Formatierung, um sicherzustellen, dass die Zeichenfolge für verschiedene Gebietsschemas usw. korrekt angezeigt wird.
Max MacLeod
Wirklich winziger Kommentar, aber es ist seltsam, ein Beispiel für die C-Funktion für die ObjectiveC-Frage zu geben. Wahrscheinlich lohnt es sich, es in das ObjectiveC-Format zu ändern?
Rilakkuma
Hat mir eine Menge Code gespart! So habe ich es für OrangeIRC verwendet .
Ahyattdev
17

Swift 3- Version der Antwort von onmyway133 :

import Foundation

func format(_ duration: TimeInterval) -> String {
    let formatter = DateComponentsFormatter()
    formatter.zeroFormattingBehavior = .pad
    formatter.allowedUnits = [.minute, .second]

    if duration >= 3600 {
        formatter.allowedUnits.insert(.hour)
    }

    return formatter.string(from: duration)!
}


print(format(12)) // 0:12
print(format(65)) // 1:05
print(format(1750)) // 29:10
print(format(3890)) // 1:04:50
print(format(45720)) // 12:42:00
Scott Gardner
quelle
Ist das Erstellen eines DateComponentsFormatter in Bezug auf die Leistung teuer, wie z. B. ein DateFormatter oder ein NumberFormatter?
Moshe
1
Statt überprüft , ob es ein Stundenwert ist, Einstellung zeroFormattingBehaviorzu sein , [.dropLeading, .pad]könnte sein , eine bessere (weniger Code) Option.
MaddTheSane
Die Kommentare scheinen falsch zu sein. Dieser Code ergibt: 00:12, 01:05, 29:10, 01:04:50, 12:42:00
Jordan H
10

Einige zusätzliche Codezeilen, aber ich bin der Meinung, dass die Verwendung von NSDateComponents einen genaueren Wert ergibt.

- (NSString *)getTimeRepresentationFromDate:(NSDate *)iDate withTimeInterval:(NSTimeInterval)iTimeInterval {
    NSString *aReturnValue = nil;
    NSDate *aNewDate = [iDate dateByAddingTimeInterval:iTimeInterval]; 

    unsigned int theUnits = NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
    NSCalendar *aCalender = [NSCalendar currentCalendar];
    NSDateComponents *aDateComponents = [aCalender components:theUnits fromDate:iDate toDate:aNewDate options:0];

    aReturnValue = [NSString stringWithFormat:@"%d:%d:%d", [aDateComponents hour], [aDateComponents minute], [aDateComponents second]];

    return aReturnValue;
}
Roshit
quelle
Die obige Methode verwendet die 2 Daten, mit denen das TimeInterval erstellt wird. Sie können [NSDate-Datum] auch als Standardwert an den iDate-Parameter übergeben.
Roshit
2
Inwiefern ist dies "genauer" als die von @ matthias-bauch verwendete Methode?
jb
1
Mit dieser Methode erhalten Sie ein Zeitintervall in Sekunden, Stunden, Minuten, dh in Form von 60, während die Antwort von @ matthias-bauch dezimal ausgedrückt wird. Wenn Sie beispielsweise auf eine ausreichende Zeit warten, sehen Sie 1 Minute 79 Sekunden anstelle von 2 Minuten 19 Sekunden
Ashish Pisey
Dies ist eine viel bessere Lösung als die akzeptierte Lösung. Die Verwendung von ":" ist immer noch ein Problem für die Internationalisierung, aber zumindest ist dies über Schalttage und Sommerzeitgrenzen hinweg robust.
Evansflash
@AshishPisey Der Modulo-Operator verhindert alles, was größer als 59 ist.
Matthias Bauch
8

In Swift 2 , iOS 8+ . Dies stellt sicher, dass wir die Stunde nur bei Bedarf anzeigen

func format(duration: NSTimeInterval) -> String {
  let formatter = NSDateComponentsFormatter()
  formatter.zeroFormattingBehavior = .Pad

  if duration >= 3600 {
    formatter.allowedUnits = [.Hour, .Minute, .Second]
  } else {
    formatter.allowedUnits = [.Minute, .Second]
  }

  return formatter.stringFromTimeInterval(duration) ?? ""
}

Also hast du

print(format(12)) // 0:12
print(format(65)) // 1:05
print(format(1750)) // 29:10
print(format(3890)) // 1:04:50
print(format(45720)) // 12:42:00
onmyway133
quelle
4
NSTimeInterval ti = 3667;
double hours = floor(ti / 60 / 60);
double minutes = floor((ti - (hours * 60 * 60)) / 60);
double seconds = floor(ti - (hours * 60 * 60) - (minutes * 60));
Julian F. Weinert
quelle
4

Swift 4

DateComponentsFormatter().string(from: <# TimeInterval #>)

Ex:

DateComponentsFormatter().string(from: 59.0)
Jakub
quelle
3

Um den Vorschlag von Matthias Bauch zu "erweitern", würde ich dies in Swift zu einer berechneten Eigenschaft von NSTimeInterval machen:

extension NSTimeInterval {
  var stringValue: String {
    let interval = Int(self)
    let seconds = interval % 60
    let minutes = (interval / 60) % 60
    let hours = (interval / 3600)
    return String(format: "%02d:%02d:%02d", hours, minutes, seconds)
  }
}

Dies hat den Vorteil, dass es an den NSTimeIntervalTyp gebunden ist , nicht an Ihren View Controller oder an einen anderen Ort, an dem Sie diese Funktion einsetzen. Um zu verwenden, würden Sie etwas gehen wie:

let timeInterval = NSDate().timeIntervalSinceDate(start)        
self.elapsedTimeLabel.text = timeInterval.stringValue
Kenny Winker
quelle
Danke, Kenny! In meinem Fall brauchte ich sie separat, also habe ich Ihrer Erweiterung zusätzliche Variablen hinzugefügt: "var Sekunden: Int {Intervall lassen = Int (Selbst); Sekunden lassen = Intervall% 60; Sekunden zurückgeben}" und so weiter für Minuten und Stunden. Diese Verwendung lautet also: print ("Minuten: (timeInterval.minutes)")
Vitalii
3

Basierend auf der Antwort von @ onmyway133 ist hier die Swift 4-Version:

func format(duration: TimeInterval) -> String {
    let formatter = DateComponentsFormatter()
    formatter.zeroFormattingBehavior = .pad

    if duration >= 3600 {
        formatter.allowedUnits = [.hour, .minute, .second];
    } else {
        formatter.allowedUnits = [.minute, .second];
    }

    return formatter.string(from: duration) ?? "";
}
Vahid Amiri
quelle
0

direkt aus Apple Docs: in h Datei:

 @property(strong,nonatomic)NSDateComponentsFormatter *timerFormatter;

in m Datei

@synthesize timerFormatter;

- (void)viewDidLoad {
[super viewDidLoad];
NSDateComponentsFormatter *timerFormatter = [[NSDateComponentsFormatter alloc] init];
timerFormatter.unitsStyle = NSDateComponentsFormatterUnitsStylePositional; 
//10:59 Positional THIS ONE DOES NOT SEEM TO WORK iOS<9 WHEN <1Minute JUST SHOWS 01, 10m 59s Abbreviated, 10min 59sec Short, 10minutes 59seconds Full ...
timerFormatter.allowedUnits = NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond;
}

Wenn Sie Ihren NSTimeInterval timeInterval in einen hh: mm: ss-String konvertieren möchten, gehen Sie folgendermaßen vor:

NSString *txt=[timerFormatter stringFromTimeInterval:timeInterval];
Boris Gafurov
quelle
0

Ich denke, der Timer-Anteil sollte begrenzt werden. Da Matthias 'Code dieses Problem in Sekundenschnelle verursachte, verwende ich Folgendes, das leicht von dem von Matthias geändert wurde

    - (NSString *)stringFromTimeInterval:(NSTimeInterval)interval {
        int ti = (int) ceil(interval);
        int seconds = ti % 60;
        int minutes = (ti / 60) % 60;
        int hours = (ti / 3600);
        return [NSString stringWithFormat:@"%02d:%02d:%02d",hours, minutes, seconds];
    }
Mujtahid Akon
quelle
0

Ziel C- Version der Antwort von onmyway133

- (NSString*) formatTimeInterval:(NSTimeInterval) timeInterval {

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

    formatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;

    if (timeInterval > 3600) {
        formatter.allowedUnits = NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
    } else {
        formatter.allowedUnits = NSCalendarUnitMinute | NSCalendarUnitSecond;
    }

    return [formatter stringFromTimeInterval:timeInterval];
}
Fonix
quelle