oracle存储时间类型 date 和 timestamp区别

、数据库存储时间用什么类型好

数据库存储时间的存储类型大概有3种,varchar2,date 和 timestamp,目前来说date最为普遍,使用varchar2,如果只做展示用,可以选择,但是长远来说,可能存在存储时间格式的差异,因为存储为varchar2,就不存在时间格式校验了,那对于以后维护是一件很可怕的事情,而date对于精度要求只要秒级别的时间是最友好的选择,对于时间精度要求时毫秒级别,比如要确定某一个游戏两个玩家操作动作谁的先后顺序,那肯定是要使用timestamp类型的 ,在此也建议一般时间存储用date,就如专业的事情专业人士干一样,因此在此主要讨论date 和 timestamp的区别

二、date和timestamp 的区别

2.1date类型的特点:

2.1.1 date类型是Oracle常用的日期型变量,date类型的最小时间间隔是秒,对于时间精度不需要到毫秒级别的可以使用该类型

SQL> SELECT TO_CHAR(sysdate,'yyyy-MM-dd HH24:MI:SS') "Date" FROM dual; 

执行结果: 2018-08-25 21:41:06

可以看出date的最小单位是秒,因为最小单位是秒,在两条数据连续写表的时候是不能直接通过时间来区分数据写入的先后顺序的

在此有一个特别使用场景,就是数据库存储使用的是date类型,我有一个需求,需要查出操作员登记的某一批参观者中的第一个登记的参观者,那这个需求就只能通过取出最小id(主键)的方法获取最先写入的数据,但是也不需要因为这种场景把数据存储类型改成timestamp ,因为这种特殊的情况使用比较少,如果经常使用这种特性,那就要存储为timestamp

2.1.2 验证date时间类型建表SQL>

CREATE TABLE DATE_TABLE(
   ID NUMBER(2), 
   D1 DATE,

   OBJCODE VARCHAR2(20)
  )

创建序列SQL>

CREATE SEQUENCE DATE_TABLE_SEQ 
INCREMENT BY 1 
START WITH 1 
NOMAXVALUE 
NOCYCLE 
NOCACHE;
插入语句SQL>

insert into date_table (id,d1) values(date_table_seq.nextval,sysdate,'objeCode');
insert into date_table (id,d1) values(date_table_seq.nextval,sysdate,'objeCode');

执行查询语句之后,出现两个插入时间是一样的,因为date的时间精度是秒级别的,

oracle存储时间类型 date 和 timestamp区别

2.1.3 查出操作员登记的某一批参观者中的第一个登记的参观者SQL>

select * from date_table where id =(select min(id) from date_table where objcode='objeCode' )

2.2 timestamp 类型的特点:

timestamp 简称时间戳, 时间戳可以存储世纪、4位年、月、日、时(以24小时格式)、分、秒。与DATE类型相比,时间戳具有以下优点:

    ● 时间戳可以存储秒的小数位。

    ● 时间戳可以存储时区。

使用时间戳类型

    时间戳有3种类型,如表所示。

    表  时间戳类型

类    型 说    明
TIMESTAMP[(seconds_precision)] 存 储世纪、4位的年、月、日、时(以24小时格式)、分和秒。seconds_precision为可选参数,用于指定精度,该参数为一个整数,范围从 0~9,默认值为9;意思是表示秒的数字的小数点右边可以存储9位数字。如果试图在秒的小数中保存超过TIMESTAMP存储精度的数字,那么该小数将被 取整
TIMESTAMP[(seconds_precision)]WITH TIME ZONE 扩展TIMESTAMP,用于存储时区
TIMESTAMP[(seconds_precision)]WITH LOCAL TIME ZONE 扩展TIMESTAMP,将给定的时间值转换成数据库的本地时区。转换过程称为时间值的规格化(normalizing)

2.1.1. 使用TIMESTAMP类型

    与其他类型类似,TIMESTAMP类型也可以用来在表中定义列。下面这个语句用于创建一个表purchases_with_timestamp, 该表用来存储顾客的购买记录。该表包含了一个TIMESTAMP类型的列made_on,该列用来记录顾客在何时购买了产品。注意TIMESTAMP的精 度设置为4(这意味着在秒的小数点右边可以存储4位小数):

