Come faccio abbattere un NSTimeInterval in anno, mesi, giorni, ore, minuti e secondi su iPhone?

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

Domanda

Ho un intervallo di tempo che si estende anni e voglio che tutti i componenti di tempo l'anno fino a pochi secondi.

Il mio primo pensiero è a intero dividere l'intervallo di tempo da secondi in un anno, sottrarre che da un totale parziale di secondi, dividere che, secondi in un mese, sottrarre tale da corsa totale e così via.

Che solo sembra contorto e ho letto che ogni volta che si sta facendo qualcosa che sembra complicata, probabilmente c'è un metodo incorporato.

C'è?

ho integrato secondo il metodo di Alex nel mio codice.

E 'in un metodo chiamato da un UIDatePicker nella mia interfaccia.

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);

Quando ho creato il selettore data per un anno 1 anno e 1 giorno, in passato, ottengo:

  

1 anno 1 mese 1 giorni 16 ore 0   minuti 20 secondi

che è 1 mese e 16 ore fuori. Se ho impostato il selettore data a 1 giorno, in passato, io sono fuori per lo stesso importo.

Aggiorna : Ho un app che calcola l'età in anni, dato il vostro compleanno (set da un UIDatePicker), eppure era spesso fuori. Questo dimostra c'era un'imprecisione, ma non riesco a capire da dove viene, si può?

È stato utile?

Soluzione

Breve descrizione

  1. Solo un altro approccio per completare la risposta di JBRWilkinson ma l'aggiunta di un po 'di codice. Può anche offre una soluzione al commento di Alex Reynolds.

  2. metodo Usa NSCalendar:

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

    • "I ritorni, come un NSDateComponents oggetto utilizzando componenti specificati, la differenza tra due date in dotazione". (Dalla documentazione API).

  3. Crea 2 NSDate la cui differenza è il NSTimeInterval si vuole abbattere. (Se il tuo NSTimeInterval deriva dal confronto tra 2 NSDate non c'è bisogno di fare questo passo, e non è nemmeno necessario il NSTimeInterval, basta applicare le date per il metodo NSCalendar).

  4. i tuoi citazioni da NSDateComponents

Codice di esempio

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

Altri suggerimenti

Questo codice è a conoscenza dei tempi di risparmio luce del giorno e altre possibili brutte cose.

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

Convertire l'intervallo in un NSDate utilizzando +dateWithIntervalSince1970, ottenere i componenti della data di metodo NSCalendar che l'utilizzo di -componentsFromDate.

SDK Riferimento

Da iOS 8 e, soprattutto, è possibile utilizzare NSDateComponentsFormatter

Ha metodi per convertire differenza di tempo in user friendly stringa formattata.

NSDateComponentsFormatter *formatter = [[NSDateComponentsFormatter alloc] init];
formatter.unitsStyle = NSDateComponentsFormatterUnitsStyleFull;

NSLog(@"%@", [formatter stringFromTimeInterval:1623452]);

In questo modo l'output - 2 settimane, 4 giorni, 18 ore, 57 minuti, 32 secondi

Questo funziona per me:

    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 differenza principale è che è necessario regolare per il fuso orario.

O c'è il mio metodo di classe. Essa non gestisce anni, ma che potrebbe essere facilmente addedn anche se è meglio per i piccoli timelaps come giorni, ore e minuti. Ci vuole plurali in considerazione e mostra solo ciò che è necessario:

+(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;

}

Ecco un'altra possibilità, un po 'più pulito:

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;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top