Почему при конвертации DAYLIGHT SAVING TIME происходит сбой CONVERT DATE с sy-subrc 12? - PullRequest
4 голосов
/ 16 октября 2019

Следующий код завершается ошибкой с sy-subrc=12.

CONVERT DATE '20191105'
    TIME '123000'
    DAYLIGHT SAVING TIME 'X'
    INTO TIME STAMP DATA(timestamp)
    TIME ZONE 'CET   '.

В документации ABAP написано:

12: указанное время не можетбыть преобразованным, потому что dat, tim или dst содержат недопустимые или противоречивые значения.

Я заметил, что когда я удаляю 'X' в sy-dayst в отладчике, он выполняет преобразование.

Но, конечно, я хочу принять во внимание летнее время, так как я могу заставить эту работу работать?

Ответы [ 2 ]

4 голосов
/ 17 октября 2019

TL; DR

Никогда не используйте DAYLIGHT SAVING TIME (за исключением очень особых случаев, если вы эксперт)

И хорошо сказано @konstantin:

"Команда CONVERT DATE автоматически позаботится о летнем времени"

Объяснение:

DAYLIGHT SAVING TIME 'X' можно использовать только при местном времени (ДАТА и ВРЕМЯ)соответствует часовому интервалу (редко два часа) для переключения с летнего на зимнее время для данного часового пояса (обратите внимание, что в некоторых часовых поясах нет перехода на летнее время).

Например, в 2003 годуБразилия перешла на зимнее время 9 марта (воскресенье) в 2 часа ночи;в 2 часа ночи пришлось перенести один час назад в 1 час ночи, и, следовательно, 1:30 происходило дважды.

Итак, если ABAP необходимо преобразовать местное время, 2003/03/09 01:30:00 ввремя UTC, оно должно знать, является ли местное время летним временем (зимнее время) или нет (летнее время), что соответственно соответствует времени UTC 2003/03/09 03:30:00 или 2003/03/ 09 04: 30: 00.

Демонстрация:

DATA: time_stamp TYPE timestamp,
      dat TYPE d,
      tim TYPE t,
      tz  TYPE ttzz-tzone.

tz = 'BRAZIL'. "UTC-03:00
dat = '20030309'.
tim = '013000'.

CONVERT DATE dat TIME tim DAYLIGHT SAVING TIME 'X' " winter time
        INTO TIME STAMP time_stamp TIME ZONE tz.
ASSERT time_stamp = '20030309033000'. " UTC time

CONVERT DATE dat TIME tim DAYLIGHT SAVING TIME ' ' " summer time
        INTO TIME STAMP time_stamp TIME ZONE tz.
ASSERT time_stamp = '20030309043000'. " UTC time

Теперь возникает вопрос, как узнать, нужно ли использовать DAYLIGHT SAVING TIME 'X' или нет. Фактически, если таблица базы данных содержит местное время, которое я использовал в приведенном выше примере, никто не может знать , является ли это летним или зимним временем, потому что летнее время никогда не назначается столбцу таблицы вместе сстолбцы даты и времени.


Вот почему SAP представила решение ~ 10 лет назад, которое сделало DAYLIGHT SAVING TIME почти устаревшим. Фактической проблемой было не летнее время, а непостоянное время, которое могло привести к таким проблемам, как хронологическая сортировка. Принцип решения состоит в том, чтобы замедлить время при переходе на летнее время, чтобы одно заданное время никогда не происходило дважды, а время оставалось непрерывным. Технически это влияет на системные переменные SY-DATUM (дата) и SY-UZEIT (время). В этом интервале «двойной час» необходимы две реальные секунды, чтобы сделать одну секунду SAP. Это поведение активируется по умолчанию (значение «включено») через параметр профиля zdate/DSTswitch_contloctime, который вы можете просмотреть через код транзакции RZ11. Ниже приведено время SAP в соответствии со старым («выкл») или новым способом («вкл»), если переключение происходит по местному времени 2 часа ночи (с «вкл» вы не видите переключатель):

off: 1:00, 1:30, 1:00, 1:30, 2:00
on : 1:00, 1:15, 1:30, 1:45, 2:00

Просто чтобы добавить сложности, обратите внимание, что CONVERT все еще имеет разрыв в один час. Например, если для zdate/DSTswitch_contloctime установлено значение «включено» и без DAYLIGHT SAVING TIME, CONVERT даст эти временные метки UTC соответственно, между 03:59:59 и 05: 00: 00: * 1046 будет промежуток в один час. *

3:00, 3:15, 3:30, 3:45, 5:00

