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.