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

2023-12-23

我对 SQL DATE 数据类型与 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 时间戳。在哪一步添加时区?为什么?

Note:

  • 我观察到对于这些数据库中的任何一个都是如此:

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

  • 我观察到这对于 SQLite 来说是错误的(它实际上并没有真正的DATE数据类型)
  • 所有这些在使用时都无关紧要java.sql.Timestamp代替java.sql.Date
  • 这是一个类似的问题,但没有回答这个问题:java.util.Date 与 java.sql.Date https://stackoverflow.com/questions/2305973/java-util-date-vs-java-sql-date

The JDBC规范 http://download.oracle.com/otndocs/jcp/jdbc-4_1-mrel-spec/index.html没有定义有关时区的任何详细信息。尽管如此,我们大多数人都知道必须处理 JDBC 时区差异的痛苦;看看所有的StackOverflow 问题 https://stackoverflow.com/search?q=jdbc+time+zone!

最终,日期/时间数据库类型的时区处理归结为数据库服务器、JDBC 驱动程序以及两者之间的所有内容。您甚至会受到 JDBC 驱动程序错误的影响; PostgreSQL 修复了一个8.3版本的bug http://jdbc.postgresql.org/changes.html#N10600 where

传递 Calendar 对象的 Statement.getTime、.getDate 和 .getTimestamp 方法正在以错误的方向旋转时区。

