我正在使用MySQL 5.0。我需要将日期时间信息存储在一列中。我的意思是使用DATETIME
或TIMESTAMP
列类型。但是夏季时间的变化我有问题。
我的时区是CET。夏天我们使用夏令时(CEST,它是GMT + 2),冬天我们使用冬季时间(CET,它是GMT + 1)。在夏季时间变为冬季的那一天(2012年是在10月28日)我们有时间凌晨2点两次。这一天的时间顺序是:
... -> 1:00 CEST -> 2:00 CEST -> 2:00 CET (= 3:00 CEST) -> 3:00 CET -> ...
所以,如果我有时间戳/日期时间'2012-10-28 02:00:00'如果此时间代表夏令时或冬季时间凌晨2点,我无法正确说出。
我有两个不同的Java日期:
Date d1 = new Date(1351382400000); // 2:00 CEST (summer-time)
Date d2 = new Date(1351386000000); // 2:00 CET (winter-time)
当我使用标准时间戳/日期时间格式(即'yyyy-MM-dd HH:mm:ss'
)将它们存储在数据库中时,它们都存储相同的数据“2012-10-28 02:00:00”。但是当我从数据库中将这些值返回到Date变量时,我得到两个相同的日期。因此输入日期不同,但输出日期相同
如果我使用FROM_UNIXTIME
函数存储日期值,则会出现同样的情况:FROM_UNIXTIME(1351382400)
和FROM_UNIXTIME(1351386000)
。值以相等的值存储在数据库列(DATETIME或TIMESTAMP类型)中。因此,当我将这些值输入Java的Date对象时,我再次得到两个相同的日期(在冬天)。
有没有办法在MySQL中存储时区,或者如何处理DATETIME / TIMESTAMP列中的时区信息?
当然,我可以使用unix-timestamp将BIGINT值存储在数据库中。但我想知道是否有任何方法可以解决任何MySQL日期时间类型的问题。
任何帮助或技巧都值得赞赏...... :)
非常感谢。
Honza(sporak)
编辑#1:
如果我试图存储时间戳值,然后将此时间戳值提取到java的日期,我再次得到错误的日期。假设我有一个带有TIMESTAMP列的简单表。我以这种方式将数据存储在此表中:
mysql> INSERT INTO `tab` (timestamp_column) VALUES
(FROM_UNIXTIME(1351382400)), // 2:00 CEST (summer-time)
(FROM_UNIXTIME(1351386000)); // 2:00 CET (winter-time)
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
当我将这些行提取到Java Date对象中时,我得到两个显示2:00 CET的相同日期。而且还有更多 - 当我在MySQL中获取这些行时,我在MySQL中再次得到错误的值:
mysql> SELECT UNIX_TIMESTAMP(timestamp_column) from tab;
+--------------------+
| UNIX_TIMESTAMP(ts) |
+--------------------+
| 1351386000 |
| 1351386000 |
+--------------------+
2 rows in set (0.00 sec)
所以TIMESTAMP在我看来毫无用处。
答案 0 :(得分:6)
在我看来,最好的办法是告诉MySQL使用GMT并处理应用程序代码中的所有本地时间问题,而不是数据库。数据库中的值始终为GMT,完全停止,这是明确的。正如你所说,在夏令时(夏令时)调整的情况下,你可以在数据库中找到相同的值,对于我们人类来说,两次不同的时间。
这也使数据库可移植。如果你移动到北美并开始使用设置为(比如)中央时间的MySQL,那么数据库中的值似乎已经移动了几个小时。我有一个我继承的数据库的问题,当我将它从美国东海岸移到西海岸时,使用服务器的本地时间,没想过检查MySQL是否从属于机器的区域... < / p>
答案 1 :(得分:2)
DATE
,TIME
,YEAR
和DATETIME
都存储相应的日期/时间指示,就像拍摄日历的照片一样和/或表盘:它们不记录时钟设置的时区,因此它们不代表任何特定时刻。它们对于在特定本地日期或特定本地时间发生的事件非常有用(即无论时区如何)。
TIMESTAMP
存储UTC时间戳(自UNIX纪元以来的秒数),根据需要执行会话time_zone
的转换:它代表一个精确,明确的时刻。这就是你想要的;只需确保适当地设置会话变量(使用SET SESSION time_zone = ...
)。
有关详细信息,请参阅MySQL Server Time Zone Support。
答案 2 :(得分:0)
您可以在存储在数据库中之前将日期转换为UTC ,然后在从数据库读取时转换回您自己的时区。
long t = 1351382400000; // the timestamp in UTC
String insert = "INSERT INTO my_table (timestamp) VALUES (?)";
PreparedStatement stmt = db.prepareStatement(insert);
java.sql.Timestamp date = new Timestamp(t);
stmt.setTimestamp(1, date);
stmt.executeUpdate();
.....
TimeZone timezone = TimeZone.getTimeZone("MyTimeZoneId");
Calendar cal = java.util.Calendar.getInstance(timezone);
String select = "SELECT timestamp FROM my_table";
// some code omitted....
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
java.sql.Timestamp ts = rs.getTimestamp(1);
cal.setTimeInMillis(ts.getTime());
System.out.println("date in db: " + cal.getTime());
}