我有一张表,用于存储来自传感器的数据
CREATE TABLE `testdatabase` (
`dateTime` datetime DEFAULT NULL,
`data` varchar(200) DEFAULT NULL,
`sensorID` varchar(10) DEFAULT NULL
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6918 DEFAULT CHARSET=utf8
这是我正在运行的选择查询,
SELECT `dateTime` from testdatabase WHERE sensorID='ABC1234' AND (dateTime BETWEEN '2017-03-26 00:01:00' AND '2017-03-26 00:00:00') order by `dateTime` asc;
当我在 MySQL Workbench 中运行此查询时,它返回正确的日期时间。
2017-03-26 00:10:00
2017-03-26 00:20:00
2017-03-26 00:30:00
2017-03-26 00:40:00
2017-03-26 00:50:00
2017-03-26 01:00:00
2017-03-26 01:10:00
2017-03-26 01:20:00
2017-03-26 01:30:00
2017-03-26 01:40:00
2017-03-26 01:50:00
2017-03-26 02:00:00
2017-03-26 02:10:00
2017-03-26 02:20:00
2017-03-26 02:30:00
2017-03-26 02:40:00
2017-03-26 02:50:00
2017-03-26 03:00:00
但是当我从我的 java 应用程序运行这个查询时,它返回以下日期时间。
2017-03-26 00:10:00
2017-03-26 00:20:00
2017-03-26 00:30:00
2017-03-26 00:40:00
2017-03-26 00:50:00
2017-03-26 02:00:00
2017-03-26 02:10:00
2017-03-26 02:20:00
2017-03-26 02:30:00
2017-03-26 02:40:00
2017-03-26 02:50:00
2017-03-26 02:00:00
2017-03-26 02:10:00
2017-03-26 02:20:00
2017-03-26 02:30:00
2017-03-26 02:40:00
2017-03-26 02:50:00
2017-03-26 03:00:00
显然,这与英国 3 月 26 日凌晨 1 点发生的夏令时变化有关。 我认为 JDBC 连接正在将时间更改为 BST,但我不希望这样。
我尝试将 MySQL 服务器全局时区设置为 00:00
SET @@global.time_zone='+00:00';
但是没有成功! 如何在不更改 DST 的情况下获得正确的时间?
编辑:
我正在使用 Java 1.7
和 mysql-connector-java-5.1.19-bin.jar
我在 Mark Rotteveel
评论之前但之后以字符串形式获取数据 我尝试了 PreparedStaement
并将日历对象设置为 UTC,但两者都返回相同的结果。
try
{
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query);
while(resultSet.next())
{
System.out.println("Without Calendar Object : "+resultSet.getString(1));
}
}catch (SQLException e){e.printStackTrace();}
try
{
PreparedStatement statement = connection.prepareStatement(query);
ResultSet resultSet = statement.executeQuery();
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
while(resultSet.next())
{
System.out.println("With Calendar Object : "+resultSet.getTimestamp(1, cal));
}
}catch (SQLException e){e.printStackTrace();}
OUTPUT:
Without Calendar Object : 2017-03-26 00:10:00.0
Without Calendar Object : 2017-03-26 00:20:00.0
Without Calendar Object : 2017-03-26 00:30:00.0
Without Calendar Object : 2017-03-26 00:40:00.0
Without Calendar Object : 2017-03-26 00:50:00.0
Without Calendar Object : 2017-03-26 02:00:00.0
Without Calendar Object : 2017-03-26 02:10:00.0
Without Calendar Object : 2017-03-26 02:20:00.0
Without Calendar Object : 2017-03-26 02:30:00.0
Without Calendar Object : 2017-03-26 02:40:00.0
Without Calendar Object : 2017-03-26 02:50:00.0
Without Calendar Object : 2017-03-26 02:00:00.0
Without Calendar Object : 2017-03-26 02:10:00.0
Without Calendar Object : 2017-03-26 02:20:00.0
Without Calendar Object : 2017-03-26 02:30:00.0
Without Calendar Object : 2017-03-26 02:40:00.0
Without Calendar Object : 2017-03-26 02:50:00.0
Without Calendar Object : 2017-03-26 03:00:00.0
With Calendar Object : 2017-03-26 00:10:00.0
With Calendar Object : 2017-03-26 00:20:00.0
With Calendar Object : 2017-03-26 00:30:00.0
With Calendar Object : 2017-03-26 00:40:00.0
With Calendar Object : 2017-03-26 00:50:00.0
With Calendar Object : 2017-03-26 02:00:00.0
With Calendar Object : 2017-03-26 02:10:00.0
With Calendar Object : 2017-03-26 02:20:00.0
With Calendar Object : 2017-03-26 02:30:00.0
With Calendar Object : 2017-03-26 02:40:00.0
With Calendar Object : 2017-03-26 02:50:00.0
With Calendar Object : 2017-03-26 02:00:00.0
With Calendar Object : 2017-03-26 02:10:00.0
With Calendar Object : 2017-03-26 02:20:00.0
With Calendar Object : 2017-03-26 02:30:00.0
With Calendar Object : 2017-03-26 02:40:00.0
With Calendar Object : 2017-03-26 02:50:00.0
With Calendar Object : 2017-03-26 03:00:00.0
编辑 2: 还有一件奇怪的事情,当我将默认时区更改为 UTC 时,它会返回凌晨 1 点而不是凌晨 2 点的重复值。
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
输出:
Without Calendar Object : 2017-03-26 00:10:00.0
Without Calendar Object : 2017-03-26 00:20:00.0
Without Calendar Object : 2017-03-26 00:30:00.0
Without Calendar Object : 2017-03-26 00:40:00.0
Without Calendar Object : 2017-03-26 00:50:00.0
Without Calendar Object : 2017-03-26 01:00:00.0
Without Calendar Object : 2017-03-26 01:10:00.0
Without Calendar Object : 2017-03-26 01:20:00.0
Without Calendar Object : 2017-03-26 01:30:00.0
Without Calendar Object : 2017-03-26 01:40:00.0
Without Calendar Object : 2017-03-26 01:50:00.0
Without Calendar Object : 2017-03-26 01:00:00.0
Without Calendar Object : 2017-03-26 01:10:00.0
Without Calendar Object : 2017-03-26 01:20:00.0
Without Calendar Object : 2017-03-26 01:30:00.0
Without Calendar Object : 2017-03-26 01:40:00.0
Without Calendar Object : 2017-03-26 01:50:00.0
Without Calendar Object : 2017-03-26 02:00:00.0
With Calendar Object : 2017-03-26 00:10:00.0
With Calendar Object : 2017-03-26 00:20:00.0
With Calendar Object : 2017-03-26 00:30:00.0
With Calendar Object : 2017-03-26 00:40:00.0
With Calendar Object : 2017-03-26 00:50:00.0
With Calendar Object : 2017-03-26 01:00:00.0
With Calendar Object : 2017-03-26 01:10:00.0
With Calendar Object : 2017-03-26 01:20:00.0
With Calendar Object : 2017-03-26 01:30:00.0
With Calendar Object : 2017-03-26 01:40:00.0
With Calendar Object : 2017-03-26 01:50:00.0
With Calendar Object : 2017-03-26 01:00:00.0
With Calendar Object : 2017-03-26 01:10:00.0
With Calendar Object : 2017-03-26 01:20:00.0
With Calendar Object : 2017-03-26 01:30:00.0
With Calendar Object : 2017-03-26 01:40:00.0
With Calendar Object : 2017-03-26 01:50:00.0
With Calendar Object : 2017-03-26 02:00:00.0
最佳答案
这里有两个问题:
- 我们是否从服务器返回了所需的
java.sql.Timestamp
值? - 当我们要求 Java 将
Timestamp
值显示为日期/时间字符串时,我们实际上看到了什么?
为了帮助解决这个问题,我们可以以数字形式显示 Timestamp
值。 Timestamp#getTime()
返回自纪元 (1970-01-01 00:00:00 UTC) 以来的毫秒数,但如果我们将其除以 60000 可以使其更易于阅读给出纪元以来的分钟数。
我们还可以使用 SimpleDateFormat
对象以明确的方式格式化 Timestamp
值。
因此对于名为 tztest
的示例表,在 phpMyAdmin 中看起来像这样
id dateTime
-- -------------------
1 2017-03-26 00:10:00
2 2017-03-26 01:10:00
3 2017-03-26 02:10:00
当我运行以下 Java 代码时
connectionUrl = "jdbc:mysql://localhost:3307/mydb";
try (Connection conn = DriverManager.getConnection(connectionUrl, myUid, myPwd)) {
SimpleDateFormat sdfLocal = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
Calendar calUTC = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
SimpleDateFormat sdfUTC = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
sdfUTC.setCalendar(calUTC);
String sql =
"SELECT id, CAST(dateTime AS CHAR) AS datetimeString, dateTime " +
"FROM tztest ORDER BY dateTime";
try ( Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(sql)) {
while (rs.next()) {
int id = rs.getInt("id");
String datetimeString = rs.getString("datetimeString");
Timestamp timestampValue = rs.getTimestamp("dateTime", calUTC);
long minutesSinceEpoch = timestampValue.getTime() / 60000;
System.out.printf("%d: %s -> %d minutes since epoch -> %s / %s%n",
id,
datetimeString,
minutesSinceEpoch,
sdfLocal.format(timestampValue),
sdfUTC.format(timestampValue)
);
}
}
} catch (Exception e) {
e.printStackTrace(System.err);
}
控制台输出是
1: 2017-03-26 00:10:00 -> 24841450 minutes since epoch -> 2017-03-26 00:10:00 GMT / 2017-03-26 00:10:00 UTC
2: 2017-03-26 01:10:00 -> 24841510 minutes since epoch -> 2017-03-26 02:10:00 BST / 2017-03-26 01:10:00 UTC
3: 2017-03-26 02:10:00 -> 24841510 minutes since epoch -> 2017-03-26 02:10:00 BST / 2017-03-26 01:10:00 UTC
很明显,我没有得到所需的 Timestamp
值,因为第 2 行和第 3 行都显示“自纪元以来 24841510 分钟”。
我可以通过简单地将 useLegacyDatetimeCode=false
添加到我的连接字符串来纠正这个问题
connectionUrl = "jdbc:mysql://localhost:3307/mydb?useLegacyDatetimeCode=false";
之后控制台输出是
1: 2017-03-26 00:10:00 -> 24841450 minutes since epoch -> 2017-03-26 00:10:00 GMT / 2017-03-26 00:10:00 UTC
2: 2017-03-26 01:10:00 -> 24841510 minutes since epoch -> 2017-03-26 02:10:00 BST / 2017-03-26 01:10:00 UTC
3: 2017-03-26 02:10:00 -> 24841570 minutes since epoch -> 2017-03-26 03:10:00 BST / 2017-03-26 02:10:00 UTC
请注意,第 3 行现在显示“自纪元以来 24841570 分钟”,比第 2 行晚 60 分钟。另请注意,UTC 格式的日期时间值与我们使用 CAST(dateTime AS CHAR)< 获得的字符串表示相匹配
在 SQL 查询中。
关于java - MySQL选择没有夏令时更改的日期时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43072071/