2010-08-02 14 views
11

Ho un metodo che estrae l'ora e i secondi componenti formano un NSDate suddividendolo nei suoi NSDateComponents. Il mio codice è il seguente ...Componenti NSDateComponents: fromDate e Fusi orari

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

Il mio problema è che sto perdendo un'ora nella conversione. Ho il sospetto che sia dovuto a fusi orari, ma per quanto posso vedere sia la data che viene trasmessa sia il calendario utilizzato sono entrambi GMT.

Per esempio, se mi passa nella seguente oggetto NSDate (questo è il log di [descrizione NSDate]) ...

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

mi aspetto che ricevo 8 per ore e 0 per i minuti, ma io in realtà tornare indietro 7 per le mie ore.

Il mio orario di sistema è GMT, quindi l'NSDate sopra è attualmente +0100 per British Summer Time.

risposta

4

Il fatto è che GMT non è uguale all'ora legale britannica. La data 2010-08-02 08:00:00 +0100 è pari a 2010-08-02 07:00:00 GMT così sette ore è il risultato che si dovrebbe aspettare.

13

Ricorda inoltre che l'oggetto NSDate mostra sempre l'ora in base a GMT, mentre i componenti che stai prelevando da quella data vengono modificati dalla parte timeZoneWithName.

Esempio:

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

Console in uscita:

[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 

Ora, se si cambia il fuso orario ...

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

uscita:

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 

Notate come le ore locali e minuti cambiano, ma la "Data di oggi:" parte riflette ancora GMT. Un po 'fuorviante per i programmatori, se me lo chiedi.

3

Sono d'accordo con Aqua. È molto fuorviante e mi ha portato a giorni a colpire la testa contro lo schermo. Funziona così: [Data NSDate] restituisce sempre la data corrente. Quindi nell'esempio sopra sarà 2010-08-02 08:00:00. Quando ci convertiamo in NSDateComponents, il tempo effettivo è perduto e trasformato in una serie di numeri interi (ora, anno, ecc) che detengono più del fuso orario.

Quando si effettua la riconversione a un oggetto NSDate, verranno presi i valori dell'anno, del mese, del giorno ecc. E verranno consegnati al GMT, quindi all'ora persa. È solo il modo in cui è stato deciso nel quadro. Quello che faccio è la seguente:

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

che mi darà una versione 'corretta' dei componenti arrotondati per il giorno corrente, che quando passò al calendario per recuperare la data sarà sempre impostato a 00:00: 00 il giorno della data passato come argomento.

+0

Quindi, se volevo confrontare il tempo di ora solo con 2 ore di apertura e chiusura senza data, il test fallisce perché ora il tempo è anche preceduto dalla data di oggi mentre le altre due volte saranno create con un anno base di 2000. Quindi come confrontare in questo caso? – marciokoko

+0

Penso che i componenti di conversione-> data prendano in considerazione il fuso orario del calendario.Dovresti essere in grado di eseguire una conversione bidirezionale senza perdita purché tu utilizzi lo stesso calendario. –