Oracle的时区问题

简介:
Oracle 9i 开始多了 3 个关于时间的数据类型:TIMESTAMP [(precision)] TIMESTAMP [(precision)] WITH TIME ZONE TIMESTAMP [(precision)] WITH LOCAL TIME ZONE,其中 TIMESTAMP [(precision)] WITH TIME ZONE 保存了时区信息。

1. Oracle 的时区设置


    Oracle 的时区可以分为两种,一种是数据库的时区,一种是 session 时区,也就是客户端连接时的时区(经过实验,连接以后再修改客户端的时区,session 的时区不会更改)。


    数据库的时区在创建数据库时可以通过在 create database 语句中加上 SET TIME_ZONE = ' { { + | - } hh : mi | time_zone_region } ' 来指定,如果,不指定,默认是按照数据库所在的操作系统时区来设定的。创建之后,可以通过 alter database 来修改。其中 time_zone_region 参数可以通过查询 V$TIMEZONE_NAMES 动态视图来获得所有支持的值。修改之后,需要重启数据库才能生效。经常有人会碰到无法修改的情况:


SQL> alter database set time_zone='+06:00';
alter database set time_zone='+06:00'
*
ERROR at line 1:
ORA-02231: missing or invalid option to ALTER DATABASE

    TOM 对此问题有过解释,TIME_ZONE 的设定主要是为了 WITH LOCAL TIME ZONE,当 session 的时区和数据库的时区不同时,oracle 根据时区的差距转换到数据库的时间,再保存到数据库的 WITH LOCAL TIME ZONE 类型中,他是不保存时区的,所以需要 TIME_ZONE 来进行各种时区之间时间的转换(WITH TIME ZONE 类型保存了原始的时区,所以不需要 TIME_ZONE 的设置也可以进行各种时区之间的转换)。但数据库中一旦有了该类型,就不能通过 alter database 修改时区了,会得到上面的错误,可以通过下面的语句获得所有包含该类型的表,将他们删除之后,再修改。


select u.name || '.' || o.name || '.' || c.name TSLTZcolumn 
  from sys.obj$ o, sys.col$ c, sys.user$ u 
where c.type# = 231
   and o.obj# = c.obj# 
   and u.user# = o.owner#;
(一般查询后的结果为:OE.ORDERS.ORDER_DATE,指的是OE用户下的ORDERS表的ORDER_DATE字段使用了时区的信息:WITH LOCAL TIME ZONE,将此信息去掉就可以再修改了,修改好了之后需要重启数据库才能生效)

    Session 的时区是根据客户端的时区来决定的,当然连接以后也可以通过 alter session 来改变。WITH LOCAL TIME ZONE 类型会根据 TIME_ZONE 的设置,自动把时间转换为 session 所在时区的时间显示出来,而 WITH TIME ZONE 因为保存了时区,不需要根据 TIME_ZONE 的设置来转换。


2. 查看时区


    可以分别使用 SESSIONTIMEZONE / DBTIMEZONE 内建函数查看 session 和数据库时区:



SYS@SKYDB> select dbtimezone from dual;


DBTIME
------
+08:00


SYS@SKYDB> select sessiontimezone from dual;


SESSIONTIMEZONE
---------------------------------------------
+09:00



    另外可以用 TZ_OFFSET 查询某时区和 UTC 之间的差值。



TZ_OFFSET ( { 'time_zone_name'
                        | '{ + | - } hh : mi'
                        | SESSIONTIMEZONE
                        | DBTMEZONE  }
                      )


SELECT TZ_OFFSET('US/Eastern') FROM DUAL;


TZ_OFFS
-------
-04:00

SELECT TZ_OFFSET(DBTIMEZONE) FROM DUAL;

