Дата с 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];

Это имеет следующие преимущества для меня:

  1. Это пользователи меньше иваров.
  2. Это меньше кода.
  3. Он всегда возвращает полночь в этот день, независимо от того, действует ли DST.

Я полагаю, что вы правы насчет високосных секунд / суммарных изменений часов, учитывающих проблему времени. Действительно ли даты, с которыми вы имеете дело в прошлом, или это просто произвольная эпоха?

В любом случае вы можете попытаться определить новую эпоху, которая намного ближе к сегодняшнему дню (скажем, эпоха Какао). Рассчитайте дельту дня между новой и старой эпохами и сохраните ее как постоянную. Когда вам нужно обработать дату, примените эту дельту к дате, а затем используйте существующую технику NSCalendar, но с новой эпохой вместо старой. Надеемся, что это позволит избежать проблемы смещения часов, которую вы видите.

Обратите внимание, что iOS учитывает очень непонятные правила для разных часовых поясов. Скорее всего, в полночь 1 января. 1600 в вашем часовом поясе фактически было в 7:12:28 UTC. Было много случаев, когда люди жаловались на ошибки в преобразованиях дат, а затем кто-то выяснял, что на самом деле они находятся в часовом поясе, который сделал странное изменение календаря много лет назад.

Вы должны сначала выяснить, что именно представляет NSDate ваши данные. "Количество дней с 1 января 1600 года" - это нонсенс, потому что вам нужен часовой пояс! Что вы должны сделать: найти "старый" номер, на котором вы знаете, какой день он должен представлять. Например, если вы "знаете", что 143671 должен быть 11 мая 1993 года в вашем часовом поясе, то начните с этой даты в качестве корневой даты и добавьте к ней (x - 143671) дней.

Другие вопросы по тегам