1 MySQL 數據庫中有五種與日期時間有關的數據類型,各種日期數據類型所占空間如下圖所示:
2 datetime 與 date
datetime 占用8字節,是占用空間最多的一種日期格式。它顯示日期,同時也顯示時間。5.5及以前的版本不支持微妙級別,任何微妙數值都會被截斷之后存入數據庫。
date 占用3字節,僅僅顯示日期。
3 timestamp
timestamp 與 datetime 顯示的結果是一樣的,不同的是timestamp 占用4個字節。它的顯示范圍是:1970-01-01 00:00:01 至 2038-01-19 01:14:07(UTC),UTC 協調世界時間,世界統一時間。
timestamp 與 datetime顯示的格式一樣,但是顯示的范圍不同,還有以下一些區別
- 建表時, 列為timestamp的類型可以設置一個默認值,datetime 不行。
- 更新表時,可以設置timestamp 類型的列自動更新時間為當前時間。
4 year 與 time
year 類型占用1字節,在定義時可以顯示指定寬度為year(4)或者year(2)。對於year(4),其顯示的年份范圍為 1901 ~ 2155;對於year(2),其顯示的年份范圍為:1970~2070。
在year(2)的設置下,00~69 代表 2000~2069。
time 類型占用3字節,顯示的范圍 -838:59:59 ~ 838:59:59。time 類型時間大於23或者為負數時用來表示時間間隔。
5 時間與日期函數
5.1 系統時間函數 now(), current_timestamp, sysdate()
這三個函數都能返回系統時間,看看它們的區別,同時訪問這三個函數得到的結果一樣,但是讓其等待幾秒之后,結果就不同了。
上圖發現sysdate()返回的時間與now(), current_timestamp不同,慢了2秒,原因如下:
current_timestamp 是now的同義詞,兩者實際上是一樣的;
sysdate() 函數返回的是執行到當前函數時的時間,而now()返回的是執行sql語句時的時間;
5.2 時間加減函數
① date_add 與 date_sub
date_add(date, interval expr unit) 與 date_sub(date, interval expr unit) 分別表示增加與減少。
select
date_add('2017-12-18 22:51:00', interval 1 second),
date_add('2017-12-18 22:51:00', interval 1 minute),
date_add('2017-12-18 22:51:00', interval 1 hour),
date_add('2017-12-18 22:51:00', interval 1 day),
date_add('2017-12-18 22:51:00', interval 1 month),
date_add('2017-12-18 22:51:00', interval 1 year);
遇到閏月時,date_add怎么處理呢,MySQL如果是閏月返回的日期為2月29,如果不是閏月返回的是2月28。
select date_add('2016-02-29 22:51:00', interval -1 year),
date_add('2016-02-29 22:51:00', interval 4 year);
2015-02-28 22:51:00 2020-02-29 22:51:00
② datediff 與 timediff
datediff(date1,date2):兩個日期相減 date1 - date2,返回天數。select datediff('2016-02-29 22:51:00','2016-03-29 22:51:00');
timediff(time1,time2):兩個日期相減 time1 - time2,返回 time 差值(格式為:838:59:59)。select timediff('2016-02-29 22:51:00','2016-01-29 22:51:00');
注意:timediff(time1,time2) 函數的兩個參數類型必須相同。
③ timestamp 增,減,轉換函數
timestamp(date) -- date to timestamp
timestamp(date, time) -- date + time
timestampadd(unit,interval,datetime_expr) -- 類似date_add,對時間按單位進行增加,減少
select timestampadd(second, 60, '2017-12-18 00:00:00');
select timestampadd(minute, 60, '2017-12-18 00:00:00');
select timestampadd(hour, 60, '2017-12-18 00:00:00');
timestampdiff(unit,datetime_expr1,datetime_expr2) --計算兩個時間的差,可以計算秒,分,時,天,月,年,周
select timestampdiff(second, '2017-12-18 00:00:00','2017-12-18 12:00:00');
select timestampdiff(hour, '2017-11-18 00:00:00','2017-12-18 12:00:00');
select timestampdiff(day, '2017-10-17 00:00:00','2017-11-18 23:00:00');
④ date_format 函數
date_format 函數主要用途是格式化日期
select date_format(now(),'%Y%m%d'),
date_format(now(),'%Y-%m-%d'),
date_format(now(),'%Y/%m/%d'),
date_format(now(),'%m/%d/%Y');
注意:查詢數據時如果對某個日期字段使用這個函數,則優化器不會使用字段的索引,也不能通過索引來查詢數據,因此查詢效率會很低,如下列查詢語句,如果字段birth_date有索引,則該索引因為使用了date_format函數失效:
select *
from employees
where date_format(birth_date,'%Y-%m-%d') = '1961-08-03';
6 日期的經典編程問題
根據某個用戶的出生日期與當前日期,計算他最近的生日(包括已經過去的和將來的)
-- 上一年,當年,下一年生日與當前時間差最小的年就是用戶最近的生日
select emp_no,first_name,last_name,birth_date,today,if(last_diff<=cur_diff and last_diff<=next_diff, last,if(cur_diff<last_diff and cur_diff<next_diff, cur, next) ) as latest_birth
from
(
-- 計算當前時間與上一年,當年,下一年生日的時間差
select emp_no,first_name,last_name,birth_date,datediff(today,last) as last_diff,abs(datediff(today,cur)) as cur_diff,abs(datediff(today,next)) as next_diff,
last,cur,next,today
from
(
-- 用戶最近的生日可能分布在前一年,當年,下一年。根據年度差year_diff計算上一年,當年,下一年用戶的生日
select emp_no,first_name,last_name,birth_date,
DATE_ADD(birth_date,INTERVAL year_diff year) as cur,
DATE_ADD(birth_date,INTERVAL year_diff+1 year) as next,
DATE_ADD(birth_date,INTERVAL year_diff-1 year) as last,
today
from
(
-- 獲取當前事前與出生日期的年度差 year_diff
select emp_no,first_name,last_name,birth_date,(year(NOW())-year(birth_date)) as year_diff, NOW() as today
from employees
) a
) b
) c