DATE、DATETIME 和 TIMESTAMP的區別

在我十年的 IT 生涯中,好像幾乎沒有使用過 MySQL 的 date 、datetime 和 timestamp 幾種數據類型。

究其原因,有兩個:一是傻傻的分不清 DATEDATETIME 和 TIMESTAMP 三種數據類型,記不住它們的格式;二是,它們或多或少和時區相關,爲了存儲時區無關數據,我一般都使用 int(11) 存儲時間戳格式

今天就稱這個機會,我們一起來熟悉下這三種數據類型

DATE、DATETIME 和 TIMESTAMP 的格式

首先要說明的是,這三種數據類型是息息相關的,它們有很多相似之處,也有各自的特徵,因爲這些特徵,才導致了彼此的不同。

其次,MySQL 可以識別多種格式的 datedatetime 和 timestamp ,具體支持的格式有

  1. 對於 date 類型,支持 YYYY-MM-DD 或 YY-MM-DD 以及它們各自的變形

說到變形,就是指中劃線 ( - ) 可以替換爲任意字符,除了數字 0-9 ,比如

格式 範例
YYYY-MM-DD 2018-09-13
YY-MM-DD 18-09-13
YYYY/MM/DD 2018/09/13
YY/MM/DD 18/09/13
YYYY^MM^DD 2018^09^13
YY^MM^DD 18^09^13
YYYY@MM@DD 2018@09@13
YY@MM@DD 18@09@13

同時還支持 YYYYMMDD 和 YYMMDD 的字符串形式,例如 '20180913' 和 '180913'

還支持 YYYYMMMDD 和 YYMMDD 的數字格式,例如 20180913 和 180913

  1. 對於 datetime 和 timestamp 類型,支持 YYYY-MM-DD HH:MM:SS 或 YY-MM-DD HH:MM:SS,一起它們的變形

這個變形其實和 DATE 一樣,而且就是指中劃線 ( - ) 可以替換爲任意字符,除了數字 0-9 。

更進一步,這兩個類型可以針對日期部分和時間部分使用不同的分隔符

格式 範例
YYYY-MM-DD HH:MM:SS 2018-09-13 21:15:10
YY-MM-DD HH:MM:SS 18-09-13 21:15:10
YYYYY^MM^DD HH+MM+SS 2018^09^13 21+15+10
YY^MM^DD HH+MM+SS 18^09^13 21+15+10
YYYY^MM^DD 2018^09^13
YY^MM^DD 18^09^13
YYYY@MM@DD HH^MM^SS 2018@09@13 21^15^10
YY@MM@DD HH^MM^SS 18@09@13 21^15^10

這種格式下也有幾個點要注意

  1. 日期和時間部分與小數秒部分之間的唯一可用的分隔符號是小數點 ( . ) 例如 2018-09-13 21:15:10.11
  2. 日期與時間部分的分隔符不一定就要使用空格 ( ' ' ),還可以使用字符 T ,例如 2018-09-13 21:15:10 和 2018-09-13T21:15:10 是等價的

同時還可以使用沒有任何分隔符的形式,比如 YYYYMMDDHHMMSS 或 YYMMDDHHMMSS,例如 '20180913211510' 與 2018-09-13 21:15:10 是等價的

但 071122129015 則是非法的,並不是因爲年份缺少了,而是因爲分鐘太大 ( 90 ),然後會被視爲 0000-00-00 00:00:00

因爲 MySQL 同時支持超大整數類型,所以,數字形式的 YYYYMMDDHHMMSS 或 YYMMDDHHMMSS 也是被支持的,例如 20180913211510 和 180913211510 被認爲與 2018-09-13 21:15:10 是等價的

DATE、DATETIME 和 TIMESTAMP 的特徵

從上面的格式中可以看出,date 類型就是隻有 年月日 沒有 時分秒,MySQL 以 YYYY-MM-DD 格式檢索並顯示 date 類型的值。支持的範圍是 1000-01-01 到 9999-12-31

datetime 類型通常包含完整的日期時間,也就是能夠完整的表達某一個時刻。MySQL 以 YYYY-MM-DD HH:MM:SS 格式檢索並顯示 datetime 類型的值,支持的範圍是 1000-01-01 00:00:00 到 9999-12-31 23:59:59

和 datetime 類型一樣,timestamp 類型通常也包含完整的日期時間,也能夠完整的表達某一個時刻。MySQL 也以 YYYY-MM-DD HH:MM:SS 格式檢索並顯示 timestamp 類型的值,但是,timestamp 支持的範圍是不同的,只能是1970-01-01 00:00:00 UTC 到 2038-12-31 23:59:59 UTC

也就是說,支持的格式和顯示上,datetime 和 timestamp 並沒有什麼不同,但在支持的範圍上是有不同的

