您的位置:首页 > 数据库 > Oracle

ORACLE 日期时间数据类型与时间间隔数据类型讲解

2013-10-08 14:30 459 查看
23.1 概述
数据类型
说明
DATE
日期时间型,精确到秒
TIMESTAMP(fractional_seconds_precision)
时间精确到秒后面fractional_seconds_precision位,默认6位,最多9位
TIMESTAMP(fractional_seconds_precision)
WITH TIME ZONE
带时区信息,时间精确到秒后面fractional_seconds_precision位,默认6位,最多9位
TIMESTAMP(fractional_seconds_precision)
WITH LOCAL TIME ZONE
带时区信息,时间精确到秒后面fractional_seconds_precision位,默认6位,最多9位,但是你查询出来的是经过转换成会话所在时区的时间,是个神奇的字段哦
INTERVAL YEAR(year_precision) TO MONTH
存储一个时间间隔,year_precision说明年的整数位数,最多9位,默认2位。
INTERVAL DAY (day_precision) TO SECOND(fractional_seconds_precision)
存储一个时间间隔,day_precision说明天的整数位数,最多9位,默认2位。fractional_seconds_precision说明秒后面小数位数,默认6位,最多9位。
一般将前四种数据类型DATE, TIMESTAMP, TIMESTAMP WITH TIME ZONE和TIMESTAMP WITH LOCAL TIME ZONE 一般称之为日期时间数据类型(datetimes),而将INTERVAL YEAR TO MONTH and INTERVAL DAY TO SECOND 这两种数据类型称之为时间间隔数据类型(intervals).
23.2 小技巧:不用TO_DATE来输入或比较不带时分秒的日期
对于不带时分秒的日期,可用使用DATE这种方法,使用这种方法是后面的日期需要按照YYYY-MM-DD的格式,如下
insert into test_ly(a) values(DATE '2008-08-10')
如果是输入当天的0时0分0秒,使用
insert into test_ly(mydate) values(trunc(sysdate))

DATE方法还可以用于比较日期
select * from BOM_CALENDAR_DATES where calendar_code='HELS_CAL' AND ALENDAR_DATE>=DATE '2009-01-01' ORDER BY CALENDAR_DATE

如何查询某天的数据?
select * from test_ly where trunc(mydate)=date '2009-11-03'

对于格式是参数NLS_DATE_FORMAT的字符串(具体使用的哪种可以通过 select * from nls_session_parameters where parameter='NLS_DATE_FORMAT'; 查看,只是可惜的是这个参数一般没有修改成为符合国人习惯的YYYY-MM-DD格式),还可以直接使用单引号将日期包括起来代表日期,比如:
insert into test_ly(mydate) values('01-1月-09')
比如我使用alter session set NLS_DATE_FORMAT='YYYY-MM-DD' 修改后
然后就这样可以插入日期了
insert into test_ly(mydate) values('2009-01-01')
23.3 某天星期几?
今天星期几?
select to_char(sysdate,'DAY', 'NLS_DATE_LANGUAGE = ''SIMPLIFIED CHINESE''') from dual;

某天星期几?
select to_char(DATE '2009-11-07','DAY', 'NLS_DATE_LANGUAGE = ''SIMPLIFIED CHINESE''') from dual;
select to_char(HIREDATE,'DAY','NLS_DATE_LANGUAGE = ''SIMPLIFIED CHINESE''') as xingqi,HIREDATE from EMP;

如果当前会话的NLS_DATE_LANGUAGE参数(这个参数值可以通过动态视图nls_session_parameters查询到 )为SIMPLIFIED CHINESE,也可简单点:
select to_char(DATE '2009-11-07','DAY') from dual;

23.4 获取年,月,日,时,分,秒
23.4.1 获取年、月、日
对于4种日期时间型数据,获取年月日的方法都是一样的,使用EXTRACT函数。
select mydate,EXTRACT(YEAR FROM mydate) as date_nian,EXTRACT(MONTH FROM mydate) AS date_yue,EXTRACT(DAY FROM mydate) AS date_ri,

