Date 类型是我们经常使用的时间类型数据表示,包括了年月日时分秒信息。作为 Date 类型的一个拓展, Oracle 提供了 Timestamp 数据类型,作为高精度时间类型的体现。

1 Timestamp 的高精度

Timestamp 在官方中的定义方式是 timestamp(n) ,其中 n 表示秒级片段( fractional_seconds )的精确度。作为 Date 类型的一个拓展, Timestamp 提供了更为精确的时间定位。

SQL> select systimestamp from dual;

SYSTIMESTAMP

--------------------------------------------------------------------------------

13-7 -11 07.52.16 . 562000 下午 +08:00

SQL> select sysdate from dual;

SYSDATE

------------------------------

2011-7-13 20:13:55

使用 systimestamp 函数,我们可以获取到当前时间的 timestamp with local time zone 取值。默认情况下,我们发现和 sysdate 显示的有一些差异。控制和显示 timestamp 格式的参数,可以通过 v$nls_parameters 进行查看。

SQL> select * from v$nls_parameters;

PARAMETER VALUE

------------------------------ ----------------------------------------

(篇幅原因,有省略

NLS_SORT BINARY

NLS_TIME_FORMAT HH.MI.SSXFF AM

NLS_TIMESTAMP_FORMAT DD-MON-RR HH.MI.SSXFF AM

NLS_TIME_TZ_FORMAT HH.MI.SSXFF AM TZR

NLS_TIMESTAMP_TZ_FORMAT DD-MON-RR HH.MI.SSXFF AM TZR

19 rows selected

参数 nls_timestamp_format nls_timestamp_tz_format 分别来控制 timestamp timestamp with local zone 的显示格式。

上面 systimestamp 显示的信息,可以解析为: 2011-7-13 19:52:16 。稍稍费解的是秒后面的 562000 数字。这个是 Timestamp 的秒片段( fractional seconds ),就是秒向下的精度划分。 timestamp 定义中的 n 就是指定的每秒划分的精度范围。

实际应用中, n 取值为 0-9 ,默认为 6 。从上面例子上的 systimestamp 函数返回值上看,也是的确如此。

SQL> create table t (d1 timestamp, d2 timestamp(0), d3 timestamp(9));

Table created

SQL> desc t;

Name Type Nullable Default Comments

---- ------------ -------- ------- --------

D1 TIMESTAMP(6) Y

D2 TIMESTAMP(0) Y

D3 TIMESTAMP(9) Y

那么, timestamp 类型的高精度有什么作用呢?个人认为大部分还是为了前端并发访问时候的锁机制,还有一些特殊行业的高精度需求。很多开发框架都需要使用一个高精度的数据列来标记行访问的时间顺序,通过 timestamp 的精度,基本可以满足这部分的需要。

2 Timestamp with time zone

Timestamp 类型的另一个特性就是时区 timezone 特性。我们知道世界各地所处的时区不同,对应同一个时刻显示的时间是不同的。所以如果精确定义一个时间点,特别是对应一个全球性系统的时候,时区 Timezone 是不可或缺的考虑因素。

Date 类型只能适应于一般时间的表示,如果加入了时区因素,就无能为力了。在这样的情况下,就可以选择 Timestamp 类型的一个拓展类型, timestamp with time zone 。这样就可以把当前对应的时区信息加入到数据列中。

函数 systimestamp 返回标准类型就是 timestamp with time zone 。与一般 timestamp 类型不同的是, timestamp with time zone 额外加入了当前时区的信息。

SQL> select systimestamp from dual;

SYSTIMESTAMP

--------------------------------------------------------------------------------

13-7 -11 07.52.16.562000 下午 +08:00

+08:00 表示时区,全球有 12 个时区。系统的时区通过参数设置或者当前操作系统 OS 的配置来获取。

SQL> create table t (d1 date, d2 timestamp, d3 timestamp with time zone);

Table created

SQL> insert into t values (systimestamp, systimestamp, systimestamp);

1 row inserted

SQL> commit;

Commit complete

SQL> select * from t;

D1 D2 D3

-------------------- -----------

2011-7-13 21:12:32 13-7 -11 09.12.32.859000 下午 13-7 -11 09.12.32.859000 下午 +08:00

加入时区信息之后,可以做到全球时间下的绝对时间比较。

此外, timestamp 还有一个 timestamp with local time zone 的拓展类型。也包括时区信息,与 time zone 的差别有下面几个:

ü 不管是什么时区的日期插入到数据库中,都会进行正规化工作。将其他时区的日期转化为数据库对应的时区( Database Time Zone )中;

ü 当进行检索操作的时候, local time zone 类型数据又会被转化为当前检索会话对应的 time zone 中。这一系列的转化操作对 end user 而言都是透明的;

在对应会话和数据库的时区上,与系统参数 NLS_TERRITORY 是相关的。 Oracle 往往通过这个参数的国家设置来判断时区。而客户端的参数往往与 nls_lang 相关。

3 Timestamp 显示格式控制

最后我们一起来看看 timestamp 显示的格式方式。默认情况下, timestamp 以及 timestamp with time zone 的显示是与系统参数 nls_timestamp_format nls_timestamp_tz_format 有关。在我们的实验环境下,两个格式字符串( format string )分别为:

NLS_TIMESTAMP_FORMAT DD-MON-RR HH.MI.SSXFF AM

NLS_TIMESTAMP_TZ_FORMAT DD-MON-RR HH.MI.SSXFF AM TZR

其中, DD MON HH MI 都是我们非常熟悉的日期格式字符串。 RR 表示使用年的后两位进行表示。而 SSXFF 是一个组合条件,应该被拆分为 SS X FF 三个部分。 SS 表示秒信息, X 表示基数开关,而 FF 表示小于一秒的时间片段。

X 表示的基数开关是什么意思呢?我们通过实验就可以看出情况。

SQL> select to_char(systimestamp,'DD-MON-RR HH.MI.SSXFF AM') SSXFF, to_char(systimestamp,'DD-MON-RR HH.MI.SSFF AM') SSFF from dual;

SSXFF SSFF

-------------------------------------- -------------------------------------

13-7 -11 09.37. 16 .843000 下午 13-7 -11 09.37. 16843000 下午

加入了 X 表示开关之后,就在秒为加入了一个 . 号表示分割。便于查看。

AM 表示是否使用( AM PM )显示上下午信息, TZR 则表示是否显示出时区信息。

当显示 timestamp 类型的时候,如果没有明确指定显示格式,系统会自动使用 nls_timestamp_format 系列参数。

SQL> select to_char(systimestamp, 'yyyy-mm-dd hh24:mi:ss ff tzr') from dual;

TO_CHAR(SYSTIMESTAMP,'YYYY-MM-

--------------------------------------------------------------

2011-07-13 21:40:50 265000 +08:00

如果期望在会话(或者系统)一级修改参数,就要使用 alter session 或者 alter system 方法。

SQL> select to_char(systimestamp) from dual;

TO_CHAR(SYSTIMESTAMP)

-----------------------------------------------------------------------

13-7 -11 09.42.44.343000 下午 +08:00

// 对当前会话修改参数;

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

Session altered

SQL> select to_char(systimestamp) from dual;

TO_CHAR(SYSTIMESTAMP)

--------------------------------------------------------------

2011-07-13 21:43:18 984000 +08:00

4 、结论

timestamp 系列类型是对 Oracle Date 类型的一种有益补充。在需要的场合下,可以适当使用。

广播电视节目制作经营许可证(京) 字第1234号 中国互联网协会会员