Come convertire un NSTimeInterval (secondi) in minuti


104

Ne ho una quantità secondspassata da un certo evento. È archiviato in un NSTimeIntervaltipo di dati.

Voglio convertirlo in minutese seconds.

Per esempio ho: "326,4" secondi e voglio convertirlo nella seguente stringa: "5:26".

Qual è il modo migliore per raggiungere questo obiettivo?

Grazie.

Risposte:


147

pseudo-codice:

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

90
Penso che valga anche la pena ricordare che un NSTimerInterval è solo un typedef per double.
Armentage

4
Vedi la risposta di Albaregar - è un modo migliore per farlo (più codice ma più flessibile,
gestibile

1
Quel codice è molto costoso, tuttavia. Per una rapida conversione di una durata in secondi, questa risposta è migliore.
SpacyRicochet

2
Tieni presente che questa risposta ti darà cose come 1:60. Guarda la risposta di StratFan che è più vicina alla verità. Ma rimuovi il pavimento e intorno e dovresti essere a casa libero.
InvulgoSoft

La risposta di Mick MacCallum di seguito al momento della stesura di questo commento sembra essere la più aggiornata e realizzata tramite l'utilizzo dell'API nativa.
Tomasz Nazarenko

183

Breve descrizione

  1. La risposta di Brian Ramsay è più conveniente se vuoi convertire solo in minuti.
  2. Se vuoi Cocoa API fallo per te e converti il ​​tuo NSTimeInterval non solo in minuti ma anche in giorni, mesi, settimane, ecc ... Penso che questo sia un approccio più generico
  3. Usa il metodo NSCalendar:

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

    • "Restituisce, come oggetto NSDateComponents utilizzando componenti specificati, la differenza tra due date fornite". Dalla documentazione API.

  4. Crea 2 NSDate la cui differenza è l'NSTimeInterval che desideri convertire. (Se il tuo NSTimeInterval proviene dal confronto di 2 NSDate non è necessario eseguire questo passaggio e non è nemmeno necessario NSTimeInterval).

  5. Ottieni i tuoi preventivi da NSDateComponents

Codice di esempio

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

Problemi noti

  • Troppo per una semplice conversione, hai ragione, ma è così che funziona l'API.
  • Il mio consiglio: se ti abitui a gestire i tuoi dati temporali utilizzando NSDate e NSCalendar, l'API farà il duro lavoro per te.

4
Sicuramente è un sacco di soluzione alternativa solo per fare una piccola conversione, ma sembra comodo, modulare e molto flessibile, vota per questo codice di esempio @Albaregar.
Rigo Vides

2
+1 Per una buona risposta esauriente, tuttavia, questo codice è piuttosto costoso.
Nick Weaver

1
+1 ... un avvertimento. Fai attenzione a usare questo stile di codice se devi arrotondare per eccesso le frazioni di secondo. Il comportamento predefinito di - [Componenti NSCalendar: fromDate: toDate: opzioni:] può incasinare nello scenario in cui il componente toDate è 31,5 secondi (ad esempio) avanti rispetto a fromDate - i componenti restituiti avranno 31 nel campo dei secondi. C'è un parametro opzionale di NSWrapCalendarComponents, ma dalla sperimentazione (limitata) che ho fatto con questo, va a capo al secondo più vicino piuttosto che arrotondare per eccesso o per difetto. Il tuo chilometraggio può variare.
David Doyle

%ldse sei in una macchina a 64 bit.
Anoop Vaidya

5
Le persone che lo trovano (come Nick Weaver) penseranno che il codice sembra lento. Non lo è. Sto facendo un'app per il timer e ho appena testato la versione di Albaregar contro qualcosa nello stile di Brian Ramsey (e altri) ... e sorprendentemente, anche sondando 100 volte al secondo (che è tremendo eccessivo) su un dispositivo relativamente lento (4S ) c'era una differenza inferiore all'1% nell'utilizzo del processore.
mmc

42

Tutti questi sembrano più complicati di quanto dovrebbero essere! Ecco un modo breve e dolce per convertire un intervallo di tempo in ore, minuti e secondi:

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;

Nota quando metti un float in un int, ottieni automaticamente floor (), ma puoi aggiungerlo ai primi due se se ti fa sentire meglio :-)


