MySql 時間類型 & JDBC時間類型
MySql時間類型:DATETIME & TIMESTAMP
長度
- DATETIME類型包含DATE和TIME,範圍1000-01-01 00:00:00 ~ 9999-12-31 23:59:59。DATETIME還能包含毫秒,例如2018-03-11 14::13:22.999
- TIMESTAMP也能存儲日期和時間,但是範圍只有1970-01-01 00:00:01 UTC ~ 2038-01-19 03:14:07 UTC
時區
DATETIME存儲的時間不包含時區
TIMESTAMP存儲的UTC時間
例如:
create table
CREATE TABLE timestamp_n_datetime ( id INT AUTO_INCREMENT PRIMARY KEY, ts TIMESTAMP, dt DATETIME );
insert now(當前時區為+08)
insert into timestamp_n_datetime(ts,dt) values (now(), now());
select
MariaDB [test]> select * from timestamp_n_datetime; +----+---------------------+---------------------+ | id | ts | dt | +----+---------------------+---------------------+ | 1 | 2018-03-11 14:35:01 | 2018-03-11 14:35:01 | +----+---------------------+---------------------+ 1 row in set (0.00 sec)
修改時區
MariaDB [test]> set time_zone = ‘+00:00‘; Query OK, 0 rows affected (0.02 sec)
再次查詢
MariaDB [test]> select * from timestamp_n_datetime -> ; +----+---------------------+---------------------+ | id | ts | dt | +----+---------------------+---------------------+ | 1 | 2018-03-11 06:35:01 | 2018-03-11 14:35:01 | +----+---------------------+---------------------+ 1 row in set (0.00 sec)
TIMESTAMP存儲的時間調整到了新時區,而DATETIME存儲的時間不變。剛接觸java的時候寫代碼的就出現過時區問題,mybatis mysql,表字段類型為DATETIME,java類型為java.util.Date。通過查看java connector源碼com.mysql.cj.mysqla.MysqlaSession.java的configureTimezone方法,
this.getServerVariable("system_time_zone")
調試這裏發現從系統裏面讀出來的時區設置是CST。於是去查找數據庫服務器的原因
MariaDB [(none)]> show variables like ‘%time_zone%‘; +------------------+--------+ | Variable_name | Value | +------------------+--------+ | system_time_zone | CST | | time_zone | SYSTEM | +------------------+--------+ 2 rows in set (0.01 sec)
解決方法:
修改配置文件 /etc/my.cnf.d/server.cnf (centos 7),需要重啟mysql
# this is only for the mysqld standalone daemon [mysqld] default-time-zone=‘+08:00‘ # 將這行加到mysqld節點下
修改數據庫服務變量(未驗證,如果不方便修改配置文件或重啟數據庫。重啟數據庫之後失效??)
set time_zone=‘+08:00‘; set global time_zone=‘+08:00‘; flush privileges;
如果是直接使用jdbc而不是mybatis,則通過
java.util.Date now = new java.util.Date(); java.sql.Timestamp sqlTimestamp = new java.sql.Timestamp(now.getTime()); PreparedStatement.setTimestamp(1, sqlTimestamp, Calendar.getInstance(Locale.CHINA));
即指定第三個參數。如果沒有指定第三個參數,則又使用了CST時間(setTimestamp源碼中)
JDBC表示時間的類型
這一節的資料有點老(https://www.cis.upenn.edu/~bcpierce/courses/629/jdkdocs/guide/jdbc/getstart/mapping.doc.html)
這三種類型都繼承自java.util.Date,因為java.util.Date沒法匹配三種JDBC時間類型。
DATE表示只包含了年月日的時間類型 java.sql.Date for SQL DATE(這裏的SQL說的是SQL-92標準)。 父類的hour, minute, second, millisecond字段被設置為0。
TIME表示只包含了時分秒的時間類型 java.sql.Time for SQL TIME information. 父類的year, month, day字段被設置為1970, 1月, 1號. 這個時間是java裏面的“零紀元”
TIMESTAMP包含了DATE+TIME再加上一個納秒(nanosecond)字段 java.sql.Timestamp for SQL TIMESTAMP information. 這個類型為java.util.Date擴展了額外的nanosecond字段。
其他命令
get current time_zoneSELECT @@global.time_zone, @@session.time_zone;
如果查詢結果是SYSTEM,表示mysql服務器使用了系統時區 date -R
命令能查看系統時區。MySql 時間類型 & JDBC時間類型