Во-первых, «я могу правильно указать значение в SELECT» не совсем верно.Эти:
TO_TIMESTAMP_TZ(MYDT, 'DD.MM.YYYY HH24:MI TZH')
TO_TIMESTAMP_TZ ('28.10.2018 00:00 00', 'DD.MM.YYYY HH24:MI TZH');
не делают то, что вы думаете.В первом случае вы выполняете неявное преобразование значения mydt
в строку, используя параметр NLS_TIMESTAMP_FORMAT
вашего сеанса, который дает вам что-то вроде '28 .10.18 02:00:00 ';и затем в обоих из них вы конвертируете строку, используя предоставленную вами маску формата.Но смещение часового пояса обеспечивается значением секунд из строки.
В обоих ваших примерах это означает, что TZH установлен в ноль, что вы видите в выходных данных.Если у вас есть исходное значение, скажем, «28 .10.18 02:00:03», то оно станет «2018-10-28 02:00:00 +03: 00», что совсем не то, что вы хотели.И если есть какие-либо значения, где секунды выше 14, то произойдет сбой с «ORA-01874: часовой пояс должен быть в диапазоне от -12 до 14».
Таким образом, ваши запросы находят нужные вам строки,но почти случайно.
Если некоторые примеры данных и настройки сеанса совпадают с тем, что, я думаю, у вас есть:
create table mytab(
mydt timestamp(0) with local time zone not null,
myval number not null
);
insert into mytab (mydt, myval) values (timestamp '2018-10-28 01:59:59 CET CEST', 1);
insert into mytab (mydt, myval) values (timestamp '2018-10-28 02:00:00 CET CEST', 2);
insert into mytab (mydt, myval) values (timestamp '2018-10-28 02:00:00 CET CET', 3);
insert into mytab (mydt, myval) values (timestamp '2018-10-28 02:00:01 CET CET', 4);
insert into mytab (mydt, myval) values (timestamp '2018-10-28 02:00:02 CET CET', 5);
insert into mytab (mydt, myval) values (timestamp '2018-10-28 02:00:03 CET CET', 6);
alter session set time_zone = 'Europe/Berlin';
alter session set nls_timestamp_format = 'DD.MM.YYYY HH24:MI:SS';
alter session set nls_timestamp_tz_format = 'DD.MM.YYYY HH24:MI:SS TZH:TZM';
, тогда вы можете увидеть проблему более четко:
select mydt, to_timestamp_tz(mydt, 'DD.MM.YYYY HH24:MI TZH')
from mytab;
Error report -
ORA-01874: time zone hour must be between -12 and 14
select mydt, to_timestamp_tz(mydt, 'DD.MM.YYYY HH24:MI TZH')
from mytab
where myval > 1;
MYDT TO_TIMESTAMP_TZ(MYDT,'DD.M
------------------- --------------------------
28.10.2018 02:00:00 28.10.2018 02:00:00 +00:00
28.10.2018 02:00:00 28.10.2018 02:00:00 +00:00
28.10.2018 02:00:01 28.10.2018 02:00:00 +01:00
28.10.2018 02:00:02 28.10.2018 02:00:00 +02:00
28.10.2018 02:00:03 28.10.2018 02:00:00 +03:00
Возможно, вы ожидали что-то более похожее на to_char(mydt, 'DD.MM.YYYY HH24:MI TZH')
, но это выдает «ORA-01821: формат даты не распознан».Однако вместо этого вы можете увидеть флаг региона и перехода на летнее время:
select mydt, to_char(mydt, 'DD.MM.YYYY HH24:MI TZR TZD')
from mytab;
MYDT TO_CHAR(MYDT,'DD.MM.YYYYHH24:MITZRTZD')
------------------- --------------------------------------------------------
28.10.2018 01:59:59 28.10.2018 01:59 EUROPE/BERLIN CEST
28.10.2018 02:00:00 28.10.2018 02:00 EUROPE/BERLIN CEST
28.10.2018 02:00:00 28.10.2018 02:00 EUROPE/BERLIN CET
28.10.2018 02:00:01 28.10.2018 02:00 EUROPE/BERLIN CET
28.10.2018 02:00:02 28.10.2018 02:00 EUROPE/BERLIN CET
28.10.2018 02:00:03 28.10.2018 02:00 EUROPE/BERLIN CET
Тем не менее, он все равно будет отображать строку с использованием часового пояса сеанса.
Аналогично ваш фильтр может выглядеть примерно так:
select myval,
mydt,
sys_extract_utc(mydt) as mydt_utc,
to_char(mydt, 'DD.MM.YYYY HH24:MI TZR TZD') as mydt_full
from mytab
where mydt = to_timestamp_tz('28.10.2018 02:00:00 CET CEST', 'DD.MM.YYYY HH24:MI:SS TZR TZD');
MYVAL MYDT MYDT_UTC MYDT_FULL
---------- ------------------- ------------------- -----------------------------------
2 28.10.2018 02:00:00 28.10.2018 00:00:00 28.10.2018 02:00 EUROPE/BERLIN CEST
и
select myval,
mydt,
sys_extract_utc(mydt) as mydt_utc,
to_char(mydt, 'DD.MM.YYYY HH24:MI TZR TZD') as mydt_full
from mytab
where mydt = to_timestamp_tz('28.10.2018 02:00:00 CET CET', 'DD.MM.YYYY HH24:MI:SS TZR TZD');
MYVAL MYDT MYDT_UTC MYDT_FULL
---------- ------------------- ------------------- -----------------------------------
3 28.10.2018 02:00:00 28.10.2018 01:00:00 28.10.2018 02:00 EUROPE/BERLIN CET
Я включил вывод sys_extract_utc()
в качестве альтернативы вашему cast()
.Вы также можете использовать mydt at time zone 'UTC'
без приведения, что дает вам метку времени со значением часового пояса.
Опять же, изменение часового пояса сеанса изменит способ отображения значения mydt_full
, но фильтр все равно будетработать, потому что правильный часовой пояс был явно указан там.И в зависимости от того, откуда поступают значения фильтра, вы можете использовать литерал отметки времени , как я делал в моих операторах вставки.
Узнайте больше о том, как отметка времени с местным временемтип данных зоны.