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


Tengo un intervalo de tiempo que abarca años y quiero todos los componentes de tiempo desde el año hasta los segundos.

Mi primer pensamiento es dividir el intervalo de tiempo por segundos en un año, restar eso de un total de segundos, dividir eso por segundos en un mes, restar eso del total y así sucesivamente.

Eso parece complicado y he leído que cada vez que estás haciendo algo que parece complicado, probablemente hay un método incorporado.

Es ¿ahí?

Integré el 2do 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 establezco el selector de fecha en una fecha de 1 año y 1 día en el pasado, obtengo:

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

Que es 1 mes y 16 horas libres. Si establezco el selector de fecha en 1 día en el pasado, estoy fuera por la misma cantidad.

Actualizar: Tengo una aplicación que calcula su edad en años, dado su cumpleaños (establecido de un UIDatePicker), sin embargo, a menudo estaba apagado. Esto prueba que hubo una inexactitud, pero no puedo averiguar de dónde viene, ¿verdad?

Author: Peter Hosey, 2009-08-06

9 answers

Breve Descripción

  1. Solo otro enfoque para completar la respuesta de JBRWilkinson pero añadiendo algo de código. También puede ofrecer una solución al comentario de Alex Reynolds.

  2. Utilice el método NSCalendar:

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

    • "Devuelve, como un objeto NSDateComponents usando componentes especificados, la diferencia entre dos fechas suministradas". (De la documentación de la API).

  3. Crear 2 NSDate cuya la diferencia es el NSTimeInterval que desea descomponer. (Si su NSTimeInterval proviene de comparar 2 NSDate, no necesita hacer este paso, y ni siquiera necesita el NSTimeInterval, simplemente aplique las fechas al método NSCalendar).

  4. Obtenga sus cotizaciones de NSDateComponents

Código de muestra

// 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]);
 99
Author: Albaregar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-16 14:49:46

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

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]);
 16
Author: vikingosegundo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-07 09:59:50

Desde iOS8 y superior puede usar NSDateComponentsFormatter

Tiene métodos para convertir la diferencia de tiempo en una cadena formateada fácil de usar.

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

 5
Author: Omkar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-19 12:52:37

Convierta su intervalo en un NSDate usando +dateWithIntervalSince1970, obtenga los componentes de fecha de eso usando el método NSCalendar's -componentsFromDate.

Referencia del SDK

 4
Author: JBRWilkinson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-18 16:11:18

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

 3
Author: doogilasovich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-06 02:00:40

O está mi método de clase. No maneja años, pero eso podría agregarse fácilmente, aunque es mejor para pequeños intervalos de tiempo como días, horas y minutos. Toma en cuenta los plurales y solo 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;
}
 3
Author: Nicolas Manzini,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-08 23:16:15
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.
...
 2
Author: Alex Reynolds,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-08-06 09:26:02

Aquí hay otra posibilidad, algo más limpia:

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;
 0
Author: Alex Reynolds,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-08-06 09:38:55
- (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;

}
 0
Author: taus-iDeveloper,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-07 21:34:54