首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >当我从数据库中读取TimeZone of java.sql.Date时,如何考虑它?

当我从数据库中读取TimeZone of java.sql.Date时,如何考虑它?
EN

Stack Overflow用户
提问于 2020-04-21 17:03:29
回答 1查看 698关注 0票数 0

我的应用程序从包含美国/纽约时区(-4 UTC)中的这些日期的数据库中读取java.sql.Date。在获取数据之后,Hibernate创建对象java.sql.Date,并在本地时区中表示它们。因此,我需要从UTC的数据库直接转换数据。我怎么能这么做?

我需要这样的东西

代码语言:javascript
复制
Instant.ofEpochMilli(((java.sql.Date) value).getTime()).atOffset(offset);

但是偏置没有做我想做的事情。例如:

数据库时间: 01-02-2020 22:00 (在美国/纽约->,它是UTC-4,我需要多加4小时)

我的应用时间: 01-02-2020 22:00 +4 (因为我的时区是UTC+4)。当我设置ZoneOffset.UTC时

代码语言:javascript
复制
Instant.ofEpochMilli(((java.sql.Date) value).getTime()).atOffset(ZoneOffset.UTC)

它删除4小时的ans toString()结果= 01-02-2020T16:00Z。

如何在数据库中添加4小时至今(java.sql.Date),使其成为02-02-2020 02:00 UTC?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-04-22 04:56:57

对于一个时区的时间点,如2020-02-01T22:00-04:00 00America/New_York,请不要使用java.sql.Date。原因有二:

  1. java.sql.Date是一个设计很差的类,实际上是一个真正的黑客,如果已经设计糟糕的java.util.Date类在上面的话。幸运的是,两个outdated.
  2. java.sql.Date类都是长的,Date是为一天中没有时间的日期而设计的。

相反:

SQL数据库中的

  • 使用timestamp with time zone,并在UTC中一致地存储时间。因此,存储在数据库中的时间应该是2020-02-02T02:00Z (Z )。
  • 在Java中将您的时间检索到一个OffsetDateTime中(因为JDBC4.2,我们可以完全绕过java.sql.Datejava.sql.Timestamp )。然后,如果需要,在您的时区转换为ZonedDateTime。使用区域/城市格式的适当时区ID (而不仅仅是您认为UTC偏移量是什么)。

为了示威:

代码语言:javascript
复制
    ZoneId zone = ZoneId.of("Asia/Tbilisi");

    OffsetDateTime dateTimeFromDatabase
            = OffsetDateTime.of(2020, 2, 2, 2, 0, 0, 0, ZoneOffset.UTC);
    ZonedDateTime dateTimeInYourTimeZone
            = dateTimeFromDatabase.atZoneSameInstant(zone);
    System.out.println(dateTimeInYourTimeZone);

输出:

2020-02-02T06:00+04:00亚洲/第比利斯

编辑1:你说过:

我知道使用过时的java.sql.Date是不好的,但我别无选择。"java.sql.Date是为一天中没有时间的日期而设计的。“--但我想我还是可以通过调用(java.sql.Date)值.getTime()(因为它返回时间戳)来获得一天中的时间。

从文件中:

为了符合SQL的定义,java.sql.Date实例包装的毫秒值必须通过将实例关联的特定时区中的小时、分钟、秒和毫秒设置为零来“规范化”。

所以在我看来你违反了合同。后果如何我不知道。它们可能依赖于JDBC驱动程序。也就是说,行为可能会随着下一个版本的JDBC驱动程序而改变。

编辑2:我仔细观察了你的数据。我同意您的看法,它们是错误的;但问题不在于您所提供的代码,而是您似乎收到的java.sql.Date对象。

为了我的调查我做了:

代码语言:javascript
复制
    // time in database: 01-02-2020 22:00
    // (in America/New_York -> it's UTC-4 and I need to add extra 4 hours)
    ZonedDateTime dateTimeInDatebase = ZonedDateTime
            .of(2020, 2, 1, 22, 0, 0, 0, ZoneId.of("America/New_York"));
    System.out.println("In database:     " + dateTimeInDatebase);
    long correctEpochMillis = dateTimeInDatebase.toInstant().toEpochMilli();
    System.out.println("Correct millis:  " + correctEpochMillis);

    // toString() result = 01-02-2020T16:00Z
    OffsetDateTime observedDateTime
            = OffsetDateTime.of(2020, 2, 1, 16, 0, 0, 0, ZoneOffset.UTC);
    long observedEpochMilli = observedDateTime.toInstant().toEpochMilli();
    System.out.println("Observed millis: " + observedEpochMilli);

    Duration error = Duration.between(dateTimeInDatebase, observedDateTime);
    System.out.println("Error:           " + error);

产出如下:

数据库中的

:2020-02-01T22:00-05:00美国/纽约正确米利斯: 1580612400000观测米利斯: 1580572800000错误: PT-11H

意见:

time/DST).

  • The
  1. 2月份在纽约的UTC偏移量不是-04:00,而是-05:00 (-04:00是夏季的正确偏移量-04:00,您从java.sql.Date中检索到的毫秒值并不表示它应该的时间点。在您的代码中没有任何东西可以改变时间点。因此,您不仅得到了不正确的类型,还得到了一个不正确的值。
  2. 将最后一行中打印的错误读取为- 11小时的时间。java.sql.Date中的毫秒值早了11个小时。

你已经解释了一些与时区差异的差异,我相信这是真的。我们还没有证实这是整个故事。所以我也不能告诉你解决方案是什么。除了向提供者提交不正确类型和值的票证外,您还可以得到正确的数据。一个可能的黑客是增加11个小时,当然,但你是否应该增加10个小时在夏季时间的一部分一年-我不是正确的人问。

编辑3:

,我刚刚想出了一个方法来修正时间戳的两倍值。类似于本地区域的第一次添加偏移量(修复jdbc驱动程序的影响),以及存储在数据库中的日期的第二个句柄偏移量。

如果我们愿意的话,我们可以这样做:

代码语言:javascript
复制
    Instant observedResult = Instant.parse("2020-02-01T16:00:00Z");
    Object receivedValue = new java.sql.Date(observedResult.toEpochMilli());

    long receivedEpochMillis = ((java.sql.Date) receivedValue).getTime();
    ZonedDateTime adjustedDateTime = Instant.ofEpochMilli(receivedEpochMillis)
            .atZone(ZoneId.systemDefault())
            .withZoneSameLocal(ZoneId.of("America/New_York"));

    System.out.println(adjustedDateTime);

在亚洲/第比利斯时区运行时输出(这是ZoneId.systemDefault()返回的输出;全年的偏移量为+04:00 ):

2020-02-01T20:00-05:00美国/纽约

它让我们更接近你所说的数据库,但还早了几个小时。我很抱歉。

链接

一起使用

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61349029

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档