TZ_OFFSET(DBTI
--------------
+08:00


    其中 time_zone_name 也可以从 V$TIMEZONE_NAMES 获得。


3. 几个内建时间函数的比较


    sysdate/systimestamp 都是返回数据库的时间并且使用数据库的时区,他们返回的是操作系统的时间。sysdate 返回的是 date 类型,没有时区信息,操作系统上是什么时间就返回什么时间;systimestamp 返回 TIMESTAMP WITH TIME ZONE 类新,有时区信息:



SYS@SKYDB> select sysdate from dual;


SYSDATE
-------------------
2006-08-03 10:01:31

SYS@SKYDB> select systimestamp from dual;


SYSTIMESTAMP
-----------------------------------------------
03-AUG-06 10.02.21.093000 AM +08:00

SYS@SKYDB> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.

修改操作系统时区为 +02:00

SYS@SKYDB> startup
ORACLE instance started.


Total System Global Area   89202456 bytes
Fixed Size                   454424 bytes
Variable Size              62914560 bytes
Database Buffers           25165824 bytes
Redo Buffers                 667648 bytes
Database mounted.
Database opened.

SYS@SKYDB> select sysdate from dual;


SYSDATE
-------------------
2006-08-03 04:03:37


SYS@SKYDB> select systimestamp from dual;


SYSTIMESTAMP
----------------------------------------------
03-AUG-06 04.04.15.687000 AM +02:00

    注:这是我单位机子上实验的结果,由于建了多个数据库,不知道为什么不能通过 ipc 来连接本地数据了,登陆时使用 sqlplus " /@skydb  as sysdba",也就是使用了监听器来连接,但在家里做相同的实验,通过 ipc 连接 sqlplus "/as sysdba",修改时区后,sysdate 依然显示修改前的时间,而 systimestamp 却正确,不知道是什么原因:

SQL> select sysdate from dual;

SYSDATE
-------------------
2006-02-08 22:21:40

SQL> select systimestamp from dual;

SYSTIMESTAMP
---------------------------------------------------------------------------
02-AUG-06 10.22.38.578000 PM +08:00

SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
修改时区为 +09:00
SQL> startup
ORACLE instance started.

Total System Global Area  131145064
bytes

Fixed Size                   453992
bytes

Variable Size             109051904
bytes

Database Buffers           20971520
bytes

Redo Buffers                 667648

bytes

Database mounted.
Database opened.
SQL> select sysdate from dual;

SYSDATE
---------
02-AUG-06

SQL> alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss';

Session altered.

SQL> select sysdate from dual;

SYSDATE
-------------------
2006-08-02 22:32:59               <- 还是之前的时间

SQL> select systimestamp from dual;

SYSTIMESTAMP
---------------------------------------------------------------------------
02-AUG-06 11.35.05.171000 PM +09:00           <- 时间正确

    另外,有个初始化参数 fixed_date,可以设置 sysdate 返回指定的时间:



alter system set fixed_date='2005-04-04-11-00-00'


this fixed_date is normally used, in oracle, for dubugging purpose.


once finishing it, you can set it back:


alter system set fixed_date=none


    Eygle 的关于这个参数的相关文章:Why sysdate is fixed

    current_timestamp/current_date 也会返回数据库的时间,但转换为 session 的时区进行显示,可以使用 alter session set time_zone 改变 session 时区。


4. 四个日期时间类型的实验


SQL> select dbtimezone from dual;

DBTIME
------
+06:00

SQL> select sessiontimezone from dual;

SESSIONTIMEZONE
---------------------------------------------------------------------------
+08:00

SQL> ed
Wrote file afiedt.buf

  1  create table tztest(a date,
  2  b timestamp(0),
  3  c timestamp(0) with time zone,
  4* d timestamp(0) with local time zone)
SQL> /

Table created.

SQL> alter session set nls_date_format ='yyyy-dd-mm hh24:mi:ss';

Session altered.

SQL> select sysdate from dual;

SYSDATE
-------------------
2006-02-08 22:21:40

SQL> select systimestamp from dual;

SYSTIMESTAMP
---------------------------------------------------------------------------
02-AUG-06 10.22.38.578000 PM +08:00

SQL> select current_date from dual;

CURRENT_DATE
-------------------
2006-02-08 22:23:50

SQL> select current_timestamp from dual;

CURRENT_TIMESTAMP
---------------------------------------------------------------------------
02-AUG-06 10.24.04.031000 PM +08:00

SQL> insert into tztest
  2  values(sysdate,systimestamp,systimestamp,systimestamp);

1 row created.

SQL> commit;

Commit complete.

SQL> select * from tztest;

A
-------------------
B
---------------------------------------------------------------------------
C
---------------------------------------------------------------------------
D
---------------------------------------------------------------------------
2006-02-08 22:25:59
02-AUG-06 10.25.59 PM
02-AUG-06 10.25.59 PM +08:00
02-AUG-06 10.25.59 PM

SQL> exit
Disconnected from Oracle9i Enterprise Edition Release 9.2.0.3.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.3.0 - Production

修改了客户端操作系统的时区

C:\Documents and Settings\Administrator>sqlplus sky/xxxx

SQL*Plus: Release 9.2.0.3.0 - Production on Wed Aug 2 23:28:01 2006

Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.


Connected to:
Oracle9i Enterprise Edition Release 9.2.0.3.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.3.0 - Production

SQL> alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss';

Session altered.

SQL> select sysdate from dual;

SYSDATE
-------------------
2006-08-02 22:28:49         <-数据库没有重启,时间依然是修改前的

SQL> select systimestamp from dual;

SYSTIMESTAMP
---------------------------------------------------------------------------
02-AUG-06 11.29.33.609000 PM +09:00   <- 这里却已经改变了,有时区信息,自动转换了?

SQL> select * from tztest;

A
-------------------
B
---------------------------------------------------------------------------
C
---------------------------------------------------------------------------
D
---------------------------------------------------------------------------
2006-08-02 22:25:59                        <- 没变
02-AUG-06 10.25.59 PM                   <- 没变
02-AUG-06 10.25.59 PM +08:00       <- 保存时区信息
02-AUG-06 11.25.59 PM                   <-自动转换为 session 的时区


    本文转自永春博客园博客,原文链接: http://www.cnblogs.com/firstyi/archive/2007/09/24/903931.html ,如需转载请自行联系原作者

相关文章
|
Oracle 关系型数据库 MySQL
LINUX时区设置及与数据库之间(ORACLE MYSQL)的关系
LINUX时区    LINUX 操作系统时区由/etc/localtime设置,其可以是一个指向/usr/share/zoneinfo下文件的软连接, 当然也可以拷贝,在/usr/share/zoneinfo目录下每个文件都包含了特定地区的时区信息,很多都分...
1448 0
|
Oracle 关系型数据库 MySQL
MYSQL和ORACLE时区设置比较
MYSQL: 注意时区会影响TIMESTAMP的取值,默认为系统时区为TIME_ZONE=SYSTEM, 动态可以修改 set global  time_zone = '+8:00';  然后 my.
1229 0
|
关系型数据库 数据库 Oracle
Oracle 数据库中的 时间 时区2
文档id:412160.1 如何查看当前实例的RDBMS DST Patch的版本: A3) for 10g and 11gR1 query v$timezone_file   SQL> conn / as sysdbaConnected.
896 0
|
Oracle 关系型数据库 Java
Oracle 恢复 Java 时区数据工具tzupdater
     甲骨文公司曾经做了一个艰难决定 ,从公共下载区域中删除 tzupdater 工具。
