TimeZone в Ax2009
Запись от Владимир Максимов размещена 29.09.2014 в 16:33
Ну, хорошо, новое правило определения TimeZone добавили. А что делает форма TimeZonePatcher? О каких таких "исправлениях" идет речь?
Для начала, надо разобраться с "физикой" процесса
При создании полей на основе базового типа данных Types::UtcDateTime физически, на уровне базы данных создаются 2 поля:
1. Поле с типом DateTime хранящее время UTC
2. Поле, имя которого совпадает с именем поля DateTime, но с добавленным окончанием "TZID".
Поле *TZID является служебным и не отображется в среде Axapta. Хотя в таблице SqlDictionary присутствуют.
Например, в таблице BatchJob есть поле OrigStartDateTime, которое видно в списке полей этой таблицы в AOT. Но, кроме того, у этой же таблицы есть поле OrigStartDateTimeTZID, которое можно увидеть только на уровне базы данных SQL. В среде Axapta оно не видно
В поле *TZID записывается идентификатор временной зоны (TZID = Time Zone IDentifier). Таким идентификатором является значение поля таблицы TimeZonesRulesData.RuleID
Таблица TimeZonesRulesData это правила, определяющие "сдвиг" в минутах, который надо добавить (или вычесть) к значению поля DateTime
Логика чтения полей DateTime выглядит так:
1. Из поля DateTime считывается значение
2. Из поля *TZID считывается идентификатор правила чтения временных зон, определяется "сдвиг" в минутах и прибавляется к значению DateTime
Исключением из этого правила являются поля CreatedDateTime и ModifiedDateTime. Им в пару не создаются поля *TZID. Т.е. при их считывании всегда используется текущее правило "сдвига" времени в минутах.
Причина, по которой возникает необходимость "патчить" данные - это тот факт, что поле *TZID заполняется один раз в момент создания записи и больше уже не изменяется на протяжении всего времени существования записи.
Это значит, что если, например, до импорта новых правил определения временных зон Вы создадите пакетное задание, плановое дата/время которого будет, скажем, 01.11.2014 01:00:00, то, после импорта новых правил будет отображаться значение 01.11.2014 02:00:00. Почему? Да потому, что поле *TZID останется без изменений и будет ссылаться на правила расчета 2011 года. Т.е. добавлять к времени UTC (то, что сохранено в базе данных в поле DateTime) 4 часа, а не 3, как должно быть по новым правилам.
Следовательно, необходимо для всех дат, которые попали в область действия новых правил определения временных зон сделать замену:
1. В поле *TZID записать код записи нового правила
2. Поле DateTime увеличить на 1 час
Зачем добавлять 1 час? Так в базе данных записано время UTC. Т.е. без сдвига на 4 часа там хранится время 31.10.2014 21:00:00. Если к этому времени добавить 3 часа по новым правилам, то получим 01.11.2014 00:00:00, вместо ожидаемого 1 часа. Вот чтобы поясное время не изменилось, время UTC и надо увеличить на 1 час
Собственно, именно этим и занимается форма TimeZonePatcher.
После открытия этой формы надо выбрать обновляемое правила из списка (этот список заполняется и обновляется при импорте файла XML) и нажать кнопку "Загрузить все затронутые поля UtcDateTime". Этот процесс займет некоторое время (несколько минут), поскольку связан с перебором всех таблиц и определения факта наличия в них полей на базе UtcDateTime.
После того, как в нижней части формы отобразится список полей таблиц, Вам надо выбрать те поля, который Вы будете обновлять и нажать кнопку "Применить исправление"
--------------------------------------------------------
Ну, вроде все хорошо? "Счаззз"... У нас же обязательно какая-нибудь проблема вылезет
Проблема заключается в том, что исправляются только те данные, которые попадают в область действия новых правил. В отношении правила 2014 года это не критично, поскольку он уже наступил. Просто импортируем файл XML с новыми правилами и запускаем форму TimeZonePatcher ДО наступления 26.10.2014 года. А вот с правилом 2015 года - есть проблема.
Если у Вас работают пакетные задания, то 01.01.2015 00:00:00 у всех них произойдет сдвиг запланированного времени исполнения на 1 час вперед. Почему? Так ведь у них по прежнему будет указан код *TZID относящийся к 2014 году. Как следствие, в январе сдвиг будет составлять 4 часа, а не 3 как необходимо.
Если для Вас сдвиг выполнени пакетных задний на 1 час не критичен, то этим можно пренебречь и выполнить запуск формы TimeZonePatcher после новогодних каникул 12 января. Если же это является проблемой, то следует поступить следующим образом:
1. В 2014 году импортируется только 1 правило, действующее с 26 октября 2014 кода и по 2153 год. Это импорт такого файла XML
Отличие от первоначального вариант - это тег <dyear>2153</dyear>. Это значит, что 26.10.1014 произойдет сдвиг на 1 час вперед, но перевод на 1 час назад произойдет только в 2153 году. Т.е. в 2015 году по прежнему будет работать сдвиг на 3 часа.
2. После наступления 2015 года в любое удобное время необходимо на уровне SQL-сервера выполнить замену
и в Axapta импортировать файл XML с правилом на 2015 год
3. После перезагрузки AOS запустить форму TimeZonePatcher для 2015 года
Для начала, надо разобраться с "физикой" процесса
При создании полей на основе базового типа данных Types::UtcDateTime физически, на уровне базы данных создаются 2 поля:
1. Поле с типом DateTime хранящее время UTC
2. Поле, имя которого совпадает с именем поля DateTime, но с добавленным окончанием "TZID".
Поле *TZID является служебным и не отображется в среде Axapta. Хотя в таблице SqlDictionary присутствуют.
Например, в таблице BatchJob есть поле OrigStartDateTime, которое видно в списке полей этой таблицы в AOT. Но, кроме того, у этой же таблицы есть поле OrigStartDateTimeTZID, которое можно увидеть только на уровне базы данных SQL. В среде Axapta оно не видно
В поле *TZID записывается идентификатор временной зоны (TZID = Time Zone IDentifier). Таким идентификатором является значение поля таблицы TimeZonesRulesData.RuleID
Таблица TimeZonesRulesData это правила, определяющие "сдвиг" в минутах, который надо добавить (или вычесть) к значению поля DateTime
Логика чтения полей DateTime выглядит так:
1. Из поля DateTime считывается значение
2. Из поля *TZID считывается идентификатор правила чтения временных зон, определяется "сдвиг" в минутах и прибавляется к значению DateTime
Исключением из этого правила являются поля CreatedDateTime и ModifiedDateTime. Им в пару не создаются поля *TZID. Т.е. при их считывании всегда используется текущее правило "сдвига" времени в минутах.
Причина, по которой возникает необходимость "патчить" данные - это тот факт, что поле *TZID заполняется один раз в момент создания записи и больше уже не изменяется на протяжении всего времени существования записи.
Это значит, что если, например, до импорта новых правил определения временных зон Вы создадите пакетное задание, плановое дата/время которого будет, скажем, 01.11.2014 01:00:00, то, после импорта новых правил будет отображаться значение 01.11.2014 02:00:00. Почему? Да потому, что поле *TZID останется без изменений и будет ссылаться на правила расчета 2011 года. Т.е. добавлять к времени UTC (то, что сохранено в базе данных в поле DateTime) 4 часа, а не 3, как должно быть по новым правилам.
Следовательно, необходимо для всех дат, которые попали в область действия новых правил определения временных зон сделать замену:
1. В поле *TZID записать код записи нового правила
2. Поле DateTime увеличить на 1 час
Зачем добавлять 1 час? Так в базе данных записано время UTC. Т.е. без сдвига на 4 часа там хранится время 31.10.2014 21:00:00. Если к этому времени добавить 3 часа по новым правилам, то получим 01.11.2014 00:00:00, вместо ожидаемого 1 часа. Вот чтобы поясное время не изменилось, время UTC и надо увеличить на 1 час
Собственно, именно этим и занимается форма TimeZonePatcher.
После открытия этой формы надо выбрать обновляемое правила из списка (этот список заполняется и обновляется при импорте файла XML) и нажать кнопку "Загрузить все затронутые поля UtcDateTime". Этот процесс займет некоторое время (несколько минут), поскольку связан с перебором всех таблиц и определения факта наличия в них полей на базе UtcDateTime.
После того, как в нижней части формы отобразится список полей таблиц, Вам надо выбрать те поля, который Вы будете обновлять и нажать кнопку "Применить исправление"
--------------------------------------------------------
Ну, вроде все хорошо? "Счаззз"... У нас же обязательно какая-нибудь проблема вылезет
Проблема заключается в том, что исправляются только те данные, которые попадают в область действия новых правил. В отношении правила 2014 года это не критично, поскольку он уже наступил. Просто импортируем файл XML с новыми правилами и запускаем форму TimeZonePatcher ДО наступления 26.10.2014 года. А вот с правилом 2015 года - есть проблема.
Если у Вас работают пакетные задания, то 01.01.2015 00:00:00 у всех них произойдет сдвиг запланированного времени исполнения на 1 час вперед. Почему? Так ведь у них по прежнему будет указан код *TZID относящийся к 2014 году. Как следствие, в январе сдвиг будет составлять 4 часа, а не 3 как необходимо.
Если для Вас сдвиг выполнени пакетных задний на 1 час не критичен, то этим можно пренебречь и выполнить запуск формы TimeZonePatcher после новогодних каникул 12 января. Если же это является проблемой, то следует поступить следующим образом:
1. В 2014 году импортируется только 1 правило, действующее с 26 октября 2014 кода и по 2153 год. Это импорт такого файла XML
PHP код:
<?xml version="1.0" encoding="UTF-8"?>
<Timezoneslist>
<!-- Russian Standard Time new rules -->
<Timezonedata>
<Timezonerule>
<ruleid>61004</ruleid>
<tzenum>61</tzenum>
<year>2014</year>
<bias>-240</bias>
<syear>0</syear>
<smonth>10</smonth>
<sdayofweek>0</sdayofweek>
<sday>5</sday>
<shour>2</shour>
<sminute>0</sminute>
<ssecond>0</ssecond>
<sbias>60</sbias>
<dyear>2153</dyear>
<dmonth>12</dmonth>
<ddayofweek>3</ddayofweek>
<dday>5</dday>
<dhour>23</dhour>
<dminute>59</dminute>
<dsecond>59</dsecond>
<dbias>0</dbias>
</Timezonerule>
</Timezonedata>
</Timezoneslist>
2. После наступления 2015 года в любое удобное время необходимо на уровне SQL-сервера выполнить замену
PHP код:
update TimeZonesRulesData
set DYear = 0
where TzEnum = 61 and RULEID = 61004
PHP код:
<?xml version="1.0" encoding="UTF-8"?>
<Timezoneslist>
<!-- Russian Standard Time new rules -->
<Timezonedata>
<Timezonerule>
<ruleid>61005</ruleid>
<tzenum>61</tzenum>
<year>2015</year>
<bias>-180</bias>
<syear>0</syear>
<smonth>0</smonth>
<sdayofweek>0</sdayofweek>
<sday>0</sday>
<shour>0</shour>
<sminute>0</sminute>
<ssecond>0</ssecond>
<sbias>0</sbias>
<dyear>0</dyear>
<dmonth>0</dmonth>
<ddayofweek>0</ddayofweek>
<dday>0</dday>
<dhour>0</dhour>
<dminute>0</dminute>
<dsecond>0</dsecond>
<dbias>0</dbias>
</Timezonerule>
</Timezonedata>
</Timezoneslist>
Всего комментариев 3
Комментарии
-
Спасибо за информацию.
Жаль нельзя давать репутацию за сообщения в блогах.Запись от Logger размещена 30.09.2014 в 11:22 -
Почему-то при настройках DYEAR=2153 и DDAY=5 Axapta посчитала, что 03.12 23:59:59 относится к текущему 2014 году. Соответственно, 04.12 произошел возврат к UTC+4
Корректно определение даты будет если установить DDAY=1Запись от Владимир Максимов размещена 04.12.2014 в 13:50 -
Владимир Максимов
Как выяснилось такая же беда с 4.12 только DDAY=1 не помогаетЗапись от d_alexe размещена 10.12.2014 в 15:20