Ответ 1
Дело в том, что GMT не равно британскому летнему времени. Дата 2010-08-02 08:00:00 +0100
равна 2010-08-02 07:00:00 GMT
, поэтому 7 часов - результат, который вы должны ожидать.
У меня есть метод, который извлекает час и второй компоненты из NSDate, разбивая его на его NSDateComponents. Мой код выглядит следующим образом:
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 для британского летнего времени.
Дело в том, что GMT не равно британскому летнему времени. Дата 2010-08-02 08:00:00 +0100
равна 2010-08-02 07:00:00 GMT
, поэтому 7 часов - результат, который вы должны ожидать.
Также имейте в виду, что объект NSDate
всегда показывает время в соответствии с GMT, тогда как компоненты, которые вы вытягиваете с этой даты, изменяются частью timeZoneWithName
.
Пример:
NSDate *today = [NSDate date];
NSLog(@"Today 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 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 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 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. Немного обманчива для программистов, если вы спросите меня.
Я согласен с 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 в день даты, переданной в качестве аргумента.