¿Cómo puedo romper a un NSTimeInterval en años, meses, días, horas, minutos y segundos en el iPhone?

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

Pregunta

Tengo un intervalo de tiempo que se extiende por años y quiero que todos los componentes de tiempo de años hasta segundos.

Lo primero que pensé es a entero dividir el intervalo de tiempo por segundo en un año, restar que a partir de un total acumulado de segundos, divida que por segundo en un mes, restar que a partir de la ejecución total y así sucesivamente.

Eso sólo parece complicado y he leído que cada vez que usted está haciendo algo que parece complicado, es probable que haya un método integrado.

¿Hay?

integré segundo método de Alex en mi código.

Está en un método llamado por un UIDatePicker en mi interfaz.

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

Cuando me puse el selector de fecha para una fecha de 1 año y 1 día en el pasado, me sale:

  

1 año 1 meses 1 días 16 horas 0   minutos 20 segundos

, que es de 1 mes y 16 horas de descanso. Si fijo el selector de fechas 1 día en el pasado, estoy fuera por la misma cantidad.

Actualizar : Tengo una aplicación que calcula su edad en años, dada su cumpleaños (conjunto de una UIDatePicker), sin embargo, a menudo estaba fuera. Esto demuestra que había algún error, pero no puedo averiguar de dónde viene, ¿verdad?

¿Fue útil?

Solución

Breve descripción

  1. Sólo otro enfoque para completar la respuesta de JBRWilkinson pero añadiendo algún código. También se ofrece una solución a los comentarios de Alex Reynolds.

  2. Método de Uso NSCalendar:

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

    • "devoluciones, como un NSDateComponents objeto utilizando componentes especificados, la diferencia entre dos fechas suministrados". (A partir de la documentación de la API).

  3. Crea 2 NSDate cuya diferencia es la NSTimeInterval desea romper. (Si su NSTimeInterval proviene de la comparación de 2 NSDate que no es necesario realizar este paso, y usted ni siquiera necesita el NSTimeInterval, solo se aplica a las fechas el método NSCalendar).

  4. Obtener sus citas de NSDateComponents

Código de ejemplo

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

Otros consejos

Este código es consciente de los tiempos de ahorro de luz del día y otras cosas desagradables posibles.

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 el intervalo en un NSDate usando +dateWithIntervalSince1970, obtener los componentes de la fecha de método NSCalendar que el uso de -componentsFromDate.

SDK Referencia

De iOS8 y arriba se puede utilizar NSDateComponentsFormatter

Tiene métodos para convertir diferencia de tiempo en la cadena con formato de usuario amigable.

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

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

Esto da la salida - 2 semanas, 4 días, 18 horas, 57 minutos, 32 segundos

Esto funciona para mí:

    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 diferencia principal aquí es que usted necesita para ajustar la zona horaria.

O no es mi método de clase. No maneja años, pero que podría ser fácilmente addedn pesar de que es mejor para los pequeños como timelaps días, horas y minutos. Se toma en cuenta los plurales y sólo muestra lo que se necesita:

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

}

Aquí hay otra posibilidad, un poco más limpio:

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;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top