gpt4 book ai didi

java - 为什么JDBC在保存日期时会将时间调整为默认时区?

转载 作者:行者123 更新时间:2023-12-05 00:16:04 25 4
gpt4 key购买 nike

这个问题与this有关但这个具体问题的重点是为什么。所以不,这不是重复的。

引用答案:

The problem is that Java Date objects don't store a time zone. The value is always in UTC, and is parsed and formatted in a given time zone, usually the JVM's default time zone.

Oracle DATE columns are also stored without time zone, but should represent the date as seen by the user. In 99.99% of cases, that means the date in the JVM's default time zone.

So, the JDBC driver takes the Timestamp / Date value, which is in UTC, converts it to the default time zone, and saves that to the database.


  • 不按原样调整和保存值 (UTC) 到底有什么问题?
  • 它试图通过在将值保存到数据库之前调整值来解决什么问题?

  • 这些问题的答案就是为什么。

    我看不到设计的好处,我只能看到与之相关的问题。一个恰当的例子是在特定时区完成保存而在另一个时区完成检索。在这个特定主题上抛出的问题数量正好证明了我的观点。

    所以最终的问题是,为什么它是这样设计的?原因是什么?

    最佳答案

    日期时间处理是一个非常复杂的话题。作为程序员,我们对时间的直观理解对我们不利,使这个主题难以掌握。此外,旧数据库和旧类中糟糕的日期时间处理使工作更加困惑。

    时间

    首先,避免与最早版本的 Java 捆绑在一起的糟糕的旧日期时间类。从不使用 java.util.Date , java.util.Calendar , java.sql.Timestamp ,也没有其他相关的类。仅使用 java.time 类。如果您必须与尚未更新到 java.time 的旧代码交互,请调用添加到旧类的新转换方法。
    DateInstant 取代.

    The problem is that Java Date objects don't store a time zone.



    不对。安 Instant (和 Date )始终采用 UTC。现代类和遗留类都表示自 UTC 时间 1970 年的第一个时刻 1970-01-01T00:00:00Z 以来的小数秒计数。总是在 UTC,easy-peasy。

    Oracle DATE columns are also stored without time zone,



    真的。

    Oracle DATE data type仅表示带时区的日期,但缺少任何时区或 UTC 偏移量的概念。这显然是一种遗留类型,在 SQL 标准定义一些基本的日期时间类型之前创建。在标准中, TIMESTAMP WITHOUT TIME ZONE可能映射接近 Oracle DATE .

    but should represent the date as seen by the user. In 99.99% of cases, that means the date in the JVM's default time zone.



    我不明白作者这句话是什么意思。我认为这是他们笨拙的说法,任何类似于 SQL 标准的类型 TIMESTAMP WITHOUT TIME ZONE只需按原样获取任何给定日期或日期与时间,而不尝试在区域或偏移量之间进行调整。因此,如果您在 2018 年 1 月 21 日中午通过,它会存储一个与此字符串等效的值 2018-01-23T12:00不考虑那是魁北克蒙特利尔的中午还是印度加尔各答的中午(两个不同的时刻,相隔几个小时)。

    So, the JDBC driver takes the Timestamp / Date value, which is in UTC, converts it to the default time zone, and saves that to the database.



    虽然此处未指定 JDBC 驱动程序,但我怀疑这是它的行为。这种行为将与 Oracle DATE 的行为相矛盾。没有这种区域调整的类型。甲骨文 DATE类型(当我阅读文档时;我不是 Oracle 用户)是不可知的或不知道区域/偏移量。

    在 Java 中,类映射到 SQL 标准 TIMESTAMP WITHOUT TIME ZONE和 Oracle DATE LocalDateTime .您应该仅在以下三种情况下使用这些无区域类型:
  • 区域或偏移量未知 。这不好。这是错误的数据。类似于在不知道货币的情况下拥有价格/成本。您应该拒绝此类数据,而不是存储它。
  • 意图是“无处不在” ,就像每个时区一样。例如,公司政策规定“我们所有的工厂都将在 12:30 吃午饭”意味着德里的工厂会比杜塞尔多夫的工厂提前几个小时休息,而杜塞尔多夫的工厂比底特律的工厂提前几个小时.
  • 打算在 future 的特定时刻,但我们是 害怕政客重新定义时区 .政府以令人惊讶的频率和令人惊讶的方式改变其时区的规则little warning甚至 no warning at all .因此,如果您想在某个日期的下午 3 点进行预约,并且您的意思是下午 3 点,而不管政府在此期间可能做出任何疯狂的决定,那么请存储 LocalDateTime .要打印报告或显示日历,请动态应用时区 ( ZoneId ) 以生成特定时刻 ( ZonedDateTimeInstant )。这必须即时完成,而不是存储值。

  • What's exactly wrong with NOT adjusting and saving the value (UTC) as it is?



    JDBC 驱动程序不应针对某种类型的 Oracle Date 对 UTC 进行任何调整。或 SQL 标准 TIMESTAMP WITHOUT TIME ZONE .

    如果 2018-06-06T21:53Z 的两个用户,一个在魁北克,一个在印度,同时将他们自己狭隘的挂钟时间的当前时刻保存到 SQL 标准 TIMESTAMP WITHOUT TIME ZONE 类型的列中。或 Oracle DATE ,那么我们应该看到两行有值:
  • 2018-06-06T17:53(注意日期是“昨天”)
  • 2018-06-07T03:23(注意日期是“明天”)

  • 值不同,因为 America/Montreal比 UTC 晚四个小时,而 Asia/Kolkata比 UTC 早五个半小时,并且没有对时区进行调整。再次重复我自己,这里存储的值仅表示日期和时间,但没有任何时区上下文或 UTC 偏移量,它们不代表时刻。

    混淆可能来自这样一个事实,即某些数据库(例如 Postgres)确实将传入值调整为 UTC,以便将值指向不同类型的列, TIMESTAMP WITH TIME ZONE类型(注意 WITHWITHOUT )。 Postgres 和其他数据库使用任何传递的区域/偏移量信息来调整为 UTC 值,然后丢弃区域/偏移量信息。所以类型名有点用词不当,你可以把它想象成 TIMESTAMP WITH RESPECT FOR TIME ZONE .

    如果上面在 2018-06-06T21:53Z 看到的相同的两个用户将当前时刻保存到类型为 TIMESTAMP WITH TIME ZONE 的 SQL 标准列中,那么这两行将显示为:
  • 2018-06-06T21:53Z
  • 2018-06-06T21:53Z
  • Z最后是发音 Zulu并表示UTC。

    What is it trying to solve by adjusting the value before saving it to the database?



    通常,日期时间处理的最佳实践是在 UTC 而不是其他区域/偏移量中工作。

    作为程序员或系统管理员工作时,忘记你自己狭隘的时区。从您自己的区域到 UTC 或其他区域来回转换会让您筋疲力尽。 将 UTC 视为唯一的真实时间 ;所有其他区域都只是变化。

    Instant class 代表时间线上的一个时刻 UTC分辨率为 nanoseconds (最多九 (9) 位小数)。
    Instant instant = Instant.now() ;  // Capture the current moment in UTC. 

    店铺。
    String sql = "INSERT INTO tbl ( event ) VALUES ( ? ) ;" ;       // Writing a moment into a column of type `TIMESTAMP WTH TIME ZONE`.  
    myPreparedStatement.setObject( 1 , instant ) ; // As of JDBC 4.2 and later, we can directly exchange java.time objects with our database.

    取回。
    Instant instant = myResultSet.getObject( … , Instant.class ) ;

    在特定时区呈现那个时刻。
    ZoneId z = ZoneId.of( "Asia/Kolkat" ) ;
    ZonedDateTime zdt = instant.atZone( z ) ; // Same moment, same point on the timeline, different wall-clock time.

    关于 java.time

    java.time框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy日期时间类,例如 java.util.Date , Calendar , & SimpleDateFormat .

    Joda-Time项目,现在在 maintenance mode ,建议迁移到 java.time类。

    要了解更多信息,请参阅 Oracle Tutorial .并在 Stack Overflow 上搜索许多示例和解释。规范为 JSR 310 .

    您可以直接与您的数据库交换 java.time 对象。使用 JDBC driver符合 JDBC 4.2或以后。不需要字符串,不需要 java.sql.*类。

    从哪里获得 java.time 类?
  • Java SE 8 , Java SE 9 , Java SE 10 , 然后
  • 内置。
  • 具有捆绑实现的标准 Java API 的一部分。
  • Java 9 添加了一些小功能和修复。
  • Java SE 6Java SE 7
  • ThreeTen-Backport 中,大部分 java.time 功能被反向移植到 Java 6 和 7。 .
  • Android
  • 更高版本的 Android 捆绑实现 java.time 类。
  • 对于早期的 Android (<26),ThreeTenABP项目适应 ThreeTen-Backport (上文提到的)。见 How to use ThreeTenABP… .

  • ThreeTen-Extra项目使用附加类扩展 java.time。该项目是 future 可能添加到 java.time 的试验场。您可能会在这里找到一些有用的类,例如 Interval , YearWeek , YearQuarter , 和 more .

    关于java - 为什么JDBC在保存日期时会将时间调整为默认时区?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42777187/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com