CREATE TABLE TIMESTAMP_TABLE (  
  PRODUCT_ID      NUMBER(2),  
  CUSTOMER_ID   NUMBER(2),  
  CREATE_TIME    TIMESTAMP(4)  
);  
insert into timestamp_table (product_id, customer_id, create_time  ) values ( 1, 1, timestamp '2005-05-13 07:15:31.1234' );  
insert into timestamp_table (product_id, customer_id, create_time  ) values ( 2, 2, systimestamp );  
insert into timestamp_table (product_id, customer_id, create_time  ) values ( 3, 3, systimestamp ); 

select product_id,customer_id,TO_CHAR(create_time,'yyyy-MM-dd HH24:MI:SS:FF4') from timestamp_table

oracle存储时间类型 date 和 timestamp区别

可以看出,使用时间戳是可以分辨出两条语句插入的先后顺序的,其中yyyy-MM-dd HH24:MI:SS:FF4中的FF4显示小数秒位数信息

其他两种类型,见另外一篇转载文章 https://blog.csdn.net/Master_Shifu_/article/details/82057275

 

三、计算两个时间间的间隔年数、月数、天数、小时数和秒数

3.1 date类型的时间间隔计算

:select to_date('2018-8-30 03:12:00','yyyy-mm-dd hh24:mi:ss')-sysdate from dual

oracle存储时间类型 date 和 timestamp区别

可以看出以上计算的时间是具体的天数的小数位,如果具体要到多少小时多少分其实还是不直观,当然我们可以根据一天有多少秒进行换算,但是不如直接转换成timestamp 来计算两个日期的间隔来得有效

3.2 timestamp 类型的时间间隔计算

select to_timestamp('2018-8-30 03:12:00','yyyy-mm-dd hh24:mi:ss')-systimestamp from dual

oracle存储时间类型 date 和 timestamp区别

可以看出,时间戳中两个时间相减,直接得到了具体的时分秒乃至毫秒值

SELECT  a1.time1, 
         a1.time2, 
         substr((a1.time2-a1.time1),instr((a1.time2-a1.time1),' ')+7,2)                 seconds, 
         substr((a1.time2-a1.time1),instr((a1.time2-a1.time1),' ')+4,2)                 minutes, 
         substr((a1.time2-a1.time1),instr((a1.time2-a1.time1),' ')+1,2)                 hours, 
         trunc(to_number(substr((a1.time2-a1.time1),1,instr(a1.time2-a1.time1,' '))))   days, 
        trunc(to_number(substr((a1.time2-a1.time1),1,instr(a1.time2-a1.time1,' ')))/7) weeks 
  FROM (
    SELECT  to_timestamp('2018-8-28 03:12:00','yyyy-mm-dd hh24:mi:ss') AS time1, 
            to_timestamp('2018-8-30 08:42:00','yyyy-mm-dd hh24:mi:ss') AS time2
    FROM dual        
  ) a1

oracle存储时间类型 date 和 timestamp区别

这样就可以不再需要关心一天有多少秒在麻烦的计算中。因此,得到天数、月数、天数、时数、分钟数和秒数就成为用substr函数摘取出数字的事情了。 

3.3  date类型与timestamp 类型的相互转换

 date和timestamp之间的相互转换可以通过to_char来转换:

   timestamp——>date:   select to_date(to_char(systimestamp,'yyyy-mm-dd hh24:mi:ss'),'yyyy-mm-dd hh24:mi:ss') from dual

  date ——>timestamp:   select to_timestamp(to_char(sysdate,'yyyy-mm-dd hh24:mi:ss'),'yyyy-mm-dd hh24:mi:ss') from dual

四、date类型获取两个时间区间之内的数据(timestamp也适用)

CREATE TABLE DATE_TABLE(
   ID NUMBER(2), 
   D1 DATE,

   OBJCODE VARCHAR2(20)
  )

