2010-08-02 16 views
11

Tengo un método que extrae la hora y los segundos componentes de un NSDate descomponiéndolo en sus NSDateComponents. Mi código es el siguiente ...Componentes de NSDateComponents: fromDate y Zonas horarias

unsigned hourAndMinuteFlags = NSHourCalendarUnit | NSMinuteCalendarUnit; 
NSCalendar* calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; 
[calendar setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]]; 
NSDateComponents* travelDateTimeComponents = [calendar components:hourAndMinuteFlags fromDate:travelDate]; 
NSString* hours = [NSString stringWithFormat:@"%02i", [travelDateTimeComponents hour]]; 
NSString* minutes = [NSString stringWithFormat:@"%02i", [travelDateTimeComponents minute]]; 

Mi problema es que estoy perdiendo una hora en la conversión. Tengo la sospecha de que se debe a zonas horarias, pero por lo que puedo ver, tanto la fecha que se pasa como el calendario que se usa son ambos GMT.

Por ejemplo si paso en el siguiente objeto NSDate (esto es un registro de [Descripción NSDate]) ...

2010-08-02 08:00:00 +0100 

espero que llegue a 8 horas y 0 para los minutos, pero de hecho, vuelvo 7 por mis horas.

Mi hora del sistema es GMT, por lo tanto, el NSDate anterior es actualmente +0100 para el horario de verano británico.

Respuesta

4

El hecho es que GMT no es igual a British Summer Time. La fecha 2010-08-02 08:00:00 +0100 es igual a 2010-08-02 07:00:00 GMT, por lo que 7 horas es el resultado que debe esperar.

13

También tenga en cuenta que el objeto NSDate siempre muestra el tiempo de acuerdo con GMT, mientras que los componentes que está tirando desde esa fecha se modifican con la parte timeZoneWithName.

Ejemplo:

NSDate *today = [NSDate date]; 
NSLog(@"Today's date: %@",today); 

unsigned hourAndMinuteFlags = NSHourCalendarUnit | NSMinuteCalendarUnit; 
NSCalendar* calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; 
[calendar setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]]; 
NSDateComponents* travelDateTimeComponents = [calendar components:hourAndMinuteFlags fromDate:today]; 
NSString* hours = [NSString stringWithFormat:@"%02i", [travelDateTimeComponents hour]]; 
NSString* minutes = [NSString stringWithFormat:@"%02i", [travelDateTimeComponents minute]]; 

NSLog(@"Calendar: %@",calendar); 
NSLog(@"Travel Components: %@",travelDateTimeComponents); 
NSLog(@"Hours: %@",hours); 
NSLog(@"Minutes: %@",minutes); 

Salida de consola:

[Session started at 2011-01-23 12:59:17 -0700.] 
2011-01-23 12:59:19.755 testttt[5697:207] Today's date: 2011-01-23 19:59:19 +0000 
2011-01-23 12:59:19.756 testttt[5697:207] Calendar: <__NSCFCalendar: 0x4b2ca70> 
2011-01-23 12:59:19.757 testttt[5697:207] Travel Components: <NSDateComponents: 0x4b2de20> 
2011-01-23 12:59:19.757 testttt[5697:207] Hours: 19 
2011-01-23 12:59:19.758 testttt[5697:207] Minutes: 59 

Ahora bien, si cambiamos la zona horaria ...

NSDate *today = [NSDate date]; 
NSLog(@"Today's date: %@",today); 

unsigned hourAndMinuteFlags = NSHourCalendarUnit | NSMinuteCalendarUnit; 
NSCalendar* calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; 
[calendar setTimeZone:[NSTimeZone timeZoneWithName:@"MST"]]; 
NSDateComponents* travelDateTimeComponents = [calendar components:hourAndMinuteFlags fromDate:today]; 
NSString* hours = [NSString stringWithFormat:@"%02i", [travelDateTimeComponents hour]]; 
NSString* minutes = [NSString stringWithFormat:@"%02i", [travelDateTimeComponents minute]]; 

NSLog(@"Calendar: %@",calendar); 
NSLog(@"Travel Components: %@",travelDateTimeComponents); 
NSLog(@"Hours: %@",hours); 
NSLog(@"Minutes: %@",minutes); 

Salida:

2011-01-23 13:05:29.896 testttt[5723:207] Today's date: 2011-01-23 20:05:29 +0000 
2011-01-23 13:05:29.897 testttt[5723:207] Calendar: <__NSCFCalendar: 0x4e10020> 
2011-01-23 13:05:29.897 testttt[5723:207] Travel Components: <NSDateComponents: 0x4e0f6d0> 
2011-01-23 13:05:29.898 testttt[5723:207] Hours: 13 
2011-01-23 13:05:29.898 testttt[5723:207] Minutes: 05 

Observe cómo cambian las horas y minutos locales, pero la parte "Fecha de hoy:" todavía refleja GMT. Un poco engañoso para los programadores, si me preguntas.

3

Estoy de acuerdo con aqua. Es muy engañoso y me ha llevado días pegándome a la cabeza contra la pantalla. Funciona de esta manera: [NSDate date] siempre devuelve la fecha actual. Entonces en el ejemplo anterior será 2010-08-02 08:00:00. Cuando convertimos en NSDateComponents, el tiempo real se pierde y se convierte en un conjunto de enteros (hora, año, etc.) que ya no contienen la zona horaria.

Al convertir de nuevo a un objeto NSDate tomará los valores de año, mes, día, etc. y se los dará en relación con GMT, de ahí la hora perdida. Es solo la forma en que se decidió en el marco. Lo que hago es la siguiente:

+(NSDateComponents *)getComponentFromDate:(NSDate *)date { 

    NSCalendar * gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; 

    unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSWeekdayCalendarUnit | NSDayCalendarUnit; 
    NSDateComponents* components = [gregorian components:unitFlags fromDate:date]; 

    NSTimeZone* timeZone = [NSTimeZone localTimeZone]; 
    if(timeZone.isDaylightSavingTime) components.hour = ((int)timeZone.daylightSavingTimeOffset/3600); 

    [gregorian release]; 

    return components; 
} 

que me dará una versión 'corregida' de los componentes redondeados hasta la actualidad que cuando se aprobó el calendario para recuperar una fecha siempre serán establecidos a las 00:00: 00 en el día de la fecha pasada como argumento.

+0

Si ahora quisiera comparar el tiempo con 2 horas de apertura y cierre sin fecha, la prueba falla porque ahora el tiempo también está precedido por la fecha actual, mientras que las otras dos veces se crearán con un año base de 2000. Entonces cómo comparar en tal caso? – marciokoko

+0

Creo que la componente de conversión-> fecha tiene en cuenta la zona horaria del calendario.Debería poder hacer una conversión bidireccional sin pérdidas siempre que use el mismo calendario. –

Cuestiones relacionadas