ara*_*ayo 5 java postgresql jdbc
Postgresql 似乎转换了我使用 setTimestamp 设置的 PreparedStatement 的时间戳参数。
[我想做的事]
我想查询今天的数据。( 2016-06-30 00:00:00 ~ 2016-06-30 23:59:59)
但是,当我从 DB 得到结果时,它是 2016-06-29 15:00:00 到 2016-06-30 14:59:59 的数据。( 9 小时间隔)
我的本地时区:GMT+9 (KST)
DB timezone : UTC (GMT+0) (在表中,UTC时间存储为更新时间。我检查过。)
所以我猜是 9 小时的差距。当我将 UTC 时间戳参数传递给 postgresql 时,它从我的时间戳参数中减去了 9 小时。我想知道为什么 postgresql 这样做,以及我如何防止这种情况发生。
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
sdf2.setTimeZone(TimeZone.getTimeZone("UTC"));
Timestamp startTime = Timestamp.valueOf(sdf.format(new Date(System.currentTimeMillis())));
Timestamp endTime = Timestamp.valueOf(sdf2.format(new Date(System.currentTimeMillis())));
PreparedStatement pstmt = conn.prepareStatement(
"SELECT * FROM some_table WHERE update_time BETWEEN ? AND ? "
);
pstmt.setTimestamp(1, startTime);
pstmt.setTimestamp(2, endTime);
ResultSet rs = pstmt.executeQuery();
Run Code Online (Sandbox Code Playgroud)
【表结构】
CREATE TABLE some_table
(
mem_no bigserial
,data char(2)
,update_time timestamp with time zone DEFAULT current_timestamp
,CONSTRAINT pk_some_table PRIMARY KEY (mem_no)
);
Run Code Online (Sandbox Code Playgroud)
[奇怪的东西]
使用调试工具,我检查了 pstmt 值。奇怪的+09:00:00
是被添加到我的参数中。
pstmt => SELECT * FROM some_table WHERE update_time BETWEEN 2016-06-30 00:00:00+09:00:00
和 2016-06-30 23:59:59+09:00:00
数据库:postgresql 9.3
我解决了这个问题^^
[我的答案] (1) WHERE 子句 (2) 字符串而不是时间戳
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
sdf2.setTimeZone(TimeZone.getTimeZone("UTC"));
String startTime = sdf.format(new Date(System.currentTimeMillis()));
String endTime = sdf2.format(new Date(System.currentTimeMillis()));
PreparedStatement pstmt = conn.prepareStatement(
"SELECT * FROM some_table " +
"WHERE update_time " +
"BETWEEN (CAST(TO_TIMESTAMP(?,'YYYY-MM-DD HH24:MI:SS') AS TIMESTAMP) AT TIME ZONE 'UTC') " +
"AND (CAST(TO_TIMESTAMP(?,'YYYY-MM-DD HH24:MI:SS') AS TIMESTAMP) AT TIME ZONE 'UTC')");
pstmt.setString(1, startTime);
pstmt.setString(2, endTime);
ResultSet rs = pstmt.executeQuery();
Run Code Online (Sandbox Code Playgroud)
显然,时区偏移量 +09 是自动附加的。所以我决定给出 String 参数而不是时间戳。(JDBC或Postgresql不会改变字符串值)然后我测试了一些这样的情况。
[测试]
PreparedStatement pstmt = conn.prepareStatement(
"SELECT TO_TIMESTAMP(?,'YYYY-MM-DD HH24:MI:SS') test1 " +
"CAST(TO_TIMESTAMP(?,'YYYY-MM-DD HH24:MI:SS') AS TIMESTAMP) test2 " +
"(CAST(TO_TIMESTAMP(?,'YYYY-MM-DD HH24:MI:SS') AS TIMESTAMP) AT TIME ZONE 'UTC') test3 " +
"FROM some_table " +
"WHERE update_time " +
"BETWEEN TO_TIMESTAMP(?,'YYYY-MM-DD HH24:MI:SS') " + => In test, this is not important
"AND TO_TIMESTAMP(?,'YYYY-MM-DD HH24:MI:SS') "); => In test, this is not important
pstmt.setString(1, startTime);
pstmt.setString(2, startTime);
pstmt.setString(3, startTime);
pstmt.setString(4, startTime);
pstmt.setString(5, endTime);
ResultSet rs = pstmt.executeQuery();
System.out.println(rs.getString("test1") + "/" +rs.getString("test2") + "/" + rs.getString("test3") );
Run Code Online (Sandbox Code Playgroud)
[结果]
当前时间:2016-07-01 15:17:40+00(UTC 时间)
开始时间:“2016-07-01 00:00:00”=>字符串
test1 : 2016-07-01 00:00:00+09 => cause subtraction ( 2017-06-30 15:00:00)
test2 : 2016-07-01 00:00:00
test3 : 2016-07-01 09:00:00+09 => Wow ^^
Run Code Online (Sandbox Code Playgroud)
[test3] 就是我想要的。当我像上面那样更改 where 子句时,我可以获得2016-07-01 00:00:00 ~ 2016-07-01 23:59:59的数据