Is java.sql.Timestamp timezone specific?
我必须将UTC日期时间存储在数据库中。我已将特定时区中给定的日期时间转换为UTC。为此,我遵循了下面的代码。我输入的日期时间是"20121225 10:00:00 Z",时区是"亚洲/加尔各答"我的服务器/DB(Oracle)运行在同一时区(IST)"亚洲/加尔各答"
获取此特定时区中的日期对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | String date ="20121225 10:00:00 Z"; String timeZoneId ="Asia/Calcutta"; TimeZone timeZone = TimeZone.getTimeZone(timeZoneId); DateFormat dateFormatLocal = new SimpleDateFormat("yyyyMMdd HH:mm:ss z"); //This date object is given time and given timezone java.util.Date parsedDate = dateFormatLocal.parse(date +"" + timeZone.getDisplayName(false, TimeZone.SHORT)); if (timeZone.inDaylightTime(parsedDate)) { // We need to re-parse because we don't know if the date // is DST until it is parsed... parsedDate = dateFormatLocal.parse(date +"" + timeZone.getDisplayName(true, TimeZone.SHORT)); } //assigning to the java.sql.TimeStamp instace variable obj.setTsSchedStartTime(new java.sql.Timestamp(parsedDate.getTime())); |
存储到数据库中
1 2 3 4 5 | if (tsSchedStartTime != null) { stmt.setTimestamp(11, tsSchedStartTime); } else { stmt.setNull(11, java.sql.Types.DATE); } |
产量
DB(Oracle)已存储相同的给定
我已从下面的SQL中确认。
1 | select to_char(sched_start_time, 'yyyy/mm/dd hh24:mi:ss') from myTable |
我的数据库服务器也在同一时区"亚洲/加尔各答"上运行
它给了我下面的样子
还有一个问题:
像
虽然没有明确规定用于
Sets the designated parameter to the given
java.sql.Timestamp value, using the givenCalendar object. The driver uses theCalendar object to construct an SQLTIMESTAMP value, which the driver then sends to the database. With aCalendar object, the driver can calculate the timestamp taking into account a custom time zone. If noCalendar object is specified, the driver uses the default time zone, which is that of the virtual machine running the application.
当使用
例如:您的本地时区是GMT+2。您存储"2012-12-25 10:00:00 UTC"。数据库中存储的实际值为"2012-12-25 12:00:00"。您再次检索它:您再次将其恢复为"2012-12-25 10:00:00 UTC"(但仅当您使用
如果要将其存储在不同的时区,则需要将
因此,假设您要存储实际的GMT时区,则需要使用:
1 2 |
对于JDBC 4.2,兼容驱动程序应支持
我认为正确的答案应该是java.sql.timestamp不是特定于时区的。timestamp是java.util.date和单独纳秒值的组合。此类中没有时区信息。因此,就像日期一样,这个类只保存了1970年1月1日00:00:00 gmt+nanos以来的毫秒数。
在PreparedStatement.SetTimeStamp中(int参数index,时间戳x,日历cal)驱动程序使用日历更改默认时区。但时间戳在格林尼治标准时间内仍保持毫秒。
API不清楚JDBC驱动程序应该如何使用日历。提供程序似乎对如何解释它感到自由,例如,上次我使用MySQL5.5日历时,驱动程序只是忽略了PreparedStatement.SetTimeStamp和ResultSet.GetTimeStamp中的日历。
这是你的司机说的。您需要在Java程序中提供一个参数来告诉它要使用的时区。
1 | java -Duser.timezone="America/New_York" GetCurrentDateTimeZone |
此外:
1 | to_char(new_time(sched_start_time, 'CURRENT_TIMEZONE', 'NEW_TIMEZONE'), 'MM/DD/YY HH:MI AM') |
在正确处理转换时也可能有价值。从这里夺走
对于MySQL,我们有一个限制。在驱动程序mysql文件中,我们有:
The following are some known issues and limitations for MySQL
Connector/J: When Connector/J retrieves timestamps for a daylight
saving time (DST) switch day using the getTimeStamp() method on the
result set, some of the returned values might be wrong. The errors can
be avoided by using the following connection options when connecting
to a database:
1 2 3 | useTimezone=true useLegacyDatetimeCode=false serverTimezone=UTC |
所以,当我们不使用这个参数,我们称之为
例子:
JVM时区是GMT+2。在数据库中,我们有一个时间戳:146110256=19/04/16 21:10:56000000000 GMT
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Properties props = new Properties(); props.setProperty("user","root"); props.setProperty("password",""); props.setProperty("useTimezone","true"); props.setProperty("useLegacyDatetimeCode","false"); props.setProperty("serverTimezone","UTC"); Connection con = DriverManager.getConnection(conString, props); ...... Calendar nowGMT = Calendar.getInstance(TimeZone.getTimeZone("GMT")); Calendar nowGMTPlus4 = Calendar.getInstance(TimeZone.getTimeZone("GMT+4")); ...... rs.getTimestamp("timestampColumn");//Oracle driver convert date to jvm timezone and Mysql convert date to GMT (specified in the parameter) rs.getTimestamp("timestampColumn", nowGMT);//convert date to GMT rs.getTimestamp("timestampColumn", nowGMTPlus4);//convert date to GMT+4 timezone |
第一种方法返回:146110256000=19/04/2016-21:10:56 GMT
第二种方法返回:146110256000=19/04/2016-21:10:56 GMT
第三种方法返回:1461085856000=19/04/2016-17:10:56 GMT
与Oracle不同,当我们使用相同的调用时,我们有:
第一种方法返回:1461093056000=19/04/2016-19:10:56 GMT
第二种方法返回:146110256000=19/04/2016-21:10:56 GMT
第三种方法返回:1461085856000=19/04/2016-17:10:56 GMT
NB:不需要为Oracle指定参数。