После поиска и чтения о том, как обрабатывать дату и время в/из Java и MySQL, я все еще в замешательстве.
Допустим, я создаю объект java.util.Date
. Этот объект хранит время в формате UTC. Любое форматирование или синтаксический анализ в другие часовые пояса можно выполнить, например, с помощью. java.text.SimpleDateFormat
.
Теперь я хочу сохранить объект даты в базе данных MySQL в формате UTC. Но когда я использую метод setTimestamp()
в java.sql.PreparedStatement
, я немного запутался. Ниже приведен пример кода, в котором я тестирую MySQL DATETIME и TIMESTAMP в своей таблице. Я также вставляю даты методами setString()
и setTimestamp()
.
java.sql.Connection conn = java.sql.DriverManager.getConnection("jdbc:mysql://localhost/test","user","password");
java.sql.Statement st = conn.createStatement();
String q = "DROP TABLE IF EXISTS tmp";
st.execute(q);
q = "CREATE TABLE tmp (dt_string TEXT, dt DATETIME, ts TIMESTAMP)";
st.execute(q);
java.sql.PreparedStatement pst = conn.prepareStatement("INSERT INTO tmp SET dt_string=?, dt=?, ts=?");
java.text.SimpleDateFormat utc = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
utc.setTimeZone(java.util.TimeZone.getTimeZone("UTC"));
java.util.TimeZone.setDefault(java.util.TimeZone.getTimeZone("EST"));
System.out.println("Default time zone: " + java.util.TimeZone.getDefault().getID());
java.util.Date d = new java.util.Date();
System.out.println("A date: " + d);
java.sql.Timestamp t = new java.sql.Timestamp( d.getTime() );
System.out.println("The timestamp: " + t);
pst.setString(1, utc.format(d) );
pst.setString(2, utc.format(d) );
pst.setString(3, utc.format(t) );
pst.execute();
pst.setTimestamp(2, t);
pst.setTimestamp(3, t);
pst.execute();
System.out.println("Use calendar: " + utc.getCalendar().getTimeZone() );
pst.setTimestamp(2, t, utc.getCalendar());
pst.setTimestamp(3, t, utc.getCalendar());
pst.execute();
conn.close();
Когда я запускаю приведенное выше, я получаю следующий вывод, который соответствует ожидаемому.
Default time zone: EST
A date: Thu Mar 22 08:49:51 EST 2012
The timestamp: 2012-03-22 08:49:51.784
Use calendar: sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
Но когда я проверяю таблицу в базе данных с помощью инструмента командной строки MySQL, я получаю:
mysql> select * from tmp;
+---------------------+---------------------+---------------------+
| dt_string | dt | ts |
+---------------------+---------------------+---------------------+
| 2012-03-22 13:49:51 | 2012-03-22 13:49:51 | 2012-03-22 13:49:51 |
| 2012-03-22 13:49:51 | 2012-03-22 08:49:51 | 2012-03-22 08:49:51 |
| 2012-03-22 13:49:51 | 2012-03-22 08:49:51 | 2012-03-22 08:49:51 |
+---------------------+---------------------+---------------------+
3 rows in set (0.00 sec)
Первый столбец имеет тип TEXT, где я храню дату в формате UTC.
В первой строке я сохранил даты, используя метод setString()
.
Во второй строке я сохранил дату, используя метод setTimestamp(i,t)
. Я предполагаю, что JDBC автоматически преобразует дату, используя часовой пояс по умолчанию (, который я установил на EST ), прежде чем сохранить его. Но разве TIMESTAMP не должен всегда автоматически сохраняться в UTC. В документации MySQL сказано, что MySQL преобразует значения TIMESTAMP из текущего часового пояса в UTC для хранения и обратно из UTC в текущий часовой пояс для извлечения.(Выпуск 1 ).
Наконец, для третьей строки я использовал pst.setTimestamp(2, t, utc.getCalendar());
для хранения даты, надеясь, что драйвер должен использовать часовой пояс UTC. Но видимо не (Выпуск 2 ).
Я могу легко решить проблему хранения дат в формате UTC, установив часовой пояс по умолчанию на UTC. Но все же, я хотел бы понять, что происходит по двум вопросам выше.