mytimestamp,EXTRACT(YEAR FROM mytimestamp) as ts_nian,EXTRACT(MONTH FROM mytimestamp) AS ts_yue,EXTRACT(DAY FROM mytimestamp) AS tm_ri FROM test_ly;
23.4.2 TIMESTAMP类型字段获取时分秒
获取的是记录本身的时分秒,与用户会话所处时区没有关系,注意,小时返回的是24小时制时间,秒钟会返回指定精度,默认是6位小数。
select mytimestamp,EXTRACT(HOUR FROM mytimestamp) as xiaoshi,EXTRACT(MINUTE FROM mytimestamp) as fenzhong,EXTRACT(SECOND FROM mytimestamp) as miao FROM test_ly;
23.4.3 TIMESTAMP WITH TIME ZONE类型字段获取时分秒
获取的是这个字段所记载的时区的分秒,但是获取的小时数却是时间标准时间(UTC)的小时 数,与用户会话所处时区没有关系。注意,小时返回的是24小时制时间,秒钟会返回指定精度,默认是6位小数。解释:当时记载的是东8区(北京时间所在时 区)的下午1点,但是取得的小时却是5,也就是13-8=5,换算成了世界标准时间。
select mytswtm,EXTRACT(HOUR FROM mytswtm) as xiaoshi,EXTRACT(MINUTE FROM mytswtm) as fenzhong,EXTRACT(SECOND FROM mytswtm) as miao FROM test_ly;

23.4.4 TIMESTAMP WITH LOCAL TIME ZONE类型字段获取时分秒
这种数据类型从某种程度上是欺骗你的,也是自适应的,它显示的字段值以及获取的时分秒与会话 所在的时区有关,会自动转化成会话所在时区的时间。你看,我当时插入的记录是东8区下午1点多,我用命令将自己会话的时区设置为东9区(ALTER SESSION SET TIME_ZONE = '+9:00';),然后查看数据,会发现小时数加了一个小时。
select mytswltm,EXTRACT(HOUR FROM mytswltm) as xiaoshi,EXTRACT(MINUTE FROM mytswltm) as fenzhong,EXTRACT(SECOND FROM mytswltm) as miao FROM test_ly;

23.4.5 DATE类型数据获取时分秒
系统看起来并没有直接提供获取DATE数据类型时分秒的方面,前面用到的EXTRACT函数 对DATE数据类型来获取时分秒并不使用,看来只有另想办法。我想到的办法是将DATE类型转换为TIMESTAMP数据类型再取时分秒,事实证明可行, 或许还有更好的办法我不知道吧。
select mydate,EXTRACT(HOUR FROM TO_TIMESTAMP(TO_CHAR(mydate,'YYYY-MM-DD HH24:MI:SS'),'YYYY-MM-DD HH24:MI:SS')) as xiaoshi,EXTRACT(MINUTE FROM TO_TIMESTAMP(TO_CHAR(mydate,'YYYY-MM-DD HH24:MI:SS'),'YYYY-MM-DD HH24:MI:SS')) as fenzhong,EXTRACT(SECOND
FROM TO_TIMESTAMP(TO_CHAR(mydate,'YYYY-MM-DD HH24:MI:SS'),'YYYY-MM-DD HH24:MI:SS')) as miao FROM test_ly;
23.5日期和TIMESTAMP类型之间的转换
将当前日期时间转换为TIMESTAMP使用SYSTIMESTAMP函数
SELECT SYSTIMESTAMP FROM dual;
将TIMESTAMP数据类型转换为某个时区的时间可以使用FROM_TZ函数
比如将2003-11-20 19:30:00这个时间转换为东8区时间:
SELECT FROM_TZ(TIMESTAMP '2003-11-20 19:30:00', '+8:00') FROM dual;
23.6查看、修改时区
23.6.1 当前会话所处时区
select SESSIONTIMEZONE from dual
23.6.2 数据库所处时区
SELECT DBTIMEZONE from dual
23.6.3更改当前会话所处时区
比如更改当前会话所处时区为东9区
ALTER SESSION SET TIME_ZONE = '+9:00';
23.6.4 如何查看TIMESTAMP WITH TIME ZONE数据类型存储的是那个时区?
还是使用EXTRACT函数,可以看出,分别使用的是东8区和东9区。
select mytswtm,extract(TIMEZONE_HOUR FROM mytswtm) AS shiqu from test_ly
23.6.5 如何查看总共有哪些时区地?
SELECT * FROM V$TIMEZONE_NAMES
23.7 DATE 和TIMESTAMP类型的区别
首先一个区别便是,DATE数据类型精确到秒,而其他三种(TIMESTAMP, TIMESTAMP WITH TIME ZONE, TIMESTAMP WITH LOCAL TIME ZONE)最多可以精确到秒后面的第9位小数,其他三种是DATE类型的扩展。

