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.
pseudo-code:
minutes = floor(326.4/60)
seconds = round(326.4 - minutes * 60)
Brève description
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.
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).
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
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 :-)
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);
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#>) {
// ...
}
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];
}
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")
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
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.
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 ...
let timeInterval: TimeInterval = 326.4
let dateComponentsFormatter = DateComponentsFormatter()
dateComponentsFormatter.unitsStyle = .positional
if let formatted = dateComponentsFormatter.string(from: timeInterval) {
print(formatted)
}
5:26
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
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)
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"