Comment puis-je réduire une NSTimeInterval en année, mois, jours, heures, minutes et secondes sur iPhone?

StackOverflow https://stackoverflow.com/questions/1237778

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?

Était-ce utile?

La solution

Brève description

  1. 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.

  2. 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).

  3. 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).

  4. 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.

SDK Référence

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;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top