在搜索和阅读如何处理来自Java和MySQL的日期和时间后,我仍然感到困惑。
假设我创建了一个java.util.Date
对象。该对象保留UTC时间。任何格式化或解析到其他时区都可以用例如java.text.SimpleDateFormat
。
现在我想将我的日期对象以UTC格式存储到MySQL数据库中。但是当我在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格式存储日期的问题。但是,我仍然想了解上述两个问题的进展情况。
答案 0 :(得分:1)
最后,我理解了一些东西,但改用了PostgreSQL。我基本上使用
重复上面的代码Connection conn = DriverManager.getConnection("jdbc:postgresql://localhost");
st.execute("CREATE TABLE tmp (ts_string TEXT, ts TIMESTAMP WITH TIME ZONE)");
//st.execute("CREATE TABLE tmp (ts_string TEXT, ts TIMESTAMP WITHOUT TIME ZONE)");
并将日期写为
pst.setString(1, utc.format(d));
pst.setTimestamp(2, t);
pst.execute();
pst.setTimestamp(2, t, utc.getCalendar());
pst.execute();
使用TIMESTAMP WITH TIMEZONE
时,我会从psql
postgres=# select * from tmp;
ts_string | ts
-------------------------+----------------------------
2012-03-23 12:48:28.057 | 2012-03-23 13:48:28.057+01
2012-03-23 12:48:28.057 | 2012-03-23 13:48:28.057+01
(2 rows)
因为它跟踪系统(服务器)时区,即CET(+01)。虽然在CET中显示,但日期是正确的。
如果我改为使用TIMESTAMP WITHOUT TIME ZONE
我
postgres=# select * from tmp;
ts_string | ts
-------------------------+------------------------
2012-03-23 12:49:04.120 | 2012-03-23 07:49:04.12
2012-03-23 12:49:04.120 | 2012-03-23 12:49:04.12
(2 rows)
并且在第一种情况下它使用默认时区(我设置为EST),日期自然是“错误的”,就像MySQL的情况一样。但是,在第二种情况下,它使用UTC,因为我将其作为setTimestamp()
方法的参数传递,这就是我在MySQL中尝试做的事情。对我来说,似乎MySQL java驱动程序只是忽略了Calendar
中的setTimestamp()
参数。也许我错过了什么。
答案 1 :(得分:0)
MySql datetime字段在您绕过它们时非常棒。
您正在使用的“SimpleDateFormat”没有附加时区,因此您的数据库假定您在服务器的时区中输入日期。如果您在-0500时区,它会增加5个小时将其转换为UTC,然后当您获取它时,它会减去5个小时,然后将其转换回当地时间。
在插入之前将时间戳转换为utc时,仍然没有在字符串上添加时区。您的数据库对其执行了相同的操作。 2012-03-22 13:49:51增加了5个小时,所以你的数据库存储2012-03-22 18:49:51(仍然假设-0500)。
所有这一切真正有趣的部分是你可以在数据库连接上设置时区,你获取或插入的所有日期时间都会随着你的连接而变化!