DECLARE
vdate VARCHAR2(255);
BEGIN
select cast(
TO_TIMESTAMP_TZ(
'2020-09-23T03:02:00+02:00',
'yyyy-mm-dd"T"hh24:mi:ssTZH:TZM' -- remove the "+"
)
as date
)
into vdate
from dual;
DBMS_OUTPUT.PUT_LINE(vdate);
END;
/
您从字符串 (2020-09-23T03:02:00+02:00) 转到时间戳(使用 TO_TIMESTAMP_TZ 函数,您不应该显式匹配 + 字符,而应该让 TZH 格式模型匹配它) 然后到一个日期,然后将其放入一个字符串变量中,该变量需要从二进制日期值隐式转换为字符串。这一切似乎都是多余的。但是,正是这最后一步,即从日期到字符串的隐式转换,导致了您的问题,因为 Oracle 将使用 NLS_DATE_FORMAT 会话参数作为格式模型进行转换。
解决这个问题的一种方法是使用:
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD"T"HH24:MI:SS';
然后您的代码应该输出正确的值而无需更改您的代码。
但是,您不应该使用此方法,因为它依赖于用户更改会话,并且大多数用户不会这样做(如果他们这样做,那么他们很可能会更改将其转换为他们喜欢的日期格式,而不是您想要的日期格式,这会再次打破您对代码行为的期望)。
相反,如果您需要特定格式或日期,则应使用 TO_CHAR 明确应用该格式:
BEGIN
DBMS_OUTPUT.PUT_LINE(
TO_CHAR(
TO_TIMESTAMP_TZ(
'2020-09-23T03:02:00+02:00',
'yyyy-mm-dd"T"hh24:mi:ssTZH:TZM'
),
'YYYY-MM-DD"T"HH24:MI:SS'
)
);
END;
/
(注意:您不需要:声明变量;使用 SQL;或转换为日期。相反,您可以在一行中完成所有操作。)
如果您确实想使用变量,那么您可以在 PL/SQL 中通过将值直接分配给变量来完成所有操作(并且不需要上下文切换来使用 SQL 引擎):
DECLARE
vdate DATE;
BEGIN
vdate := TO_TIMESTAMP_TZ(
'2020-09-23T03:02:00+02:00',
'yyyy-mm-dd"T"hh24:mi:ssTZH:TZM'
);
DBMS_OUTPUT.PUT_LINE( TO_CHAR( vdate, 'YYYY-MM-DD"T"HH24:MI:SS' ) );
END;
/
db小提琴here