Insert into EXPORT_TABLE (ID,"TO_CHAR(D1,'YYYY-MM-DDHH24:MI:SS')",OBJCODE) values (6,'2018-08-25 22:16:32','objeCode');
Insert into EXPORT_TABLE (ID,"TO_CHAR(D1,'YYYY-MM-DDHH24:MI:SS')",OBJCODE) values (7,'2018-08-25 22:16:32','objeCode');
Insert into EXPORT_TABLE (ID,"TO_CHAR(D1,'YYYY-MM-DDHH24:MI:SS')",OBJCODE) values (8,'2018-08-25 23:41:24','objeCode');
Insert into EXPORT_TABLE (ID,"TO_CHAR(D1,'YYYY-MM-DDHH24:MI:SS')",OBJCODE) values (9,'2018-08-25 23:42:05','objeCode');
Insert into EXPORT_TABLE (ID,"TO_CHAR(D1,'YYYY-MM-DDHH24:MI:SS')",OBJCODE) values (10,'2018-08-25 23:40:19','objeCode');
Insert into EXPORT_TABLE (ID,"TO_CHAR(D1,'YYYY-MM-DDHH24:MI:SS')",OBJCODE) values (11,'2018-08-25 23:38:32','objeCode');
Insert into EXPORT_TABLE (ID,"TO_CHAR(D1,'YYYY-MM-DDHH24:MI:SS')",OBJCODE) values (12,'2018-08-25 23:43:43','objeCode');
Insert into EXPORT_TABLE (ID,"TO_CHAR(D1,'YYYY-MM-DDHH24:MI:SS')",OBJCODE) values (13,'2018-08-23 14:34:34','objeCode');
Insert into EXPORT_TABLE (ID,"TO_CHAR(D1,'YYYY-MM-DDHH24:MI:SS')",OBJCODE) values (14,'2018-08-24 14:34:34','objeCode');
Insert into EXPORT_TABLE (ID,"TO_CHAR(D1,'YYYY-MM-DDHH24:MI:SS')",OBJCODE) values (15,'2018-08-27 14:34:34','objeCode');
Insert into EXPORT_TABLE (ID,"TO_CHAR(D1,'YYYY-MM-DDHH24:MI:SS')",OBJCODE) values (16,'2018-08-29 14:34:34','objeCode');
Insert into EXPORT_TABLE (ID,"TO_CHAR(D1,'YYYY-MM-DDHH24:MI:SS')",OBJCODE) values (17,'2018-08-31 14:34:34','objeCode');
Insert into EXPORT_TABLE (ID,"TO_CHAR(D1,'YYYY-MM-DDHH24:MI:SS')",OBJCODE) values (18,'2018-09-01 14:34:34','objeCode');
Insert into EXPORT_TABLE (ID,"TO_CHAR(D1,'YYYY-MM-DDHH24:MI:SS')",OBJCODE) values (19,'2018-08-01 14:34:34','objeCode');

oracle存储时间类型 date 和 timestamp区别

4.1 通过to_date比较

SELECT ID,to_char(d1,'yyyy-MM-dd HH24:mi:ss') FROM date_table 
WHERE 
d1>=to_date('2018-08-25 23:41:24','yyyy-MM-dd HH24:mi:ss')
AND 
d1<=to_date('2018-08-25 23:43:43','yyyy-MM-dd HH24:mi:ss')

oracle存储时间类型 date 和 timestamp区别

4.1 通过to_char比较

SELECT ID,to_char(d1,'yyyy-MM-dd HH24:mi:ss') FROM date_table 
WHERE 
to_char(d1,'yyyy-MM-dd HH24:mi:ss') BETWEEN '2018-08-25 23:41:24'
AND 
'2018-08-25 23:43:43'

oracle存储时间类型 date 和 timestamp区别

由此也可见,between..and 其实也是上下闭区间的 其效果等价于 >= and <=

4.3 通过统计8月的访问网址总数据比较to_date和to_char的区别

SELECT ID,to_char(d1,'yyyy-MM-dd HH24:mi:ss') FROM date_table 
WHERE 
d1>=to_date('2018-08-01','yyyy-MM-dd')
AND 
d1<=to_date('2018-08-31','yyyy-MM-dd')

oracle存储时间类型 date 和 timestamp区别

查询之后你会惊奇的发现,居然没有 08-31的数据,其实使用to_date,如果最小单位是日,那他的下区间其实是<=to_date('2018-08-31 00:00:00','yyyy-MM-dd HH24:mi:ss'),而上区间取得是>=to_date('2018-08-01 00:00:00','yyyy-MM-dd HH24:mi:ss'),那我统计某个月的访问数,下区间还要加上 23:59:59 999,或者多算一天,这那也太麻烦了,所以如果统计区间的单位最小是天 ,建议使用 to_char就可以解决这个问题

SELECT ID,to_char(d1,'yyyy-MM-dd HH24:mi:ss') FROM date_table 
WHERE 
to_char(d1,'yyyy-MM-dd') BETWEEN  '2018-08-01'
and '2018-08-31'

oracle存储时间类型 date 和 timestamp区别

四、下篇 在后端date 和 timestamp处理的区别

参考文章:https://blog.csdn.net/huaguoming/article/details/8693679

参考文章:http://tivan.iteye.com/blog/772431