做试验说明更多:
create table test_ly(

mydate date,

mytimestamp TIMESTAMP(6),

mytswtm TIMESTAMP(6) WITH TIME ZONE,

mytswltm TIMESTAMP(6) WITH LOCAL TIME ZONE,

myiytm INTERVAL YEAR(2) TO MONTH,

myidts INTERVAL DAY(6) TO SECOND(6)

)

插入一行记录比较,注意LOCALTIMESTAMP返回的是会话当前时区的当前时间的 TIMESTAMP类型的值,不带时区信息,而CURRENT_TIMESTAMP返回的是会话当前时区的当前时间并带有当前会话时区的 TIMESTAMP WITH TIME ZONE类型的值。具体区别如下表:
Table 10-1. Comparison of functions that return current date and time
Function
Time zone
Datatype returned
CURRENT_DATE
Session
DATE
CURRENT_TIMESTAMP
Session
TIMESTAMP WITH TIME ZONE
LOCALTIMESTAMP
Session
TIMESTAMP
SYSDATE
Server
DATE
SYSTIMESTAMP
Server
TIMESTAMP WITH TIME ZONE
insert into test_ly(mydate,mytimestamp,mytswtm,mytswltm)

values(sysdate,LOCALTIMESTAMP,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP)
要将LOCALTIMESTAMP转换成CURRENT_TIMESTAMP可以使用
select TO_TIMESTAMP_TZ(LOCALTIMESTAMP, 'DD-MON-RR HH.MI.SSXFF PM TZH:TZM') from dual;

然后我看看插入的几条记录,显示的时间内容基本一致。
我将我当前会话的时区改成东9区,然后再插入记录
insert into test_ly(mydate,mytimestamp,mytswtm,mytswltm)

values(sysdate,LOCALTIMESTAMP,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP)
这时候返回记录看看异同:发现sysdate记载的是服务器时间,与会话所取时区没有关 系,TIMESTAMP类型字段显示的是插入记录时会话时区的时间,不带时区,你看东8区是上午10点多,东9区则是上午11点多,TIMESTAMP WITH TIME ZONE类型字段显示的是插入记录时会话时区的时间,带时区信息,也就是东9区什么时候,TIMESTAMP WITH LOCAL TIME ZONE字段显示时没有时区信息,这是根据会话所在时区灵活显示时间的。
为了更好的说明TIMESTAMP WITH LOCAL TIME ZONE类型字段是根据会话灵活显示时间的,我现在又将时区修改为东8区,再看显示,你会发现该字段显示的小时数变了,和sysdate相同了,这就是神 奇之处,显示给你看的是根据会话所在时区转换后的时间,而TIMESTAMP和TIMESTAMP WITH TIME ZONE字段则不会转化显示时间给你看。

如何插入指定日期的TIMESTAMP数据?
insert into test_ly(mydate,mytimestamp,mytswtm,mytswltm)

values(sysdate,TIMESTAMP '1983-11-09 04:26:50.124',TIMESTAMP '1983-11-09 04:26:50.124 +8:00',TIMESTAMP '1983-11-09 04:26:50.124 +8:00')

23.8如何对date类型字段实现各种细度的汇总?
我想这些东东可能就是oracle宣称的商务只能可以做到很小的细微粒度吧,比如查看某些日子有多少人登陆过EBS系统:
23.8.1 按日汇总
select TRUNC(start_time) AS RIQI,count(*) as denglurenshu from FND_LOGINS where start_time> DATE '2009-10-01' group by TRUNC(start_time)
23.8.2 按月汇总
select TRUNC(start_time,'MONTH') AS YUEFEN,count(*) as denglurenshu from FND_LOGINS where start_time> DATE '2009-09-01' group by TRUNC(start_time,'MONTH')
23.8.3 按年汇总
select TRUNC(start_time,'YEAR') AS nian,count(*) as denglurenshu from FND_LOGINS group by TRUNC(start_time,'YEAR')
23.8.4 按季度汇总
select TRUNC(start_time,'Q') AS jidu,count(*) as denglurenshu from FND_LOGINS where start_time> DATE '2009-01-01' group by TRUNC(start_time,'Q')
23.8.5 按周汇总
不过值得注意的是,默认周日是一周的开始,周六是一周的结束哦。当然可以通过更改数据库参数NLS_TERRITORY来实现更改。
select TRUNC(start_time,'DAY') AS jidu,count(*) as denglurenshu from FND_LOGINS where start_time> DATE '2009-10-01' group by TRUNC(start_time,'DAY')
23.8.6按小时汇总
select TRUNC(start_time,'HH') AS jidu,count(*) as denglurenshu from FND_LOGINS where start_time> DATE '2009-11-01' group by TRUNC(start_time,'HH')
23.8.7 按分钟汇总
select TRUNC(start_time,'MI') AS jidu,count(*) as denglurenshu from FND_LOGINS where start_time> DATE '2009-11-03' group by TRUNC(start_time,'MI')
23.9日期时间类型数据相加减,相差多少?
23.9.1 多少天(时分秒)之前或者多少天(时分秒)之后
直接用DATE型数据与数字(可以使用小数)进行相加减即可,比如
SELECT SYSDATE + 2 FROM DUAL

