J'ai un intervalle de temps qui s'étend sur des années et je veux toutes les composantes de temps de l'année à quelques secondes.
Ma première pensée est de diviser l'intervalle de temps en secondes dans une année, de le soustraire d'un total cumulé de secondes, de le diviser en secondes dans un mois, de le soustraire du total cumulé, etc.
Cela semble juste compliqué et j'ai lu que chaque fois que vous faites quelque chose qui semble compliqué, il y a probablement une méthode intégrée.
Y a-t-il?
J'ai intégré la 2ème méthode d'Alex dans mon code.
C'est dans une méthode appelée par un UIDatePicker dans mon interface.
NSDate *now = [NSDate date];
NSDate *then = self.datePicker.date;
NSTimeInterval howLong = [now timeIntervalSinceDate:then];
NSDate *date = [NSDate dateWithTimeIntervalSince1970:howLong];
NSString *dateStr = [date description];
const char *dateStrPtr = [dateStr UTF8String];
int year, month, day, hour, minute, sec;
sscanf(dateStrPtr, "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minute, &sec);
year -= 1970;
NSLog(@"%d years\n%d months\n%d days\n%d hours\n%d minutes\n%d seconds", year, month, day, hour, minute, sec);
Lorsque je règle le sélecteur de date sur une date de 1 an et 1 jour dans le passé, j'obtiens:
1 ans 1 mois 1 jours 16 heures 0 minutes 20 secondes
qui est de 1 mois et 16 heures de repos. Si j'ai réglé le sélecteur de date sur 1 jour dans le passé, je suis hors tension du même montant.
pdate: J'ai une application qui calcule votre âge en années, compte tenu de votre anniversaire (défini à partir d'un UIDatePicker), mais il était souvent désactivé. Cela prouve qu'il y avait une inexactitude, mais je ne peux pas comprendre d'où elle vient, pouvez-vous?
Brève description
Juste une autre approche pour compléter la réponse de JBRWilkinson mais en ajoutant du code. Il peut également offrir une solution au commentaire d'Alex Reynolds.
Utilisez la méthode NSCalendar:
(NSDateComponents *)components:(NSUInteger)unitFlags fromDate:(NSDate *)startingDate toDate:(NSDate *)resultDate options:(NSUInteger)opts
"Renvoie, en tant qu'objet NSDateComponents utilisant les composants spécifiés, la différence entre deux dates fournies". (D'après la documentation de l'API).
Créez 2 NSDate dont la différence est le NSTimeInterval que vous souhaitez décomposer. (Si votre NSTimeInterval vient de la comparaison de 2 NSDate, vous n'avez pas besoin de faire cette étape, et vous n'avez même pas besoin du NSTimeInterval, appliquez simplement les dates à la méthode NSCalendar).
Obtenez vos devis de NSDateComponents
Exemple de code
// The time interval
NSTimeInterval theTimeInterval = ...;
// 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
NSCalendarUnit unitFlags = NSHourCalendarUnit | NSMinuteCalendarUnit | NSDayCalendarUnit | NSMonthCalendarUnit;
NSDateComponents *breakdownInfo = [sysCalendar components:unitFlags fromDate:date1 toDate:date2 options:0];
NSLog(@"Break down: %i min : %i hours : %i days : %i months", [breakdownInfo minute], [breakdownInfo hour], [breakdownInfo day], [breakdownInfo month]);
Ce code est conscient des heures d'été et d'autres choses désagréables possibles.
NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [gregorianCalendar components: (NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit | NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit )
fromDate:startDate
toDate:[NSDate date]
options:0];
NSLog(@"%ld", [components year]);
NSLog(@"%ld", [components month]);
NSLog(@"%ld", [components day]);
NSLog(@"%ld", [components hour]);
NSLog(@"%ld", [components minute]);
NSLog(@"%ld", [components second]);
Convertissez votre intervalle en NSDate
en utilisant +dateWithIntervalSince1970
, extrayez les composants de date à l'aide de NSCalendar
's -componentsFromDate
méthode.
Depuis iOS8 et supérieur, vous pouvez utiliser NSDateComponentsFormatter
Il a des méthodes pour convertir la différence de temps dans une chaîne formatée conviviale.
NSDateComponentsFormatter *formatter = [[NSDateComponentsFormatter alloc] init];
formatter.unitsStyle = NSDateComponentsFormatterUnitsStyleFull;
NSLog(@"%@", [formatter stringFromTimeInterval:1623452]);
Cela donne la sortie - 2 semaines, 4 jours, 18 heures, 57 minutes, 32 secondes
Ou il y a ma méthode de classe. Il ne gère pas les années, mais cela pourrait facilement être ajouté, bien qu'il soit préférable pour les petits timelaps comme les jours, les heures et les minutes. Il prend en compte les pluriels et ne montre que ce qui est nécessaire:
+(NSString *)TimeRemainingUntilDate:(NSDate *)date {
NSTimeInterval interval = [date timeIntervalSinceNow];
NSString * timeRemaining = nil;
if (interval > 0) {
div_t d = div(interval, 86400);
int day = d.quot;
div_t h = div(d.rem, 3600);
int hour = h.quot;
div_t m = div(h.rem, 60);
int min = m.quot;
NSString * nbday = nil;
if(day > 1)
nbday = @"days";
else if(day == 1)
nbday = @"day";
else
nbday = @"";
NSString * nbhour = nil;
if(hour > 1)
nbhour = @"hours";
else if (hour == 1)
nbhour = @"hour";
else
nbhour = @"";
NSString * nbmin = nil;
if(min > 1)
nbmin = @"mins";
else
nbmin = @"min";
timeRemaining = [NSString stringWithFormat:@"%@%@ %@%@ %@%@",day ? [NSNumber numberWithInt:day] : @"",nbday,hour ? [NSNumber numberWithInt:hour] : @"",nbhour,min ? [NSNumber numberWithInt:min] : @"00",nbmin];
}
else
timeRemaining = @"Over";
return timeRemaining;
}
Cela fonctionne pour moi:
float *lenghInSeconds = 2345.234513;
NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:lenghInSeconds];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
[formatter setDateFormat:@"HH:mm:ss"];
NSLog(@"%@", [formatter stringFromDate:date]);
[formatter release];
La principale différence ici est que vous devez ajuster le fuseau horaire.
NSDate *date = [NSDate dateWithTimeIntervalSince1970:timeInterval];
// format: YYYY-MM-DD HH:MM:SS ±HHMM
NSString *dateStr = [date description];
NSRange range;
// year
range.location = 0;
range.length = 4;
NSString *yearStr = [dateStr substringWithRange:range];
int year = [yearStr intValue] - 1970;
// month
range.location = 5;
range.length = 2;
NSString *monthStr = [dateStr substringWithRange:range];
int month = [monthStr intValue];
// day, etc.
...
Voici une autre possibilité, un peu plus propre:
NSDate *date = [NSDate dateWithTimeIntervalSince1970:timeInterval];
NSString *dateStr = [date description];
const char *dateStrPtr = [dateStr UTF8String];
// format: YYYY-MM-DD HH:MM:SS ±HHMM
int year, month, day, hour, minutes, seconds;
sscanf(dateStrPtr, "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minutes, &seconds);
year -= 1970;
- (NSString *)convertTimeFromSeconds:(NSString *)seconds {
// Return variable.
NSString *result = @"";
// Int variables for calculation.
int secs = [seconds intValue];
int tempHour = 0;
int tempMinute = 0;
int tempSecond = 0;
NSString *hour = @"";
NSString *minute = @"";
NSString *second = @"";
// Convert the seconds to hours, minutes and seconds.
tempHour = secs / 3600;
tempMinute = secs / 60 - tempHour * 60;
tempSecond = secs - (tempHour * 3600 + tempMinute * 60);
hour = [[NSNumber numberWithInt:tempHour] stringValue];
minute = [[NSNumber numberWithInt:tempMinute] stringValue];
second = [[NSNumber numberWithInt:tempSecond] stringValue];
// Make time look like 00:00:00 and not 0:0:0
if (tempHour < 10) {
hour = [@"0" stringByAppendingString:hour];
}
if (tempMinute < 10) {
minute = [@"0" stringByAppendingString:minute];
}
if (tempSecond < 10) {
second = [@"0" stringByAppendingString:second];
}
if (tempHour == 0) {
NSLog(@"Result of Time Conversion: %@:%@", minute, second);
result = [NSString stringWithFormat:@"%@:%@", minute, second];
} else {
NSLog(@"Result of Time Conversion: %@:%@:%@", hour, minute, second);
result = [NSString stringWithFormat:@"%@:%@:%@",hour, minute, second];
}
return result;
}