Дата с 1600 до NSDate?
У меня есть дата, которая с 1 января 1600 года хранится в количестве дней, с которыми мне нужно иметь дело. Это устаревший формат даты, который мне нужно читать много раз в моем приложении.
Ранее я создавал календарь, пустые компоненты даты и корневую дату следующим образом:
self.gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier: NSGregorianCalendar
] autorelease];
id rootComponents = [[[NSDateComponents alloc] init] autorelease];
[rootComponents setYear: 1600];
[rootComponents setMonth: 1];
[rootComponents setDay: 1];
self.rootDate = [gregorian dateFromComponents: rootComponents];
self.offset = [[[NSDateComponents alloc] init] autorelease];
Затем, чтобы преобразовать целое число позже в дату, я использую это:
[offset setDay: theLegacyDate];
id eventDate = [gregorian dateByAddingComponents: offset
toDate: rootDate
options: 0];
(Я никогда не меняю значения в смещении где-либо еще.)
Проблема в том, что у меня другое время rootDate
на iOS против Mac OS X. На Mac OS X я получаю полночь. На iOS я получаю 8:12:28. (Похоже, до сих пор это не противоречит.) Когда я добавляю количество дней спустя, странное время остается.
ОС | legacyDate | rootDate | Дата события ======== | ========== | ==========================|========================== Mac OS X | 143671 | 1600-01-01 00:00:00 -0800 | 1993-05-11 00:00:00 -0700 iOS | 143671 | 1600-01-01 08:12:28 +0000 | 1993-05-11 07:12:28 +0000
В предыдущем выпуске моего продукта меня не волновало время; сейчас делаю. Почему странное время на iOS, и что мне с этим делать? (Я предполагаю, что разница в часах - летнее время.)
Я попытался установить часы, минуты и секунды для rootComponents на 0. Это не имеет никакого влияния. Если я установлю для них значение, отличное от 0, это добавит их к 8:12:28. Мне было интересно, имеет ли это какое-то отношение к високосным секундам или другим накопленным изменениям часов.
Или это совершенно неправильный подход для использования на iOS?
3 ответа
Похоже, правильный ответ - сделать вещи проще. Вместо создания rootDate я просто каждый раз строю дату из компонентов. Это должно быть не медленнее, и все еще держит код действительно близко к идее.
Начальная настройка:
self.gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier: NSGregorianCalendar
] autorelease];
self.components = [[[NSDateComponents alloc] init] autorelease];
[components setYear: 1600];
[components setMonth: 1];
(Очевидно, свойства и ivars корректируются.)
Позже, чтобы фактически преобразовать устаревшую дату в NSDate
:
[components setDay: 1 + theLegacyDate];
id eventDate = [gregorian dateFromComponents: components];
Это имеет следующие преимущества для меня:
- Это пользователи меньше иваров.
- Это меньше кода.
- Он всегда возвращает полночь в этот день, независимо от того, действует ли DST.
Я полагаю, что вы правы насчет високосных секунд / суммарных изменений часов, учитывающих проблему времени. Действительно ли даты, с которыми вы имеете дело в прошлом, или это просто произвольная эпоха?
В любом случае вы можете попытаться определить новую эпоху, которая намного ближе к сегодняшнему дню (скажем, эпоха Какао). Рассчитайте дельту дня между новой и старой эпохами и сохраните ее как постоянную. Когда вам нужно обработать дату, примените эту дельту к дате, а затем используйте существующую технику NSCalendar, но с новой эпохой вместо старой. Надеемся, что это позволит избежать проблемы смещения часов, которую вы видите.
Обратите внимание, что iOS учитывает очень непонятные правила для разных часовых поясов. Скорее всего, в полночь 1 января. 1600 в вашем часовом поясе фактически было в 7:12:28 UTC. Было много случаев, когда люди жаловались на ошибки в преобразованиях дат, а затем кто-то выяснял, что на самом деле они находятся в часовом поясе, который сделал странное изменение календаря много лет назад.
Вы должны сначала выяснить, что именно представляет NSDate ваши данные. "Количество дней с 1 января 1600 года" - это нонсенс, потому что вам нужен часовой пояс! Что вы должны сделать: найти "старый" номер, на котором вы знаете, какой день он должен представлять. Например, если вы "знаете", что 143671 должен быть 11 мая 1993 года в вашем часовом поясе, то начните с этой даты в качестве корневой даты и добавьте к ней (x - 143671) дней.