web-dev-qa-db-fra.com

Comment convertir un NSTimeInterval (secondes) en minutes

J'ai un certain nombre de secondes qui ont passé d'un certain événement. Il est stocké dans un type de données NSTimeInterval.

Je veux le convertir en minutes et en secondes.

Par exemple, j'ai: "326,4" secondes et je veux le convertir en chaîne suivante: "5:26".

Quel est le meilleur moyen d'atteindre cet objectif?

Merci.

104
Ilya Suzdalnitski

pseudo-code:

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

Brève description

  1. La réponse de Brian Ramsay est plus pratique si vous souhaitez uniquement convertir en minutes.
  2. Si vous voulez que l'API Cocoa le fasse à votre place et convertisse votre NSTimeInterval non seulement en minutes, mais également en jours, mois, semaine, etc.
  3. Utilisez la méthode NSCalendar:

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

    • "Renvoie, en tant qu'objet NSDateComponents à l'aide de composants spécifiés, la différence entre deux dates fournies". De la documentation de l'API. 

  4. Créez 2 NSDate dont la différence est le NSTimeInterval que vous souhaitez convertir. (Si votre NSTimeInterval provient de la comparaison de 2 NSDate, vous n'avez pas besoin de faire cette étape et vous n'avez même pas besoin de NSTimeInterval).

  5. Obtenez vos devis de NSDateComponents

Exemple de code

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

Problèmes connus

  • Vous avez raison, c'est trop, mais c'est ainsi que fonctionne l'API.
  • Ma suggestion: si vous avez l'habitude de gérer vos données de temps à l'aide de NSDate et de NSCalendar, l'API fera le travail difficile pour vous.
182
Albaregar

Tout cela a l'air plus compliqué qu'il ne le faut! Voici un moyen simple et rapide de convertir un intervalle de temps en heures, minutes et secondes:

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;

Notez que lorsque vous mettez un float dans un int, vous obtenez automatiquement floor (), mais vous pouvez l'ajouter aux deux premiers si vous vous sentez mieux :-)

40
Prasad

Pardonnez-moi d'être vierge, je ne sais pas trop comment répondre à la réponse de Brian Ramsay.

L'utilisation de round ne fonctionnera pas pour les secondes valeurs comprises entre 59,5 et 59,99999. La deuxième valeur sera 60 pendant cette période. Utilisez trunc à la place ...

 double progress;

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

Si vous ciblez au-dessus de iOS 8 ou OS X 10.10, cela devient beaucoup plus facile. La nouvelle classe NSDateComponentsFormatter vous permet de convertir une NSTimeInterval donnée de sa valeur en secondes en une chaîne localisée à afficher pour l'utilisateur. Par exemple:

Objectif 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

Rapide

let interval = 326.4

let componentFormatter = NSDateComponentsFormatter()

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

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

NSDateCompnentsFormatter permet également à cette sortie d'être sous une forme plus longue. Vous trouverez plus d'informations dans l'article de NSHipster NSFormatter . Et en fonction des classes avec lesquelles vous travaillez déjà (si ce n'est pas NSTimeInterval), il peut être plus pratique de transmettre au formateur une instance de NSDateComponents ou deux objets NSDate, ce qui peut également être fait via les méthodes suivantes.

Objectif c

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

Rapide

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

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

Le code de Brian Ramsay, dé-pseudofié:

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

Voici une version de 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)
}

Peut être utilisé comme ceci:

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

Les sorties: 

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

Puisqu'il s'agit essentiellement d'un double ...

Divisez par 60,0 et extrayez la partie intégrale et la partie fractionnaire.

La partie intégrale sera le nombre entier de minutes.

Multipliez à nouveau la partie fractionnaire par 60,0.

Le résultat sera les secondes restantes.

5
Policywatcher

N'oubliez pas que la question d'origine concerne une sortie de chaîne, pas un pseudo-code ou des composants de chaîne individuels.

Je veux le convertir dans la chaîne suivante: "5:26"

De nombreuses réponses manquent aux problèmes d'internationalisation et la plupart font les calculs mathématiques à la main. Tout ça pour le 20ème siècle ...

Ne faites pas les maths vous-même (Swift 4)

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

5:26


Effet de levier sur les bibliothèques

Si vous voulez vraiment des composants individuels et un code facilement lisible, consultez SwiftDate :

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

5


Crédits à @mickmaccallum et @polarwar pour une utilisation adéquate de DateComponentsFormatter

1
SwiftArchitect

Comment je l'ai fait dans Swift (y compris le formatage de la chaîne pour l'indiquer comme "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
SilentDirge

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"
0
SPatel