我们的Oracle服务器在澳大利亚/悉尼时间运行。
我们计划以UTC格式存储一些新日期。
例如,我们可能存储的日期之一是 2014年10月5日凌晨2:00 。
然而,在悉尼,我们同时开始夏令时,这意味着当天不存在从凌晨2:00 到凌晨2:59 的时间。< / p>
例如,在 2014年10月5日上,发生的时间是:
1点58
01:59
03:00
03:01
问题在于,如果我尝试将时间2014-10-05 02:00
存储在数据库中,它会默默地转换为2014-10-05 03:00
我们没有选择更改服务器上的时区,所以有没有办法将2014-10-05 02:00
存储在我们的数据库中?
编辑@mrjoltcola的评论
我们的服务器正在运行时区设置(GMT +10)堪培拉,墨尔本,悉尼
如果我运行命令select DBTIMEZONE from dual;
,则输出为单值+00:00
(这是意外的)。
我们的原始专栏是 TIMESTAMP 专栏,我没有提供插入的任何时区详细信息。
为了进一步探索,我创建了一个测试表,如下所示:
create table TEST
(
ID number,
TS timestamp,
TS_TZ timestamp with time zone
)
然后我运行以下插入语句(有和没有时区):
insert into TEST
VALUES
(
1,
TIMESTAMP '2014-10-05 02:00:00 UTC',
TIMESTAMP '2014-10-05 02:00:00 UTC'
);
insert into TEST
VALUES
(
2,
TIMESTAMP '2014-10-05 02:00:00',
TIMESTAMP '2014-10-05 02:00:00'
);
产生结果:
+---+---------------------------------+--------------------------------------------------+
| 1 | 05/OCT/14 03:00:00.000000000 AM | 05/OCT/14 02:00:00.000000000 AM UTC |
+---+---------------------------------+--------------------------------------------------+
| 2 | 05/OCT/14 03:00:00.000000000 AM | 05/OCT/14 03:00:00.000000000 AM AUSTRALIA/SYDNEY |
+---+---------------------------------+--------------------------------------------------+
答案 0 :(得分:0)
麻烦的是,如果我尝试将时间2014-10-05 02:00存储在数据库中,它会默默转换为2014-10-05 03:00
在我的数据库中,我可以将会话时区设置为“澳大利亚/悉尼”,并且仍然在一个普通的TIMESTAMP列中存储2014-10-05 02:00:00而不进行转换。但如果我将其更改为TIMESTAMP WITH TIMEZONE并尝试存储相同的值,我会得到 ORA-01878
所以我不认为你的时间被转换为03:00:00,基于Oracle试图调整夏令时,我认为你应该收到 ORA-01878 指定错误的时间戳时。相反,我认为您的客户端/会话时区与数据库/服务器时区不匹配一个小时,并且您看到正常的Oracle调整。
当客户端/会话时区与服务器/数据库时区不匹配时,Oracle将转换时间戳。由于常规TIMESTAMP字段中没有时区信息,因此Oracle不介意存储它。
所以你的“静默转换为2014-10-05 03:00”应该已经发生了其他时间值(你是否尝试插入01:00并查看是否导致调整和/或ORA-01878错误?)。
当我在这里尝试将我的会话时区设置为澳大利亚/悉尼并插入该时间时,我得到:
SQL> alter session set time_zone = 'Australia/Sydney';
Session altered.
SQL> insert into test(ts) values(1, timestamp '2014-10-05 02:00:00');
insert into test values(1, timestamp '2014-10-05 02:00:00')
1 row created.
SQL> insert into test(ts_tz) values(2, timestamp '2014-10-05 02:00:00');
insert into test(ts_tz) values(2, timestamp '2014-10-05 02:00:00')
*
ERROR at line 1:
ORA-01878: specified field not found in datetime or interval
现在,关于您的问题,如果您想存储UTC时间,您应该使用UTC明确指定时间戳,或者将数据库或会话时区设置为UTC。您不必具有DBA权限来设置会话time_zone,它可以与db time_zone不同。
SQL> alter session set time_zone = '+00:00';
Session altered.
SQL> select dbtimezone, sessiontimezone from dual;
DBTIME SESSIONTIMEZONE
------ ---------------------------------------------------------------------------
+00:00 +00:00
SQL> insert into test values(1, timestamp '2014-10-05 02:00:00');
1 row created.
SQL> select * from test;
ID TS
---------- ---------------------------------------------------------------------------
1 05-OCT-14 02.00.00.000000 AM
但是,上述TIMESTAMP字段不一定是UTC。如果DB服务器时区发生更改,它可能会更改。对于Oracle,简单的TIMESTAMP只是一个没有时区信息的时间戳。如果您想要UTC时间,但可能正在处理不同时区的客户端,您可以使用TIMESTAMP WITH TIMEZONE或TIMESTAMP WITH LOCAL TIMEZONE。