3

我正在使用 MySQL 5.0。我需要将日期时间信息存储在一列中。我的意思是使用DATETIMETIMESTAMP列类型。但是我对夏冬时间的变化有疑问。

我的时区是 CET。夏季我们使用夏令时(CEST,GMT+2),冬季我们使用冬季时间(CET,GMT+1)。在夏令时变为冬令时的那一天(今年 2012 年是 10 月 28 日)我们有两次凌晨 2:00 的时间。这一天的时间顺序是:

... -> 1:00 CEST -> 2:00 CEST -> 2:00 CET (= 3:00 CEST) -> 3:00 CET -> ...

因此,如果我有时间戳/日期时间 '2012-10-28 02:00:00' 我无法正确地说出这个时间是代表夏季时间还是冬季时间凌晨 2:00。

我有两个不同的 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”。但是当我从数据库中将这些值返回到日期变量中时,我得到了两个相同的日期。所以输入日期不同但输出日期相同。
如果我使用该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 在我看来没什么用。

4

3 回答 3

6

在我看来,你最好的选择是告诉 MySQL 使用 GMT 并在你的应用程序代码中处理所有本地时间问题,而不是你的数据库。数据库中的值始终是 GMT,句号,这是明确的。正如您所说,通过夏令时(夏令时)调整,您最终可以在数据库中获得相同的值,对于我们人类来说,这是两个不同的时间。

这也使数据库具有可移植性。如果您搬到北美并开始使用设置为(例如)中央时间的 MySQL,突然之间,您的数据库中的值似乎已经移动了几个小时。我继承的数据库使用服务器的本地时间时遇到了这个问题:当我将它从美国东海岸移动到西海岸时,没有考虑检查 MySQL 是否设置为使用机器的区域......

于 2012-11-05T15:30:26.080 回答
3

DATE, TIME,YEARDATETIME都存储各自的日期/时间指示,就像拍摄日历和/或钟面的照片一样:它们不记录设置时钟的时区,因此它们不代表任何特定的时刻。它们对于发生在特定本地日期或特定本地时间(即不考虑时区)的事件很有用。

TIMESTAMP存储 UTC 时间戳(自 UNIX 纪元以来的秒数),time_zone根据需要执行与会话的转换:它表示精确、明确的时刻。这就是你想要的;只要确保适当地设置您的会话变量(使用SET SESSION time_zone = ...)。

有关更多信息,请参阅MySQL 服务器时区支持

于 2012-11-05T15:56:30.427 回答
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());
}
于 2012-11-05T16:22:12.470 回答