2010-08-02 2 views
11

У меня есть метод, который извлекает час и второй компонент из NSDate, разбивая его на свои NSDateComponents. Мой код выглядит следующим образом:Компоненты NSDateComponents: fromDate и Time Zones

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

Моя проблема в том, что я теряю час при конвертации. У меня есть подозрение, что это связано с часовыми поясами, но насколько я могу видеть и дату передачи, и используемый календарь - GMT.

Например, если я прохожу в следующий объект NSDate (это журнал [описание NSDate]) ...

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

Я ожидаю, что я получаю 8 в течение нескольких часов и 0 минут, но я на самом деле вернусь 7 на мои часы.

Мое системное время: GMT, поэтому NSDate выше в настоящее время +0100 для британского Summer Time.

ответ

4

Дело в том, что GMT не равно британскому летнему времени. Дата 2010-08-02 08:00:00 +0100 равна 2010-08-02 07:00:00 GMT, поэтому 7 часов - результат, которого вы должны ожидать.

13

Также помните, что объект NSDate всегда показывает время согласно GMT, тогда как компоненты, которые вы вытягиваете с этой даты, изменяются частью timeZoneWithName.

Пример:

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

Консоль вывода:

[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 

Теперь, если мы изменим часовой пояс ...

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

Выход:

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 

Обратите внимание, как местные часы и минуты меняются, но часть «Сегодняшняя дата:» по-прежнему отражает GMT. Немного вводить в заблуждение программистов, если вы спросите меня.

3

Я согласен с aqua. Это очень вводит в заблуждение и привело меня к тому, что я ударился головой о экран. Он работает следующим образом: [NSDate date] всегда возвращает текущую дату. Таким образом, в приведенном выше примере это будет 2010-08-02 08:00:00. Когда мы конвертируем в NSDateComponents, фактическое время теряется и преобразуется в набор целых чисел (час, год и т. Д.), Которые больше не удерживают часовой пояс.

При преобразовании обратно в объект NSDate он принимает значения года, месяца, дня и т. Д. И передает их вам относительно GMT, следовательно, час утрачен. Это было так, как это было решено в рамках. Что я делаю следующее:

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

Это даст мне «исправленную» версию компонентов округления до текущего дня, когда передается в календарь, чтобы получить дату всегда будет установлено в 00:00: 00 в день, указанный в качестве аргумента.

+0

Так что, если бы я хотел сравнить сейчас время только с 2 днями открытия и закрытия бездействия, тест терпит неудачу, потому что теперь времени также предшествует дата, тогда как другие два раза будут созданы с базовым годом 2000 года. как сравнивать в таком случае? – marciokoko

+0

Я думаю, что данные о конверсиях-> учитывают часовой пояс календаря.Вы должны иметь возможность делать двустороннее преобразование без потерь при условии, что вы используете один и тот же календарь. –