Компоненты 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 для британского летнего времени.
3 ответа:
Дело в том, что 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'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);
Вывод:
Обратите внимание, как меняются местные часы и минуты, но часть "сегодняшняя дата:" по-прежнему отражает GMT. Немного вводит в заблуждение программистов, Если вы спросите меня.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
Я согласен с аквой. Это очень обманчиво и привело меня к тому, что я несколько дней бил головой об экран. Он работает следующим образом: [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 в день даты, переданной в качестве аргумента.