Oracle 将 EET 视为时区区域名称(SELECT tzname, tzabbrev FROM V$TIMEZONE_NAMES WHERE tzname = 'EET',或参见the docs),因此它处理夏令时/夏令时 (EEST/EEDT)。在 2011-09-26 EET region was actually EEST 所以它比 UTC 早了三个小时,而不是两个小时;由于 IST 始终为 +05:30,因此偏移量实际上为 +02:30。所以你的结果是“正确的”。
您可以使用from_tz 函数将普通时间戳更改为带时区的时间戳,而不是来回跳转到字符串;然后at time zone 在不同的区域获得它:
select to_timestamp('2011-09-26T21:00:00Z', 'YYYY-MM-DD"T"HH24:MI:SS"Z"') orig_ts,
from_tz(to_timestamp('2011-09-26T21:00:00Z', 'YYYY-MM-DD"T"HH24:MI:SS"Z"'),
'EET') orig_tsz,
sys_extract_utc(from_tz(to_timestamp('2011-09-26T21:00:00Z', 'YYYY-MM-DD"T"HH24:MI:SS"Z"'),
'EET')) orig_utc,
from_tz(to_timestamp('2011-09-26T21:00:00Z', 'YYYY-MM-DD"T"HH24:MI:SS"Z"'),
'EET') at time zone 'Asia/Calcutta' new_tsz
from dual;
ORIG_TS ORIG_TSZ ORIG_UTC NEW_TSZ
------------------- -------------------------- ------------------- ---------------------------------
2011-09-26 21:00:00 2011-09-26 21:00:00 EET 2011-09-26 18:00:00 2011-09-26 23:30:00 ASIA/CALCUTTA
原始字符串中的“T”表示时间,“Z”表示(或应该!)这表示 UTC 中的日期/时间;这是the ISO 8601 standard notation。 Oracle 的转换功能允许您embed character literals in the format model 忽略这些。由于它有一个“Z”,因此您应该将其视为 UTC 而不是 EET,因此您可能希望返回到您从中获取这些值的任何人。
如果您确实希望所有值都来自没有夏令时偏移的 EET 时区,那么您可以使用固定的 TZH:TZM 而不是区域名称:
select to_timestamp('2011-09-26T21:00:00Z', 'YYYY-MM-DD"T"HH24:MI:SS"Z"') orig_ts,
from_tz(to_timestamp('2011-09-26T21:00:00Z', 'YYYY-MM-DD"T"HH24:MI:SS"Z"'),
'+02:00') orig_tsz,
sys_extract_utc(from_tz(to_timestamp('2011-09-26T21:00:00Z', 'YYYY-MM-DD"T"HH24:MI:SS"Z"'),
'+02:00')) orig_utc,
from_tz(to_timestamp('2011-09-26T21:00:00Z', 'YYYY-MM-DD"T"HH24:MI:SS"Z"'),
'+02:00') at time zone 'Asia/Calcutta' new_tsz
from dual;
ORIG_TS ORIG_TSZ ORIG_UTC NEW_TSZ
------------------- -------------------------- ------------------- ---------------------------------
2011-09-26 21:00:00 2011-09-26 21:00:00 +02:00 2011-09-26 19:00:00 2011-09-27 00:30:00 ASIA/CALCUTTA
我怀疑这实际上是你想要的,但你需要澄清你的要求。
最后要将转换后的值恢复为原始格式,您需要使用to_char:
select to_char(from_tz(to_timestamp('2011-09-26T21:00:00Z',
'YYYY-MM-DD"T"HH24:MI:SS"Z"'), 'EET') at time zone 'Asia/Calcutta',
'YYYY-MM-DD HH24:MI:SS') new_string
from dual;
NEW_STRING
-------------------
2011-09-26 23:30:00
您可以使用'YYYY-MM-DD"T"HH24:MI:SS' 重新嵌入“T”;不过,将“Z”重新添加到末尾似乎是错误的。
如果您的源时间来自柏林,正如您的问题编辑所建议的那样(这是 CET/CEST,而不是 EET/EEST;为您赢得那个缺失的时间)只需更改 from_tz 区域:
select to_char(from_tz(to_timestamp('2011-09-26T21:00:00Z',
'YYYY-MM-DD"T"HH24:MI:SS"Z"'), 'Europe/Berlin') at time zone 'Asia/Calcutta',
'YYYY-MM-DD"T"HH24:MI:SS') new_string
from dual;
NEW_STRING
-------------------
2011-09-27T00:30:00