1955 0
|
SQL Oracle 关系型数据库
Oracle的时区问题 #
Oracle的时区问题 Oracle 9i 开始多了 3 个关于时间的数据类型:TIMESTAMP [(precision)] TIMESTAMP [(precision)] WITH TIME ZONE TIMESTAMP [(precision)] WITH LOCAL TIME ZONE,其中 TIMESTAMP [(precision)] WITH TIME ZONE 保存了时区信息。
1196 0
|
2月前
|
Oracle 关系型数据库 Linux
【赵渝强老师】Oracle数据库配置助手:DBCA
Oracle数据库配置助手(DBCA)是用于创建和配置Oracle数据库的工具,支持图形界面和静默执行模式。本文介绍了使用DBCA在Linux环境下创建数据库的完整步骤,包括选择数据库操作类型、配置存储与网络选项、设置管理密码等,并提供了界面截图与视频讲解,帮助用户快速掌握数据库创建流程。
291 93
|
24天前
|
Oracle 关系型数据库 Linux
【赵渝强老师】使用NetManager创建Oracle数据库的监听器
Oracle NetManager是数据库网络配置工具,用于创建监听器、配置服务命名与网络连接,支持多数据库共享监听,确保客户端与服务器通信顺畅。
122 0
|
4月前
|
存储 Oracle 关系型数据库
服务器数据恢复—光纤存储上oracle数据库数据恢复案例
一台光纤服务器存储上有16块FC硬盘,上层部署了Oracle数据库。服务器存储前面板2个硬盘指示灯显示异常,存储映射到linux操作系统上的卷挂载不上,业务中断。 通过storage manager查看存储状态,发现逻辑卷状态失败。再查看物理磁盘状态,发现其中一块盘报告“警告”,硬盘指示灯显示异常的2块盘报告“失败”。 将当前存储的完整日志状态备份下来,解析备份出来的存储日志并获得了关于逻辑卷结构的部分信息。
|
2月前
|
SQL Oracle 关系型数据库
Oracle数据库创建表空间和索引的SQL语法示例
以上SQL语法提供了一种标准方式去组织Oracle数据库内部结构,并且通过合理使用可以显著改善查询速度及整体性能。需要注意,在实际应用过程当中应该根据具体业务需求、系统资源状况以及预期目标去合理规划并调整参数设置以达到最佳效果。
228 8
|
4月前
|
SQL Oracle 关系型数据库
比较MySQL和Oracle数据库系统,特别是在进行分页查询的方法上的不同
两者的性能差异将取决于数据量大小、索引优化、查询设计以及具体版本的数据库服务器。考虑硬件资源、数据库设计和具体需求对于实现优化的分页查询至关重要。开发者和数据库管理员需要根据自身使用的具体数据库系统版本和环境,选择最合适的分页机制,并进行必要的性能调优来满足应用需求。
195 11

推荐镜像

更多