NSCalendar dateFromComponents: часовой пояс GMT вместо systemTimeZone

Этот код

NSCalendar *calendar =[NSCalendar currentCalendar];
[gregorian setTimeZone:tz];

NSLog(@"%@", [gregorian timeZone]);

NSDateComponents *comp = [gregorian components:(NSYearCalendarUnit | NSMonthCalendarUnit) fromDate:[NSDate date]];

[comp setDay:info.day];
[comp setMonth:info.month];
[comp setYear:info.year];
[comp setHour:info.hour];
[comp setMinute:info.minute];
[comp setSecond:info.second];
[comp setTimeZone:tz];  

NSLog(@"%@", [comp timeZone]);
NSLog(@"%@", [gregorian dateFromComponents:comp]);

показывает в консоли следующее:

Europe/Moscow (MSKS) offset 14400 (Daylight)

Europe/Moscow (MSKS) offset 14400 (Daylight)

2011-08-31 20:00:00 +0000

Итак, часовой пояс для календаря и компонентов указан правильно, но [gregorian dateFromComponents:comp] возвращает значение NSDate с неправильным часовым поясом (GMT).

Что мне нужно исправить, чтобы получить правильный часовой пояс?


person Mitry    schedule 06.09.2011    source источник
comment
Если вы выполните NSLog NSDateobject напрямую, вы всегда получите его представление по Гринвичу. Во всяком случае, NSDate объекты вообще не имеют понятия о часовых поясах. Они представляют собой абсолютный момент времени, отсчитываемый от контрольной даты. Вы можете получить различные удобочитаемые представления даты для разных часовых поясов, используя NSDateFormatter, но они это, представления.   -  person albertamg    schedule 07.09.2011
comment
Я думаю, что NSDate скрывает часовой пояс, из которого он был получен, в незначительных битах временной метки. Однако это предназначено только для использования [описание NSDate] и в лучшем случае ненадежно.   -  person Hot Licks    schedule 07.09.2011
comment
Да, ребята, вы правы. Спасибо, теперь я понял :)   -  person Mitry    schedule 07.09.2011
comment
NSDate - это количество секунд с первого момента 01.01.2001 по Гринвичу. Обратите внимание на часовой пояс. Метод описания использует часовой пояс пользователя, поэтому он не является истинным NSDate, но делает людей счастливыми в представлении.   -  person zaph    schedule 07.09.2011


Ответы (2)


Результат, который вы видите, совершенно нормальный. Если вы выполните NSLog для объекта NSDate напрямую, вы получите все, что возвращает метод description, то есть представление даты по Гринвичу (но это не высечено в камне).

NSDate объекты не зависят от часовых поясов. NSDate представляет абсолютный момент времени, отсчитываемый от контрольной даты. Например, на момент написания текущая дата представляет собой что-то вроде 337035053.199801 (секунд с контрольной даты), что может быть представлено как 2011-09-06 20:50:53 GMT или 2011-09-06 22:50:53 CEST. Оба являются разными удобочитаемыми представлениями одной и той же даты.

В заключение, что вам нужно, чтобы получить правильный часовой пояс? Вам нужно использовать NSDateFormatter, чтобы получить строковое представление вашего NSDate в любом часовом поясе, который вам нравится.

person albertamg    schedule 06.09.2011
comment
Референтной датой фактически является первое мгновение 1 января 2001 г. по Гринвичу. В любом случае, это момент времени, когда мы начинаем считать, т.е. 0.0, и вы можете выразить этот момент времени, используя любой часовой пояс. - person albertamg; 07.09.2011
comment
И место в космосе, а именно часовой пояс. - person zaph; 07.09.2011
comment
NSDates не зависят от GMT или любого другого часового пояса в этом отношении (да, внутри они хранят дельту от контрольной даты, выраженной в GMT). Неправильно попробовать для преобразования даты в другой часовой пояс путем изменения исходной даты и получения другого объекта даты. NSDate представляет собой инвариантный момент времени, и он не зависит от того, в какой части мира вы находитесь. Существует только одно NSDate, которое представляет now, а не несколько NSDate для каждого часового пояса. - person albertamg; 07.09.2011
comment
Из документации Apple: единственный примитивный метод NSDate, timeIntervalSinceReferenceDate, обеспечивает основу для всех других методов в интерфейсе NSDate. Этот метод возвращает значение времени относительно абсолютной ссылочной даты - первого момента 1 января 2001 г. по Гринвичу. - person zaph; 07.09.2011
comment
Как я уже сказал, да, внутри они хранят дельту от контрольной даты, выраженной в GMT. Я хочу сказать, что даты не относятся к часовым поясам. Такие вещи, как - (NSDate*) convertToUTC:(NSDate*)sourceDate;, которые я видел, - ерунда. - person albertamg; 07.09.2011

Этот вопрос возникает довольно часто, и ответ заключается в использовании _ 1_, чтобы получить желаемый результат для формата даты. В настоящее время он всегда печатается с часовым поясом GMT. Вот обсуждение документации для NSDate:

Обсуждение
Не гарантируется, что представление остается постоянным в разных версиях операционной системы. Чтобы отформатировать дату, вы должны вместо этого использовать объект форматирования даты (см. NSDateFormatter и Руководство по форматированию данных)

person Joe    schedule 06.09.2011