Но этот разрыв не является большим недостатком по сравнению с риском возникновения хронологических проблем сортировки.

Дополнительная информация: https://blogs.sap.com/2009/12/09/daylight-saving-time-and-slowing-down-the-time/ и SAP-нота 950114 - Профильпараметр zdate / DSTswitch_contloctime .


Обратите внимание, что SY-DAYST соответствует индикатору DST текущего времени сервера приложений (SY-DATUM, SY-UZEIT и часового пояса, определяемого встол TTZCU). Я не вижу никакого возможного использования этого. Если вы хотите преобразовать время, которое было первоначально получено с помощью SY-DATUM и SY-UZEIT, в метку времени UTC, вы должны использовать метод SYSTEMTSTMP_SYST2UTC класса CL_ABAP_TSTMP. Пример получения текущего времени:

cl_abap_tstmp=>systemtstmp_syst2utc(
  EXPORTING
    syst_date = sy-datum
    syst_time = sy-uzeit
  IMPORTING
    utc_tstmp = DATA(now_utc) ).

Как продемонстрировал @konstantin (" DATE '20190331' TIME '023000' [...] местное время в Германии не существует" ), CONVERT DATE без DAYLIGHT SAVING TIME может возвращать sy-subrc=12 в редких случаях, если введенные дата и время соответствуют чему-то внутри «исчезающего часа» из-за перехода с зимнего времени на летнее время или если часовой поясимеет летнее времяНапример: «в 2 часа ночи, это 3 часа ночи», местного времени «2:30 утра» вообще не существует.

4 голосов
/ 16 октября 2019

То есть вы имеете в виду, что мне не нужно передавать DAYLIGHT SAVING TIME, потому что CET приведет к тому, что Дата будет преобразована в правильный путь?

tl; dr : Да, команда CONVERT DATE автоматически заботится о летнем времени (по крайней мере, для часового пояса CET). sy-subrc==12 ist установлен для недопустимых аргументов.

Вот минимальная программа для вашего фрагмента, которая охватывает все крайние случаи. Я добавил полученные комментарии в удобочитаемом формате (отредактирован вручную) в комментариях.

CONVERT DATE '20190101' TIME '000000' "" // german 'winter time' (no DST, GMT+1)
        INTO TIME STAMP DATA(timestamp0) "" // 2018-12-31T23:00:00Z
        TIME ZONE 'CET   '.

CONVERT DATE '20190701' TIME '000000' "" // german 'summer time' (DST, GMT+2)
        INTO TIME STAMP DATA(timestamp1) "" // 2019-06-30T22:00:00Z
        TIME ZONE 'CET   '.

CONVERT DATE '20190331' TIME '015959' "" // last second before non DST (GMT+1) ==> DST (GMT+2) transition
        INTO TIME STAMP DATA(timestamp2) "" // 2019-03-31T00:59:59
        TIME ZONE 'CET   '.

CONVERT DATE '20190331' TIME '023000' "" // local time does not exist in germany, it's skipped
        INTO TIME STAMP DATA(timestamp3) "" // '0' <-- is this initial?
        TIME ZONE 'CET   '.
""// sy-subrc == 12 here!

CONVERT DATE '20190331' TIME '030000' "" // first second of german DST (GMT+2)
        INTO TIME STAMP DATA(timestamp4) "" // 2019-03-31T01:00:00Z
        TIME ZONE 'CET   '.

CONVERT DATE '20191027' TIME '015959' "" // last second before SAP undefined time range (turn your system off now)
        INTO TIME STAMP DATA(timestamp5) ""// 2019-10-26T23:59:59Z
        TIME ZONE 'CET   '.

CONVERT DATE '20191027' TIME '023000' "" // in the undefined zone, could theoretically be both DST and non-DST
        INTO TIME STAMP DATA(timestamp6) "" 2019-10-27T00:30:00Z <-- but is treated as DST
        TIME ZONE 'CET   '.

CONVERT DATE '20191027' TIME '030000' "" // first second in non DST time (german winter, GMT+1 again)
        INTO TIME STAMP DATA(timestamp7) "" 2019-10-27T02:00:01Z
        TIME ZONE 'CET   '.

Существует причина, по которой современные языки программирования обрабатывают объекты даты и времени как нечто более сложное, чем просто строки длиной 8 или 14 числовых символов. Работа с различными часовыми поясами и локальными данными против UTC раздражает в ABAP, потому что большинство таблиц SAP и зависимых функциональных модулей и классов случайным образом предполагают, что сохраненные даты и время находятся в UTC или местном времени (что даже не уникально в случае летнего времени). !)

...