Eccezionale! Ho provato il codice di Ramsay anche se sembra essere uscito di un secondo.
uplearnedu.com

Manca un punto e virgola nel tuo codice ma non mi permette di modificarlo per risolverlo.
Jeef

Penso che il tuo approccio sia il migliore: semplice, porta a termine il lavoro e "leggero" sulle zecche. Perfetto.
BonanzaDriver

29

Perdonami per essere una vergine di Stack ... non sono sicuro di come rispondere alla risposta di Brian Ramsay ...

L'utilizzo di round non funzionerà per i secondi valori compresi tra 59,5 e 59,99999. Il secondo valore sarà 60 durante questo periodo. Usa trunc invece ...

 double progress;

 int minutes = floor(progress/60);
 int seconds = trunc(progress - minutes * 60);

1
In realtà basta rimuovere del tutto il pavimento e il bagagliaio / rotondo. :)
InvulgoSoft

@StratFan Puoi aggiungere ore alla tua risposta?
Shmidt

27

Se stai mirando a iOS 8 o OS X 10.10 o superiore, questo è diventato molto più semplice. La nuova NSDateComponentsFormatterclasse ti consente di convertire un datoNSTimeInterval dal suo valore in secondi in una stringa localizzata da mostrare all'utente. Per esempio:

Objective-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

veloce

let interval = 326.4

let componentFormatter = NSDateComponentsFormatter()

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

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

NSDateCompnentsFormatterconsente inoltre che questo output sia in forme più lunghe. Maggiori informazioni possono essere trovate nell'articolo NSFormatter di NSHipster . E a seconda delle classi con cui stai già lavorando (in caso contrario NSTimeInterval), potrebbe essere più conveniente passare al formattatore un'istanza NSDateComponentso due NSDateoggetti, cosa che può essere eseguita anche tramite i seguenti metodi.

Objective-C

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

veloce

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

if let formattedString = componentFormatter.stringFromDateComponents(<#T##components: NSDateComponents##NSDateComponents#>) {
    // ...
}

Questo è il modo corretto per creare la stringa, adeguatamente localizzata
SwiftArchitect

1
Questa risposta è molto più "Objective-C" e utile della risposta accettata. Non è necessario switcho if elsedichiarazioni con questo. NSDateComponentsFormattersi prende cura di tutto. Ore, minuti, secondi stampati senza alcuna preoccupazione.
rustyMagnet

17

Il codice di Brian Ramsay, de-pseudofied:

- (NSString*)formattedStringForDuration:(NSTimeInterval)duration
{
    NSInteger minutes = floor(duration/60);
    NSInteger seconds = round(duration - minutes * 60);
    return [NSString stringWithFormat:@"%d:%02d", minutes, seconds];
}

Questo non si localizza
SwiftArchitect

7

Ecco una versione 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)
}

Può essere usato in questo modo:

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

Uscite:

timeLater: 22:27
timeLeft: 1 hours 29 minutes  59 seconds

è un esempio davvero perfetto per
nascondere

5

Dal momento che è essenzialmente un doppio ...

Dividi per 60,0 ed estrai la parte integrale e la parte frazionaria.

La parte integrante sarà il numero intero di minuti.

Moltiplica nuovamente la parte frazionaria per 60,0.

Il risultato saranno i secondi rimanenti.


3

Ricorda che la domanda originale riguarda un output di stringa, non pseudo-codice o singoli componenti di stringa.

Voglio convertirlo nella seguente stringa: "5:26"

Molte risposte mancano dei problemi di internazionalizzazione e la maggior parte esegue i calcoli matematici a mano. Tutto solo così 20 ° secolo ...

Non fare la matematica da solo (Swift 4)

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

05:26


Sfrutta le biblioteche

Se vuoi davvero componenti individuali e un codice piacevolmente leggibile, dai un'occhiata a SwiftDate :

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

5


Crediti a @mickmaccallum e @polarwar per un utilizzo adeguato diDateComponentsFormatter


0

Come l'ho fatto in Swift (inclusa la formattazione della stringa per mostrarla come "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

Versione 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"
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.