日期和時間函數對建立一個站點是非常有用的。站點的主人往往對一個表中的數據何時被更新感興趣。通過日期和時間函數,你可以在秒級跟蹤一個表的改變。
日期和時間類型是DATETIME、DATE、TIMESTAMP、TIME和YEAR。這些的每一個都有合法值的一個范圍,而“零”當你指定確實不合法的值時被使用。注意,MySQL允許你存儲某個“不嚴格地”合法的日期值,例如1999-11-31,原因我們認為它是應用程序的責任來處理日期檢查,而不是SQL服務器。為了使日期檢查更“快”,MySQL僅檢查月份在0-12的范圍,天在0-31的范圍。上述范圍這樣被定義是因為MySQL允許你在一個DATE或DATETIME列中存儲日期,這裡的天或月是零。這對存儲你不知道准確的日期的一個生日的應用程序來說是極其有用的,在這種情況下,你簡單地存儲日期象1999-00-00或1999-01-00。(當然你不能期望從函數如DATE_SUB()或DATE_ADD()得到類似以這些日期的正確值)。
返回當前日期和時間
通過函數GETDATE(),你可以獲得當前的日期和時間。例如,
CURDATE() 返回當前日期
CURRENT_DATE
以'YYYY-MM-DD'或YYYYMMDD格式返回今天日期值,取決於函數是在一個字符串還是數字上下文被使用。
MySQL> select CURDATE();
+------------+
| CURDATE() |
+------------+
| 2001-02-20 |
+------------+
MySQL> select CURDATE() + 0;
+-------------+
| CURDATE()+0 |
+-------------+
| 20010220 |
+-------------+
CURTIME() 返回當前時間
以'HH:MM:SS'或HHMMSS格式返回當前時間值,取決於函數是在一個字符串還是在數字的上下文被使用。
MySQL> select CURTIME();
+-----------+
| CURTIME() |
+-----------+
| 10:42:38 |
+-----------+
MySQL> select CURTIME() + 0;
+-------------+
| CURTIME()+0 |
+-------------+
| 104525 |
+-------------+
NOW() 返回當前時期和時間
NOW()以YYYY-MM-DD HH:MM:SS的格式或者YYYYMMDDHHMMSS的格式返回日期和時間值,取決於上下文。
MySQL>select now();
+---------------------+
| now() |
+---------------------+
| 2001-02-20 10:45:57 |
+---------------------+
MySQL>select now()+0;
+----------------+
| now()+0 |
+----------------+
| 20010220105635 |
+----------------+
這些得到當前日期和時間的函數,對於日期和時間的計算很方便,尤其是計算一個時間到現在的時間差。例如,在pet表中,我們以天為單位計算寵物的年齡:
MySQL> SELECT name,CURDATE()-birth FROM pet;
+----------+-----------------+
| name | CURDATE()-birth |
+----------+-----------------+
| Fluffy | 80016 |
| Claws | 69903 |
| Buffy | 119707 |
| Chirpy | 29309 |
| Fang | 109393 |
| Bowser | 109389 |
| Whistler | 39011 |
| Slim | 49791 |
| Puffball | 19890 |
+----------+-----------------+
自動記錄數據的改變時間
TIMESTAMP列類型提供一種類型,TIMESTAMP值可以從1970的某時的開始一直到2037年,精度為一秒,其值作為數字顯示。你可以使用它自動地用當前的日期和時間標記INSERT或UPDATE的操作。如果你有多個TIMESTAMP列,只有第一個自動更新。
自動更新第一個TIMESTAMP列在下列任何條件下發生:
列沒有明確地在一個INSERT或LOAD DATA INFILE語句中指定。
列沒有明確地在一個UPDATE語句中指定且一些另外的列改變值。(注意一個UPDATE設置一個列為它已經有的值,這將不引起TIMESTAMP列被更新,因為如果你設置一個列為它當前的值,MySQL為了效率而忽略更改。)
你明確地設定TIMESTAMP列為NULL.
除第一個以外的TIMESTAMP列也可以設置到當前的日期和時間,只要將列設為NULL,或NOW()。
例如,創建如下的表:
MySQL> CREATE TABLE student
-> (
-> id int,
-> name char(16),
-> english tinyint,
-> chinese tinyint,
-> history tinyint,
-> time timestamp
-> );
向表中插入記錄,可以查看效果:
MySQL> INSERT student(id,name,englisht,Chinese,history) VALUES(11,”Tom”,66,93,67);
查看記錄的存儲情況:
MySQL> SELECT * FROM student;
+------+---------+---------+---------+---------+----------------+
| id | name | english | chinese | history | time |
+------+---------+---------+---------+---------+----------------+
| 11 | Tom | 66 | 93 | 67 | 20010220123335 |
+------+---------+---------+---------+---------+----------------+
你可以看到time列紀錄下了數據錄入時的時間值。如果你更新改記錄,在查看操作的結果:
MySQL> UPDATE student SET english=76 WHERE id=11;
MySQL> SELECT * FROM student;
+------+------+---------+---------+---------+----------------+
| id | name | english | chinese | history | time |
+------+------+---------+---------+---------+----------------+
| 11 | Tom | 76 | 93 | 67 | 20010220125736 |
+------+------+---------+---------+---------+----------------+
可以清楚的看到,time列的時間被自動更改為修改記錄的時間。
有時候你希望不更改任何值,也能打到修改TIMESTAMP列的值,這時只要設置該列的值為NULL,MySQL就可以自動更新TIMESTAMP列的值:
MySQL> UPDATE student SET time=NULL WHERE id=11;
MySQL> select * from student where id=11;
+------+------+---------+---------+---------+----------------+
| id | name | english | chinese | history | time |
+------+------+---------+---------+---------+----------------+
| 11 | Tom | 76 | 93 | 67 | 20010220130517 |
+------+------+---------+---------+---------+----------------+
通過明確地設置希望的值,你可以設置任何TIMESTAMP列為不同於當前日期和時間的值,即使對第一個TIMESTAMP列也是這樣。例如,如果,當你創建一個行時,你想要一個TIMESTAMP被設置到當前的日期和時間,但在以後無論何時行被更新時都不改變,你可以使用這樣使用:
讓MySQL在行被創建時設置列,這將初始化它為當前的日期和時間。
當你執行隨後的對該行中其他列的更改時,明確設定TIMESTAMP列為它的當前值。
例如,當你在修改列時,可以把原有的值付給TIMESTAMP列:
MySQL> UPDATE student SET english=66,time=time WHERE id=11;
MySQL> select * from student where id=11;
+------+------+---------+---------+---------+----------------+
| id | name | english | chinese | history | time |
+------+------+---------+---------+---------+----------------+
| 11 | Tom | 66 | 93 | 67 | 20010220130517 |
+------+------+---------+---------+---------+----------------+
另一方面,你可能發現,當你想要實現上面這個效果時,很容易用一個你用NOW()初始化的DATETIME列然後不再改變它,這樣也許直接些。 但是,TIMESTAMP列的以後好處是存儲要求比較小,節省空間。TIMESTAMP的存儲需求是4字節,而DATETIME列的存儲需求是8字節。
返回日期和時間范圍
當你分析表中的數據時,你也許希望取出某個特定時間的數據。我們用下面一個表來模仿一個web站點的記錄。
MySQL> CREATE TABLE weblog
-> (
-> data float,
-> entrydate datetime
-> );
然後隨機的增加幾個數據:
MySQL> INSERT weblog VALUES(rand(),now());
rand()函數返回一個隨機的浮點值,now()函數返回當前時間。多執行上面語句幾次,得到一個作為測試的表。
最為測試你還可以增加一個值:
MySQL> INSERT weblog VALUES(rand(),”2001-02-08”);
這條語句,插入一個entry為”2001-02-08 00:00:00”的值(假定現在為2001年2月8日),你可以查看這個表的值:
MySQL> select * from weblog;
+-----------+---------------------+
| data | entrydate |
+-----------+---------------------+
| 0.973723 | 2001-02-08 00:00:00 |
| 0.437768 | 2001-02-08 13:57:06 |
| 0.327279 | 2001-02-08 13:57:09 |
| 0.0931809 | 2001-02-08 13:58:29 |
| 0.198805 | 2001-02-08 13:57:54 |
+-----------+---------------------+
你也許對特定的某一天中――比如說2001年2月18日――訪問者在你站點上的活動感興趣。要取出這種類型的數據,你也許會試圖使用這樣的SELECT語句:
MySQL> SELECT * FROM weblog WHERE entrydate="2001-02-08"
不要這樣做。這個SELECT語句不會返回正確的記錄――它將只返回值為2000-02-08 00:00:00的記錄,換句話說,只返回當天零點零時的記錄。上面語句的結果為:
+----------+---------------------+
| data | entrydate |
+----------+---------------------+
| 0.973723 | 2001-02-08 00:00:00 |
+----------+---------------------+
要返回正確的記錄,你需要適用日期和時間范圍。有不止一種途徑可以做到這一點。
1、使用關系運算符和邏輯運算符來限制時間范圍
例如,下面的這個SELECT 語句將能返回正確的記錄:
MySQL> SELECT * FROM weblog
-> WHERE entrydate>="2001-02-08" AND entrydate<"2001-02-09" ;
這個語句可以完成任務,因為它選取的是表中的日期和時間大於等於2001-02-08 00:00:00並小於2001-02-09 00:00:00的記錄。換句話說,它將正確地返回2000年2月8日這一天輸入的每一條記錄。 其結果為:
+-----------+---------------------+
| data | entrydate |
+-----------+---------------------+
| 0.973723 | 2001-02-08 00:00:00 |
| 0.437768 | 2001-02-08 13:57:06 |
| 0.327279 | 2001-02-08 13:57:09 |
| 0.0931809 | 2001-02-08 13:58:29 |
| 0.198805 | 2001-02-08 13:57:54 |
+-----------+---------------------+
2、另一種方法是,你可以使用LIKE來返回正確的記錄。通過在日期表達式中包含通配符“%”,你可以匹配一個特定日期的所有時間。
這裡有一個例子:
MySQL> SELECT * FROM weblog WHERE entrydate LIKE '2001-02-08%' ;
這個語句可以匹配正確的記錄。因為通配符“%”代表了任何時間。
+-----------+---------------------+
| data | entrydate |
+-----------+---------------------+
| 0.973723 | 2001-02-08 00:00:00 |
| 0.437768 | 2001-02-08 13:57:06 |
| 0.327279 | 2001-02-08 13:57:09 |
| 0.0931809 | 2001-02-08 13:58:29 |
| 0.198805 | 2001-02-08 13:57:54 |
+-----------+---------------------+
3、上面兩種方法的異同
由於使用關系運算符進行的是比較過程,時轉換成內部的存儲格式後進行的,因此,因此時間的書寫可以不是那麼嚴格要求。
例如,下面幾種寫法是等價的:
MySQL> SELECT * FROM weblog WHERE entrydate>="2001-02-08";
MySQL> SELECT * FROM weblog WHERE entrydate>="2001-2-8";
MySQL> SELECT * FROM weblog WHERE entrydate>="2001*02*08";
MySQL> SELECT * FROM weblog WHERE entrydate>="20010208";
SELECT * FROM weblog WHERE entrydate>="2001/2/8";
而使用LIKE運算符和模式匹配,是通過比較串值進行的,因此必須使用標准的時間書寫格式,YYYY-MM-DD HH-MM-SS。
比較日期和時間
已知兩個日期,比較它們的前後,可以直接求出它們的差和零值比較,也可以利用已知的時間函數:
TO_DAYS(date)
給出一個日期date,返回一個天數(從0年的天數),date可以是一個數字,也可以是一個串值,當然更可以是包含日期的時間類型。
MySQL> select TO_DAYS(960501);
+-----------------+
| TO_DAYS(960501) |
+-----------------+
| 729145 |
+-----------------+
MySQL> select TO_DAYS('1997-07-01');
+-----------------------+
| TO_DAYS('1997-07-01') |
+-----------------------+
| 729571 |
+-----------------------+
例如:返回2個時間相差的天數(21世紀已經過去了多少天)
MySQL> select to_days(now())-to_days('20010101');
+---------------------------------------------------+
| to_days(now()-00000012000000)-to_days('20010101') |
+---------------------------------------------------+
| 38 |
+---------------------------------------------------+