你有一个从 TIMESTAMP 到 TIMESTAMP WITH TIME ZONE 的隐式转换:
to_char(
cast((sysdate + 1/24) as timestamp) -- TIMESTAMP (without time zone)
at time zone 'UTC', -- TIMESTAMP WITH TIME ZONE
'yyyy-mm-dd"T"hh24:mi:ss.ff3"Z"'
)
这实际上是在添加一个时区:
to_char(
cast(sysdate + 1/24 as timestamp with local time zone)
at time zone 'UTC',
'yyyy-mm-dd"T"hh24:mi:ss.ff3"Z"'
)
它将数据库时区中的SYSDATE 转换为本地时区(无论客户端应用程序使用哪个时区,而不是数据库时区),然后将其转换为UTC。
您最好使用SYSTIMESTAMP 而不是SYSDATE,这样可以避免很多关于数据类型和时区的困惑:
TO_CHAR(
(SYSTIMESTAMP + INTERVAL '1' HOUR) AT TIME ZONE 'UTC',
'YYYY-MM-DD"T"HH24:MI:SS.FF3"Z"'
)
但是,如果您确实想使用SYSDATE,请使用数据库时区而不是本地(客户端)时区:
to_char(
FROM_TZ(CAST(sysdate + 1/24 AS TIMESTAMP), DBTIMEZONE)
at time zone 'UTC',
'yyyy-mm-dd"T"hh24:mi:ss.ff3"Z"'
)
例如,如果数据库时间是 UTC 而你这样做:
ALTER SESSION SET TIME_ZONE = 'Asia/Shanghai';
SELECT 'SYSDATE with implicit local cast' AS method,
to_char(
cast(sysdate + 1/24 as timestamp)
at time zone 'UTC',
'yyyy-mm-dd"T"hh24:mi:ss.ff3"Z"'
) AS utc_timestamp
FROM DUAL
UNION ALL
SELECT 'SYSDATE with explicit local cast',
to_char(
cast(sysdate + 1/24 as timestamp with local time zone)
at time zone 'UTC',
'yyyy-mm-dd"T"hh24:mi:ss.ff3"Z"'
)
FROM DUAL
UNION ALL
SELECT 'SYSDATE with explicit DB timezone cast',
to_char(
FROM_TZ(CAST(sysdate + 1/24 AS TIMESTAMP), DBTIMEZONE)
at time zone 'UTC',
'yyyy-mm-dd"T"hh24:mi:ss.ff3"Z"'
)
FROM DUAL
UNION ALL
SELECT 'SYSTIMESTAMP',
TO_CHAR(
(SYSTIMESTAMP + INTERVAL '1' HOUR) AT TIME ZONE 'UTC',
'YYYY-MM-DD"T"HH24:MI:SS.FF3"Z"'
)
FROM DUAL;
那么输出是:
| METHOD |
UTC_TIMESTAMP |
| SYSDATE with implicit local cast |
2021-11-01T04:07:04.000Z |
| SYSDATE with explicit local cast |
2021-11-01T04:07:04.000Z |
| SYSDATE with explicit DB timezone cast |
2021-11-01T12:07:04.000Z |
| SYSTIMESTAMP |
2021-11-01T12:07:04.200Z |
db小提琴here