datetime和timestamp--時間戳是絕對值,日期是相對值

遇到的問題:系統時間與數據庫時間不一致,系統時間是8:20,存到數據庫裏是0:20。mysql

 

第一直覺是時區不一樣致使的。sql

 

先看一段代碼:數據庫

 

 

Java代碼  
  1. public static void main(String[] args) {  
  2.     //System.out.println(TimeZone.getDefault());  
  3.       
  4.     SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
  5.     Calendar c = Calendar.getInstance();  
  6.     //System.out.println(c.getTime());  
  7.     System.out.println(sdf.format(c.getTime()));  
  8.     System.out.println(c.getTimeInMillis());  
  9.       
  10.     TimeZone.setDefault(TimeZone.getTimeZone("GMT+5:00"));  
  11.     sdf.setTimeZone(TimeZone.getDefault());  
  12.       
  13.     //System.out.println(c.getTime());  
  14.     //System.out.println(c.getTime().getTimezoneOffset());  
  15.     System.out.println(sdf.format(c.getTime()));  
  16.     System.out.println(c.getTimeInMillis());  
  17. }  

 

 

 

 

輸出結果:併發

2011-11-25 10:33:21oracle

1322188401796高併發

2011-11-25 07:33:21sqlserver

1322188401796性能

 

這說明,時間的顯示是由時區決定的,時間所表示的距標準時間毫秒數是絕對的,不會隨時區不一樣而改變。理解這一點很重要。測試

 

那麼數據庫裏的時間也應該有個時區概念,那究竟是如何處理的呢?一直這麼認爲的,時間在數據庫裏實際存的是毫秒數。那咱們在客戶端看到的時間必定是通過數據庫格式化之後的。spa

但結果不徹底是這樣的,下面咱們要討論數據庫中的兩個時間類型 datetime 和 timestamp 。

 

網上有文稱

datetime - 存儲日期和時間部分,精確到秒,沒有時區信息

timestamp - 時間戳,存儲日期、時間和時區信息,秒值精確到小數點後6位

注意這裏的時間戳,在sqlserver中根本就不是時間,他只記錄相對時間的前後,不記錄具體時間。我認爲應該叫作數據版本號。

 

首先在sqlserver中測試:

 

select getdate()

 

執行結果跟想像的同樣,操做系統的時區如何修改,他都能隨之變化,他確定得到了系統的時區信息,而後對當前毫秒數格式化。

 

把系統時區恢復到GMT+8:00,建立一個測試表,並插入兩條數據

create table TEST_TIMEZONE(

  tid int,

  time1 datetime ,

  time2 datetime

);

 

insert into TEST_TIMEZONE values(1,getdate(),getdate());

insert into TEST_TIMEZONE values(2,getdate(),getdate());

 

select * from TEST_TIMEZONE;

 

這時數據庫查詢結果爲

1     2011-11-25 10:47:23.750       2011-11-25 10:47:23.750

2     2011-11-25 10:47:27.513       2011-11-25 10:47:27.513

 

如今修改系統時區爲GMT+5:00,再插入兩條數據,並修改第一條數據

 

insert into TEST_TIMEZONE values(3,getdate(),getdate());

insert into TEST_TIMEZONE values(4,getdate(),getdate());

 

update TEST_TIMEZONE set time1=getdate() where tid=1;

 

select * from TEST_TIMEZONE;

 

這時數據庫查詢結果爲

1     2011-11-25 07:50:20.373       2011-11-25 10:47:23.750

2     2011-11-25 10:47:27.513       2011-11-25 10:47:27.513

3     2011-11-25 07:50:15.920       2011-11-25 07:50:15.920

4     2011-11-25 07:50:18.500       2011-11-25 07:50:18.500

 

由於datetime沒有時區信息,只有年月日時分秒,因此保存的是幾點就是幾點,兩次操做差了3個小時。

 

select t.*,t.time2-t.time1 from TEST_TIMEZONE t where t.tid=1

 

 

咱們再看時間戳類型,sqlserver一個表只能有一個時間戳列,並且時間戳列不用操做,在數據行插入或更新時自動更新。

新建測試表

create table TEST_TIMEZONE2(

  tid int,

  time1 timestamp

);

 

insert into TEST_TIMEZONE2(tid) values(1);

insert into TEST_TIMEZONE2(tid) values(2);

insert into TEST_TIMEZONE2(tid) values(3);

 

 

select * from TEST_TIMEZONE2;

 

查詢結果:

1     0x000000000000200A

2     0x000000000000200B

3     0x000000000000200C

 

update TEST_TIMEZONE2 set tid=4 where tid=3;

 

select * from TEST_TIMEZONE2;

 

查詢結果:

1     0x000000000000200A

2     0x000000000000200B

4     0x000000000000200E

 

這個時間戳主要用在處理併發問題上,作爲數據是否已被修改的憑證,能夠提升併發性能。 再次明確sqlserver的時間戳不是具體時間。

 

恢復一下時區到GMT+8:00,都不知道如今幾點了。

 

 

 

接下來,在mysql作個測試:

 

select now()

 

修改系統時區對查詢結果沒有影響,這與sqlserver不一樣。修改時區後,重啓mysql,再執行有效果了。說明mysql在啓動時記錄了系統時區,而不是實時的讀取系統時區。

 

恢復時區到GMT+8:00,新建 表

create table TEST_TIMEZONE(

  tid int,

  time1 datetime ,

  time2 timestamp ,

  time3 timestamp

);

插入數據

insert into TEST_TIMEZONE(tid) values(1);

insert into TEST_TIMEZONE(tid) values(2);

insert into TEST_TIMEZONE values(3,now(),now(),now());

insert into TEST_TIMEZONE values(4,now(),now(),now());

 

select * from TEST_TIMEZONE

查詢結果

  

 

Mysql容許多個timestamp列,但只有第一列會自動更新,默認值 爲

CURRENT_TIMESTAMP。

 

恢復時區到GMT+5:00,重啓動mysql,執行查詢



  

結果說明datetime的時間不隨系統時區而變化,timestamp會隨系統時區變化而變化,也sqlserver徹底不一樣。Mysql在timestamp字段記錄的是毫秒數,而且按初始的系統時區格式化後顯示。

 

另外對oracle如今沒有測試環境。

 

結論:

Datatime類型只保存年月日時分秒信息,不含時區。

Timestamp時間戳,不一樣數據庫有不一樣的實現,不要用作業務列,更不能做爲索引或鍵使用,他會自動被更新。

相關文章
相關標籤/搜索