SELECT SYSDATE - 2.5 FROM DUAL
比如计算3天5小时后是什么时候可以这么计算:
SELECT SYSDATE + (3 + 5/24) FROM DUAL
23.9.2 多少(年)月之前或者多少(年)月之后
使用函数ADD_MONTHS进行,比如
select ADD_MONTHS(SYSDATE,1) FROM DUAL
值得注意的是,月有大小,比如2009年10月有31日,那么加一个月后是11月31日吗?肯定不是啦,11月没有31日,那么应该是11月30日。
select ADD_MONTHS(DATE '2009-10-31',1) FROM DUAL
同样的,如果是闰年闰月之类的问题呢,比如2008年2月有29天,那么这天一年后是哪天呢?当然是2009年2月28日。
select ADD_MONTHS(DATE '2008-02-29',12) FROM DUAL

23.9.3 使用INTERVAL来计算多少年多少月多少小时多少分钟之前之后
随便举几个例子,interval的用法可以参考sql reference文档。
10年2个月以后的日期
select sysdate + interval '10-2' year(2) to month from dual
20年以后
select sysdate + interval '20' year from dual
5个月后
select sysdate + interval '5' month from dual
5天10分钟以后
select sysdate + interval '5 00:10' day to minute from dual
5小时10分钟秒以后
select sysdate + interval '5:10:10.11111' hour to second(5) from dual
10年5小时10分钟后
select sysdate + interval '10' year + interval '5:10' hour to minute from dual
23.9.4 使用NUMTODSINTERVAL和NUMTOYMINTERVAL 来计算多少年(月),时(分)之后
用法:NUMTODSINTERVAL(n,[‘DAY’|’HOUR’|’MINUTE’|’SECOND’])
NUMTOYNINTERVAL(n,[‘YEAR’|’MONTH’])
用法示例:
一个小时后:
select sysdate,sysdate + NUMTODSINTERVAL(1,'HOUR') from dual
5个月5小时后:
select sysdate,sysdate + NUMTOYMINTERVAL(5,'MONTH') + NUMTODSINTERVAL(5,'HOUR') from dual
23.9.5 本月,今年还剩多少天?
基本用法是使用LAST_DAY函数,但是还有些问题要注意。
本月还剩多少天?
请注意,LAST_DAY函数返回的是参数日期月份的最后一天的同小时同分钟同秒钟的时间,其实本月的最后一时是下月的第一天的0时0分0秒。
select LAST_DAY(trunc(sysdate)) + 1 - sysdate from dual
今年还剩多少天?
select ADD_MONTHS(TRUNC(sysdate,'YEAR'),12) - sysdate from dual
23.9.6如何计算两个timestamp相差多少年月,多少天多少小时多少分钟多少秒
select (SYSTIMESTAMP - TIMESTAMP '1983-11-09 04:26:50.124 +8:00') YEAR TO MONTH as xiangchaninayue from dual

select (SYSTIMESTAMP - TIMESTAMP '1983-11-09 04:26:50.124 +8:00') DAY(6) TO SECOND as xiangchatianshifenmiao from dual
23.10 如何让datetimes字段类型显示更加符合国人习惯?
可以更改会话让当前的日期更加符合国人的习惯,最好是更改数据库设置,
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'
还可以对日期进行格式化,比如
select TO_CHAR(sysdate,'YYYY-MM-DD HH24:MI:SS') from dual
但是这种格式化对TIMESTAMP类型数据不管用,还是显示比较丑陋的方式,需要进行如下的格式化才好:
select to_char(SYSTIMESTAMP,'YYYY-MM-DD HH24:MI:SSxFF TZH:TZM') from dual
select to_char(SYSTIMESTAMP,'YYYY-MM-DD HH24:MI:SSxFF') from dual
select to_char(SYSTIMESTAMP,'YYYY-MM-DD HH24:MI:SS') from dual
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: