当前位置: 首页 > 面试题库 >

SQL DATE中的时区vs java.sql.Date

昝涛
2023-03-14
问题内容

我对SQL DATE数据类型与的数据类型的行为感到有些困惑java.sql.Date。以以下语句为例:

select cast(? as date)           -- in most databases
select cast(? as date) from dual -- in Oracle

让我们准备并执行Java语句

PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setDate(1, new java.sql.Date(0)); // GMT 1970-01-01 00:00:00
ResultSet rs = stmt.executeQuery();
rs.next();

// I live in Zurich, which is CET, not GMT. So the following prints -3600000, 
// which is CET 1970-01-01 00:00:00
// ... or   GMT 1969-12-31 23:00:00
System.out.println(rs.getDate(1).getTime());

换句话说,我绑定到该语句的GMT时间戳成为我获取的CET时间戳。在什么时候添加时区,为什么?

注意:

  • 我观察到以下任何数据库都是如此:

DB2,Derby,H2,HSQLDB,Ingres,MySQL,Oracle,Postgres,SQL Server,Sybase ASE,Sybase
SQL Anywhere

  • 我观察到这对于SQLite是错误的(它实际上没有真正的DATE数据类型)
  • 使用java.sql.Timestamp代替时,所有这些都不相关java.sql.Date

问题答案:

在JDBC规范不问候时区定义的任何细节。尽管如此,我们大多数人都知道必须处理JDBC时区差异的痛苦。

最终,日期/时间数据库类型的时区处理归结为数据库服务器,JDBC驱动程序以及两者之间的所有内容。您甚至受JDBC驱动程序错误的支配。PostgreSQL修复了版本8.3中的错误,其中

传递给Calendar对象的Statement.getTime,.getDate和.getTimestamp方法使时区朝错误的方向旋转。

当您使用创建新日期时new Date(0)(假设您正在使用Oracle JavaSE
java.sql.Date,则会创建您的日期

使用给定的毫秒时间值。如果给定的毫秒值包含时间信息,则驱动程序会将时间分量设置为默认时区(运行应用程序的Java虚拟机的时区)中与GMT零相对应的时间。

因此,new Date(0)应使用GMT。

调用时ResultSet.getDate(int),您正在执行JDBC实现。JDBC规范没有规定JDBC实现应如何处理时区细节。因此,您无法实现。从Oracle
11g
oracle.sql.DATEJavaDoc看,Oracle
DB似乎没有存储时区信息,因此它执行自己的转换以将日期转换为java.sql.Date。我没有使用Oracle
DB的经验,但是我想JDBC的实现是使用服务器的本地JVM的时区设置来进行从oracle.sql.DATE到的转换java.sql.Date

您提到了多个RDBMS实现可以正确处理时区,但SQLite除外。让我们看一下将日期值发送到JDBC驱动程序以及从JDBC驱动程序获取日期值时H2和SQLite的工作方式。

H2 JDBC驱动程序PrepStmt.setDate(int, Date)使用ValueDate.get(Date),该调用DateTimeUtils.dateValueFromDate(long)进行时区转换。

使用此SQLite JDBC驱动程序,PrepStmt.setDate(int, Date)调用PrepStmt.setObject(int, Object)并且不进行任何时区转换。

H2
JDBC驱动程序JdbcResultSet.getDate(int)返回get(columnIndex).getDate()get(int)返回Value指定列的H2
。由于列类型为DATE,因此H2使用ValueDateValueDate.getDate()调用DateTimeUtils.convertDateValueToDate(long),最终会java.sql.Date在时区转换后创建一个。

使用此SQLite JDBC驱动程序,RS.getDate(int)代码要简单得多。它只是java.sql.Date使用long存储在数据库中的日期值返回a

因此,我们看到H2 JDBC驱动程序在处理带日期的时区转换方面很聪明,而SQLite
JDBC驱动程序则不明智(并不是说这个决定不明智,它可能很适合SQLite设计决定)。如果您追查提到的其他RDBMS
JDBC驱动程序的源代码,则可能会发现大多数驱动程序都以与H2相似的方式接近日期和时区。

尽管JDBC规范没有详细说明时区处理,但是RDBMS和JDBC实现设计人员考虑时区并会正确处理时区是很有意义的。特别是如果他们希望自己的产品在全球舞台上可销售。这些设计师非常聪明,即使没有具体规范,大多数人也都能做到这一点,我对此并不感到惊讶。

我在Microsoft SQL Server博客中找到了使用SQL Server
2008中的时区数据,它说明了时区如何使事情变得复杂:

时区是一个复杂的区域,每个应用程序都需要解决如何处理时区数据的问题,以使程序更加用户友好。

不幸的是,当前没有时区名称和值的国际标准权威。每个系统都需要使用自己选择的系统,并且直到有国际标准之前,尝试让SQL
Server提供一个系统都是不可行的,最终将导致比解决的问题更多的问题。



 类似资料:
  • 问题内容: 我允许我的Web应用程序上的用户根据他们选择的时区安排事件。 我想向最终用户提供一个很好的时区列表,然后将其轻松转换为服务器端的对象。 是我可以使用的东西,但问题是它可以打印约585个时区ID。 向用户显示时区的简短列表(如Windows框时区设置)并在服务器端使用其ID轻松转换为TimeZone对象的最佳方法是什么? 问题答案: 时区列表取决于应用程序和区域设置。只有您知道哪些区域最

  • 我有一个日期。它是如何存储在数据库中的。我正在使用并调用此函数。 在这里,我知道我的

  • 问题内容: 谁能建议一种简单的方法来将日期和时间转换为php中的不同时区? 问题答案: 您可以为此使用datetime对象或其函数别名: 编辑评论 但我无法使用此方法,因为当用户从不同位置登录时,我需要在不同时区显示日期 那不是问题。用户登录后,您将确定其时区并将其设置为DateTime对象,如图所示。我在我的一个项目中使用了类似的方法,它的工作原理很吸引人。 在数据库中,我需要获取任何单个时区中

  • 我在时区面临一个问题。现在我正在从客户端保存时区,并将所有日期时间存储在UTC中。它工作正常,但当我试图将UTC的日期时间转换为CST、EST、EDT等时区后,它会显示错误的数据。 问题-假设我在美国东部夏令时晚上10点做了任何任务,并且它将在凌晨2点(按照UTC)保存在DB中,但当我尝试获取一天的数据并通过当前UTC日期时。 我的问题是,如果我试图获取一天的数据,比如从美国东部时间午夜11点到当

  • 问题内容: 我知道相反。给定一个时区,我可以通过以下代码片段获取时区偏移量: 我想知道如何从时区偏移量获取时区名称。 鉴于 (以毫秒为单位; +6.00偏移) 我想得到以下任何可能的时区名称的结果: 问题答案: 用

  • 问题内容: 在我的客户中,我有以下代码: 这两条线接连地运行。我从不设置时区或手动设置,仅依靠从OS和本地系统读取的默认设置。 执行后,它们产生: 系统时区确实是Phoenix,而不是UTC。Joda如何正确而JDK如何错误? 编辑 :这是Windows 7 x64主机,JRE是1.6.22 x64。 编辑2 :不要尝试复制它。它只会在某些系统上失败,而不是在所有系统上失败(例如3k用户群中的几十