当您使用创建新日期时new Date(0)(假设您正在使用 Oracle JavaSEjava.sql.Date http://docs.oracle.com/javase/7/docs/api/java/sql/Date.html,您的日期已创建

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

So, new Date(0)应该使用 GMT。

你打电话时ResultSet.getDate(int) http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html#getDate%28int%29,您正在执行 JDBC 实现。 JDBC 规范没有规定 JDBC 实现应如何处理时区详细信息;所以你只能受实施的摆布。看看Oracle 11goracle.sql.DATE http://docs.oracle.com/cd/E18283_01/appdev.112/e13995/oracle/sql/DATE.htmlJavaDoc,Oracle DB 似乎没有存储时区信息,因此它执行自己的转换以将日期转换为java.sql.Date。我没有使用 Oracle DB 的经验,但我猜测 JDBC 实现正在使用服务器和本地 JVM 的时区设置来进行转换oracle.sql.DATE to java.sql.Date.


您提到多种 RDBMS 实现都可以正确处理时区,但 SQLite 除外。让我们看看如何H2 http://www.h2database.com/ and SQLite http://www.sqlite.org/当您将日期值发送到 JDBC 驱动程序以及从 JDBC 驱动程序获取日期值时,该功能会起作用。

H2 JDBC 驱动程序PrepStmt.setDate(int, Date) https://code.google.com/p/h2database/source/browse/trunk/h2/src/main/org/h2/jdbc/JdbcPreparedStatement.java#359 uses ValueDate.get(Date) https://code.google.com/p/h2database/source/browse/trunk/h2/src/main/org/h2/value/ValueDate.java#56,这称为DateTimeUtils.dateValueFromDate(long) https://code.google.com/p/h2database/source/browse/trunk/h2/src/main/org/h2/util/DateTimeUtils.java#732它进行时区转换。

使用这个SQLite JDBC 驱动程序 https://code.google.com/p/sqlite-jdbc/, PrepStmt.setDate(int, Date) https://code.google.com/p/sqlite-jdbc/source/browse/src/main/java/org/sqlite/PrepStmt.java#283 calls PrepStmt.setObject(int, Object) https://code.google.com/p/sqlite-jdbc/source/browse/src/main/java/org/sqlite/PrepStmt.java#221并且不进行任何时区转换。

H2 JDBC 驱动程序JdbcResultSet.getDate(int) https://code.google.com/p/h2database/source/browse/trunk/h2/src/main/org/h2/jdbc/JdbcResultSet.java#344回报get(columnIndex).getDate(). get(int) https://code.google.com/p/h2database/source/browse/trunk/h2/src/main/org/h2/jdbc/JdbcResultSet.java#2950返回一个H2Value https://code.google.com/p/h2database/source/browse/trunk/h2/src/main/org/h2/value/Value.java对于指定的列。由于列类型是DATE, H2 使用ValueDate https://code.google.com/p/h2database/source/browse/trunk/h2/src/main/org/h2/value/ValueDate.java. ValueDate.getDate() https://code.google.com/p/h2database/source/browse/trunk/h2/src/main/org/h2/value/ValueDate.java#80 calls DateTimeUtils.convertDateValueToDate(long) https://code.google.com/p/h2database/source/browse/trunk/h2/src/main/org/h2/util/DateTimeUtils.java#628,最终创建一个java.sql.Date时区转换后。

使用这个SQLite JDBC 驱动程序 https://code.google.com/p/sqlite-jdbc/, the RS.getDate(int) https://code.google.com/p/sqlite-jdbc/source/browse/src/main/java/org/sqlite/RS.java#265代码更简单;它只是返回一个java.sql.Date使用long存储在数据库中的日期值。

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

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


我找到了这个 Microsoft SQL Server 博客,在 SQL Server 2008 中使用时区数据 https://blogs.msdn.com/b/sqlprogrammability/archive/2008/03/18/using-time-zone-data-in-sql-server-2008.aspx,这解释了时区如何使事情变得复杂:

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SQL DATE 与 java.sql.Date 中的时区 的相关文章

随机推荐

  • 在javascript中获取元数据属性

    我在从元标记检索信息时遇到问题 我正在尝试从网站获取 img src 但不太明白 这是我正在尝试做的一个例子 var image document querySelector meta property og image getAttrib
  • 如何在引导模式主体上创建具有固定标题的可滚动表格?

    我尝试了这个 但这不起作用 字段值是动态变化的 所以宽度不固定 div class table responsive table class table table hover thead tr tr thead tbody style h
  • 对 Django Q 对象执行逻辑异或

    我想执行逻辑异或 XOR http en wikipedia org wiki Exclusive disjunction on django db models Q对象 使用operator http docs python org 2
  • if 语句无论条件是否满足都运行

    我的 if 语句贯穿始终 就好像条件已满足 即使条件尚未满足 我尝试过移动一些代码 甚至以不同的方式重写 if 语句 但它并没有改变结果 有谁知道我做错了什么 include
  • 如何将字节数组转换为MultipartFile

    我正在接收 BASE64 编码字符串 encodedBytes 形式的图像 并使用以下方法在服务器端解码为 byte BASE64Decoder decoder new BASE64Decoder byte decodedBytes dec
  • 平均特定数字的随机数

    看起来很简单 但我想要一个公式 最好是 net 对于给定的数字 比如说 1 5 公式将输出一个随机数 该数字在一系列中平均约为 1 5 所以它可能是 0 1 1 2 7 1 2 5 2 等 但平均值将接近1 5 澄清 我希望这些数字是正数
  • 在 Mobile Safari 上的 CSS 中使用右浮动时字体大小错误

    我在使用简单的 CSS 布局时遇到问题 它适用于桌面浏览器 但不适用于 iPhone 的 Mobile Safari 使用 style float right 似乎与 Mobile Safari 进行的自动字体大小调整相冲突 以下代码在桌面
  • shmget() 返回的 shmid 在进程中是否唯一?

    这是我无法真正弄清楚的事情 如果你在Linux上使用相同的密钥但在不同的进程中调用shmget 你会得到相同的shmid吗 shmid 是一个临时值 例如文件描述符编号 还是可以在调用之间保留的值 是的 您将收到相同的 shmid 共享内存
  • 如何相对于图像定位 div?

    我有一张图像 它可能会根据某些操作和我想要的几个 div 来改变其位置position on the img tag 简化后的代码如下 div img src someRandomImageUrl div foobar div div 为了
  • Symfony3:致命错误:在 .\bin\console 中找不到类“AppKernel”

    刚开始做一个项目 我跑了composer update并在尝试清除缓存时遇到异常 当我尝试跑步时php bin console server run我收到这样的消息 php bin console server run PHP Fatal
  • 在唯一约束之前清理 SQL 数据

    我想在对两列添加唯一约束之前清理表中的一些数据 CREATE TABLE test a integer NOT NULL b integer NOT NULL c integer NOT NULL CONSTRAINT a pk PRIMA
  • 与Butterknife绑定以在android中动态添加视图

    如何绑定布局中存在的视图 该布局是使用 ButterKnife 动态添加到父视图的 我有一个 LinearLayout 说容器 我有一个自定义布局 其中包含两个按钮 将此布局表示为子视图在活动中我添加了子视图成功到父LinearLayout
  • UILabel sizeToFit 仅适用于关闭自动布局的情况

    所以我正在使用 iOS 6 制作一个应用程序 并且想知道为什么我的代码曾经在 iOS 5 上运行良好 但现在不再运行了 我有一个带有动态 UILabel 的单元格 它会根据它所携带的文本进行调整 这是打开自动布局的情况 这是关闭自动布局的情
  • 使 VBE 助手在使用其他办公应用程序的功能/命令时显示

    我正在编写一些操作其他办公应用程序 office 的代码 当我编写代码时 我希望 VBE 帮助我处理属性和函数 就像它对链接到 Excel 的代码一样 这是怎么做到的 例如 当我输入 word doc 并在后面添加一个点时 我希望 VBE
  • 用于监视 FTP 服务器上的更改的批处理脚本

    我想要制作一个批处理脚本 能够侦听我的 ftp 服务器 并在每次在 ftp 服务器上上传新文件时将文件下载到我的计算机 有任何想法吗 我用的是WinSCP 您可以使用WinSCP 脚本 https winscp net eng docs s
  • WPF - 具有三列的 GridSplitter

    我有一个带有 3 列网格的应用程序 第一列和第二列之间的网格分离器工作得很好 为了使分离器位于第二列和第三列之间 我为分离器制作了一列 所以现在第三列实际上是第四列 当我调整大小时 其他列也会缩小 我认为这是因为我将它们设置为相对大小 但我
  • Golang XML:解组忽略名称空间

    我正在 Go 系统中实现一项从外部 SOAP 服务读取数据的服务 现在我正在为其编写测试 我遇到了这个问题 unable to unmarshal request body for testing expected element type
  • CALayer 优化?

    我添加了几个 CALayer 作为 UIView 层的子层 每层的内容是从服务器下载的不同图像 每个图层都从屏幕外动画到随机生成的位置 图像数据是异步下载的 每个图像大约为 300x300 或更小 由于随机放置 图层重叠 有些图层被上面的图
  • Visual Studio 2010 - 如何强制项目引用使用确切路径而不是 GAC 或程序文件?

    我们永远都会遇到这个问题 我们有很多解决方案和一个相邻的 Components 文件夹 我们要引用的所有 DLL 都在这个文件夹中 其中一些是我们从源代码构建的 以使用仅存在于组件二进制文件中的特定版本号 但是当不同计算机上的用户从 TFS
  • SQL DATE 与 java.sql.Date 中的时区

    我对 SQL DATE 数据类型与 SQL DATE 数据类型的行为感到有点困惑java sql Date 以下面的语句为例 select cast as date in most databases select cast as date