1. 程式人生 > >MySQL中有關TIMESTAMP和DATETIME的總結

MySQL中有關TIMESTAMP和DATETIME的總結

轉載自iVictor,原文連結:http://www.cnblogs.com/ivictor/p/5028368.html

一、MySQL中如何表示當前時間?

其實,表達方式還是蠻多的,彙總如下:

CURRENT_TIMESTAMP

CURRENT_TIMESTAMP()

NOW()

LOCALTIME

LOCALTIME()

LOCALTIMESTAMP

LOCALTIMESTAMP()

二、關於TIMESTAMP和DATETIME的比較

一個完整的日期格式如下:YYYY-MM-DD HH:MM:SS[.fraction],它可分為兩部分:date部分和time部分,其中,date部分對應格式中的“YYYY-MM-DD”,time部分對應格式中的“HH:MM:SS[.fraction]”。對於date欄位來說,它只支援date部分,如果插入了time部分的內容,它會丟棄掉該部分的內容,並提示一個warning。

如下所示:

複製程式碼

複製程式碼

mysql> create table test(id int,hiredate date);
Query OK, 0 rows affected (0.01 sec)

mysql> insert into test values(1,'20151208000000');
Query OK, 1 row affected (0.00 sec)

mysql> insert into test values(1,'20151208104400');
Query OK, 1 row affected, 1 warning (0.01 sec)

mysql> show warning;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'warning' at line 1
mysql> select * from test;
+------+------------+
| id   | hiredate   |
+------+------------+
|    1 | 2015-12-08 |
|    1 | 2015-12-08 |
+------+------------+
2 rows in set (0.00 sec)

複製程式碼

複製程式碼

注:第一個沒提示warning的原因在於它的time部分都是0

TIMESTAMP和DATETIME的相同點:

1> 兩者都可用來表示YYYY-MM-DD HH:MM:SS[.fraction]型別的日期。

TIMESTAMP和DATETIME的不同點:

1> 兩者的儲存方式不一樣

對於TIMESTAMP,它把客戶端插入的時間從當前時區轉化為UTC(世界標準時間)進行儲存。查詢時,將其又轉化為客戶端當前時區進行返回。

而對於DATETIME,不做任何改變,基本上是原樣輸入和輸出。

下面,我們來驗證一下

首先建立兩種測試表,一個使用timestamp格式,一個使用datetime格式。

複製程式碼

複製程式碼

mysql> create table test(id int,hiredate timestamp);
Query OK, 0 rows affected (0.01 sec)

mysql> insert into test values(1,'20151208000000');
Query OK, 1 row affected (0.00 sec)

mysql> create table test1(id int,hiredate datetime);
Query OK, 0 rows affected (0.01 sec)

mysql> insert into test1 values(1,'20151208000000');
Query OK, 1 row affected (0.00 sec)

mysql> select * from test;
+------+---------------------+
| id   | hiredate            |
+------+---------------------+
|    1 | 2015-12-08 00:00:00 |
+------+---------------------+
1 row in set (0.01 sec)

mysql> select * from test1;
+------+---------------------+
| id   | hiredate            |
+------+---------------------+
|    1 | 2015-12-08 00:00:00 |
+------+---------------------+
1 row in set (0.00 sec)

複製程式碼

複製程式碼

兩者輸出是一樣的。

其次修改當前會話的時區

複製程式碼

複製程式碼

mysql> show variables like '%time_zone%'; 
+------------------+--------+
| Variable_name    | Value  |
+------------------+--------+
| system_time_zone | CST    |
| time_zone        | SYSTEM |
+------------------+--------+
2 rows in set (0.00 sec)

mysql> set time_zone='+0:00';
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test;
+------+---------------------+
| id   | hiredate            |
+------+---------------------+
|    1 | 2015-12-07 16:00:00 |
+------+---------------------+
1 row in set (0.00 sec)

mysql> select * from test1;
+------+---------------------+
| id   | hiredate            |
+------+---------------------+
|    1 | 2015-12-08 00:00:00 |
+------+---------------------+
1 row in set (0.01 sec)

複製程式碼

複製程式碼

上述“CST”指的是MySQL所在主機的系統時間,是中國標準時間的縮寫,China Standard Time UT+8:00

通過結果可以看出,test中返回的時間提前了8個小時,而test1中時間則不變。這充分驗證了兩者的區別。

2> 兩者所能儲存的時間範圍不一樣

timestamp所能儲存的時間範圍為:'1970-01-01 00:00:01.000000' 到 '2038-01-19 03:14:07.999999'。

datetime所能儲存的時間範圍為:'1000-01-01 00:00:00.000000' 到 '9999-12-31 23:59:59.999999'。

總結:TIMESTAMP和DATETIME除了儲存範圍和儲存方式不一樣,沒有太大區別。當然,對於跨時區的業務,TIMESTAMP更為合適。

三、關於TIMESTAMP和DATETIME的自動初始化和更新

首先,我們先看一下下面的操作

複製程式碼

複製程式碼

