Comment puis-je réduire une NSTimeInterval en année, mois, jours, heures, minutes et secondes sur iPhone?
-
11-09-2019 - |
Question
J'ai un intervalle de temps qui couvre des années et je veux que tous les composants de temps de l'année jusqu'à secondes.
Ma première pensée est à l'entier diviser l'intervalle de temps par seconde en un an, soustrayez un total de secondes en cours d'exécution, diviser par seconde en un mois, soustrayez du total et en cours d'exécution ainsi de suite.
Ce tout semble alambiqué et j'ai lu que chaque fois que vous faites quelque chose qui ressemble alambiqué, il y a probablement une méthode intégrée.
Y at-il?
I intégrée 2ème méthode d'Alex dans mon code.
Il 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);
Quand je mets le sélecteur de date à une date 1 an et 1 jour dans le passé, je reçois:
1 an 1 mois 1 jours 16 heures 0 minutes 20 secondes
qui est de 1 mois et 16 heures de repos. Si je mets le sélecteur de date 1 jour dans le passé, je suis hors du même montant.
Mise à jour : J'ai une application qui calcule votre âge en années, compte tenu de votre anniversaire (ensemble d'un UIDatePicker), mais il était souvent hors. Cela prouve qu'il y avait une inexactitude, mais je ne peux pas comprendre d'où il vient, pouvez-vous?
La solution
Brève description
-
Juste une autre approche pour compléter la réponse de JBRWilkinson, mais en ajoutant un code. Il propose toute une solution au commentaire de Alex Reynolds.
-
Utiliser la méthode NSCalendar:
-
(NSDateComponents *)components:(NSUInteger)unitFlags fromDate:(NSDate *)startingDate toDate:(NSDate *)resultDate options:(NSUInteger)opts
-
« retour, comme un NSDateComponents objet en utilisant des composants spécifiques, la différence entre deux dates fournies ». (A partir de la documentation de l'API).
-
-
Créer 2 NSDate dont la différence est la NSTimeInterval que vous voulez briser. (Si votre NSTimeInterval vient de comparer 2 NSDate vous n'avez pas besoin de faire cette étape, et vous ne même pas besoin de la NSTimeInterval, il suffit d'appliquer les dates de la méthode NSCalendar).
-
Obtenez vos citations 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]);
Autres conseils
Ce code est conscient des temps d'économie de lumière du jour 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]);
Convertir votre intervalle dans un NSDate
utilisant +dateWithIntervalSince1970
, obtenir les composants de la date hors de la méthode de NSCalendar
de qu'utiliser -componentsFromDate
.
De iOS8 et ci-dessus, vous pouvez utiliser NSDateComponentsFormatter
Il a des méthodes pour convertir la différence de temps facile à utiliser chaîne formatée.
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
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 est que vous devez régler le fuseau horaire.
Ou il est ma méthode de classe. Il ne gère pas des années, mais cela pourrait facilement être addedn mais il vaut mieux pour les petits comme timelaps jours, heures et minutes. Il prend en compte pluriels et montre seulement 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;
}
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.
...
- (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;
}
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;