Postgresql 似乎转换了 PreparedStatement 的时间戳参数

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

ara*_*ayo 0

我解决了这个问题^^

[我的答案] (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的数据