DATETIME 和 TIMESTAMP 的小數部分

datetime 和 timestamp 兩種時間類型還可以精確到 微秒 ,具體的形式就是支持在  後面使用 6 位精度的小數來支持,例如 2018-09-13 21:15:10.111111

而且,插入 datetime 或 timestamp 列的值中的任何小數部分都將被存儲而不是被丟棄。

當包含小數部分時,datetime 和 timstamp 兩個日期時間類型的格式爲 YYYY-MM-DD HH:MM:SS [.fraction],datetime 值的範圍爲 1000-01-01 00:00:00.000000 至 9999 -12-31 23:59:59.999999 而 timestamp 類型的範圍則爲 1970-01-01 00:00:01.000000 到 2038-01-19 03:14:07.999999

注意: 小數部分與其它部分的唯一的分隔符只能是小數點 ( . ),且沒有任何其它可替代的字符。

DATETIME 和 TIMESTAMP 支持自動賦值

MySQL 還爲 datetime 和 timestamp 兩種日期時間類型提供了自動賦值功能。也就是在 MySQL INSERT 時可以自動初始化爲當前日期時間,在 MySQL Update 時自動更新爲當前時間。

而具體的做法,就是創建表結構時爲這兩種日期時間類型添加以下約束:

CREATE TABLE t1 (
 ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
 dt DATETIME  DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
  1. DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP 指示在 insert 操作時自動插入當前日期時間
  2. DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP 指示在 update 操作時自動更新爲當前日期時間

DATETIME 和 TIMESTAMP 的時區問題

datetime 和 timestamp 兩種類型的另一個區別,就是它們對待 時區 有所不同

  1. timestamp 會將值的時區從當前時區轉換爲 UTC 然後存儲,並在需要顯示和檢索時從 UTC 轉換回當前時區
  2. 但對於 datetime 類型,什麼都不會發生,值是什麼時區,存儲的就是什麼時區

默認情況下,timestamp 和 datetime 都會將當前連接的 MySQL 服務器的時區當作當前時區,當然了,這個時區是可配置的,而且可以針對每個連接單獨配置。

從某些方面說,在數據轉移或者在不同地方顯示時,只要設置了一樣的時區,那麼數據就是一致的,否額

  1. datetime 的值雖然存儲和顯示的時候都是同一個值,但可能不是我們想要的,因爲時區錯了
  2. timestamp 雖然可以保證時間是正常的,但存儲的值和顯示的值可能會不一樣,可能會導致我們錯覺發生

PS 就是因爲這個原因,導致了我不敢輕易使用 DATETIME 數據類型,連帶 timestamp 也不敢使用

DATE、DATETIME 和 TIMESTAMP 的注意事項

  1. 對於這三種日期時間類型,無效的值將會轉換爲相應的  值,也就是,date 類型會轉換爲 0000-00-00 ,datetime 類型會轉換爲 0000-00-00 00:00:00 ,而 timestamp 則會轉換爲 1970-01-01 00:00:00

  2. 雖然 MySQL 支持爲指定爲字符串的值使用 寬鬆 格式,其中任何標點字符都可以用作日期部分或時間部分之間的分隔符,但是,在某些情況下,這種語法可能是欺騙性的。

例如,10:11:12 之類的值可能看起來像時間值,因爲它們的分隔符是 : ,但它也可以表示爲一個日期 2010-11-12

還有,年月日時分秒中的任何一部分只要非法,那麼整個值就會 歸零,例如 date 類型的值如果爲 10:45:15 那麼就會被轉換爲 0000-00-00,因爲 45 不是有效月份值

  1. 上面也提到了,就是日期和時間部分與小數秒部分之間識別的唯一分隔符是小數點

  2. MySQL 服務器會真實的判斷一個日期是否有效,而不僅僅是判斷月份和日期是否分別在 1 到 12 和 1 到 31 的範圍內。

在嚴格模式下 ( sql_mode=TRADITIONAL ) 無效的月份和日期 ( 例如 '2004-04-31' )直接會導致一個錯誤發生,

即使在禁用嚴格模式後,'2004-04-31' 等無效日期也會被轉換爲 '0000-00-00' 且生成一個警告

  1. 對於 timestamp 類型,MySQL 並不支持月份和日期中的 0 值,也就是沒有什麼 00 月和 00 日,這些都不是有效的值,會直接導致整體的值被轉換爲 1970-01-01 00:00:00

  2. 對於 datetime 和 timestamp 類型,兩位數的年是不確定的日期,因爲不知道是屬於哪個世紀。

對於兩位數的年份,MySQL 使用下面這些規則解釋

  1. 00-69 範圍內的年份值將轉換爲 2000-2069
  2. 70-99 範圍內的年份值轉換爲 1970-1999
發佈了160 篇原創文章 · 獲贊 179 · 訪問量 28萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章