mysql> create table test(id int,hiredate timestamp);
Query OK, 0 rows affected (0.01 sec)

mysql> insert into test(id) values(1);
Query OK, 1 row affected (0.00 sec)

mysql> select * from test;
+------+---------------------+
| id   | hiredate            |
+------+---------------------+
|    1 | 2015-12-08 14:34:46 |
+------+---------------------+
1 row in set (0.00 sec)

mysql> show create table test\G
*************************** 1. row ***************************
       Table: test
Create Table: CREATE TABLE `test` (
  `id` int(11) DEFAULT NULL,
  `hiredate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

複製程式碼

複製程式碼

看起來是不是有點奇怪,我並沒有對hiredate欄位進行插入操作,它的值自動修改為當前值,而且在建立表的時候,我也並沒有定義“show create table test\G”結果中顯示的“ DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP”。

其實,這個特性是自動初始化和自動更新(Automatic Initialization and Updating)。

自動初始化指的是如果對該欄位(譬如上例中的hiredate欄位)沒有顯性賦值,則自動設定為當前系統時間。

自動更新指的是如果修改了其它欄位,則該欄位的值將自動更新為當前系統時間。

它與“explicit_defaults_for_timestamp”引數有關。

預設情況下,該引數的值為OFF,如下所示:

複製程式碼

複製程式碼

mysql> show variables like '%explicit_defaults_for_timestamp%';
+---------------------------------+-------+
| Variable_name                   | Value |
+---------------------------------+-------+
| explicit_defaults_for_timestamp | OFF   |
+---------------------------------+-------+
1 row in set (0.00 sec)

複製程式碼

複製程式碼

下面我們看看官檔的說明:

By default, the first TIMESTAMP column has both DEFAULT CURRENT_TIMESTAMP and ON UPDATE CURRENT_TIMESTAMP if neither is specified explicitly。

很多時候,這並不是我們想要的,如何禁用呢?

1. 將“explicit_defaults_for_timestamp”的值設定為ON。

2. “explicit_defaults_for_timestamp”的值依舊是OFF,也有兩種方法可以禁用

     1> 用DEFAULT子句該該列指定一個預設值

     2> 為該列指定NULL屬性。

如下所示:

複製程式碼

複製程式碼

mysql> create table test1(id int,hiredate timestamp null);
Query OK, 0 rows affected (0.01 sec)

mysql> show create table test1\G
*************************** 1. row ***************************
       Table: test1
Create Table: CREATE TABLE `test1` (
  `id` int(11) DEFAULT NULL,
  `hiredate` timestamp NULL DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

mysql> create table test2(id int,hiredate timestamp default 0);
Query OK, 0 rows affected (0.01 sec)

mysql> show create table test2\G
*************************** 1. row ***************************
       Table: test2
Create Table: CREATE TABLE `test2` (
  `id` int(11) DEFAULT NULL,
  `hiredate` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

複製程式碼

複製程式碼

在MySQL 5.6.5版本之前,Automatic Initialization and Updating只適用於TIMESTAMP,而且一張表中,最多允許一個TIMESTAMP欄位採用該特性。從MySQL 5.6.5開始,Automatic Initialization and Updating同時適用於TIMESTAMP和DATETIME,且不限制數量。

datetime 1. 佔用8個位元組 2. 允許為空值,可以自定義值,系統不會自動修改其值。 3. 實際格式儲存(Just stores what you have stored and retrieves the same thing which you have stored.) 4. 與時區無關(It has nothing to deal with the TIMEZONE and Conversion.) 5. 不可以設定預設值,所以在不允許為空值的情況下,必須手動指定datetime欄位的值才可以成功插入資料。 6. 可以在指定datetime欄位的值的時候使用now()變數來自動插入系統的當前時間。

結論:datetime型別適合用來記錄資料的原始的建立時間,因為無論你怎麼更改記錄中其他欄位的值,datetime欄位的值都不會改變,除非你手動更改它。

timestamp 1. 佔用4個位元組 2. 允許為空值,但是不可以自定義值,所以為空值時沒有任何意義。 3. TIMESTAMP值不能早於1970或晚於2037。這說明一個日期,例如'1968-01-01',雖然對於DATETIME或DATE值是有效的,但對於TIMESTAMP值卻無效,如果分配給這樣一個物件將被轉換為0。 4.值以UTC格式儲存( it stores the number of milliseconds) 5.時區轉化 ,儲存時對當前的時區進行轉換,檢索時再轉換回當前的時區。 6. 預設值為CURRENT_TIMESTAMP(),其實也就是當前的系統時間。 7. 資料庫會自動修改其值,所以在插入記錄時不需要指定timestamp欄位的名稱和timestamp欄位的值,你只需要在設計表的時候新增一個timestamp欄位即可,插入後該欄位的值會自動變為當前系統時間。 8. 以後任何時間修改表中的記錄時,對應記錄的timestamp值會自動被更新為當前的系統時間。 結論:timestamp型別適合用來記錄資料的最後修改時間,因為只要你更改了記錄中其他欄位的值,timestamp欄位的值都會被自動更新。