当前位置: 首页 > 知识库问答 >
问题:

序列化java.sql。计算夏令时时通过Jackson的日期

龙佐
2023-03-14

我使用的是<code>java.sql。Date将日期字段存储在我的一个域对象中。此字段映射到MySQL<code>DATE</code>列。当我试图通过Jackson将该字段序列化为JSON时,Jackson似乎没有考虑夏时制。

下面是我的域对象中的字段:

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd", timezone = "EST")
private Date date;

如您所见,杰克逊已被指示将时区解释为EST。我的MySQL数据库也使用EST时区:

SHOW VARIABLES LIKE '%zone';
Output:
system_time_zone | EST
time_zone        | SYSTEM

我的问题是,对于夏令时开始和结束之间的日期,Jackson返回的日期比存储在html" target="_blank">数据库中的日期少一天。我假设这是因为Jackson没有考虑夏令时。

我通过尝试在 Java 字段中将日期的格式从 yyyy-MM-dd 更改为 yyyy-MM-dd HH:mm:ss 得出了这个结论。我注意到服务器返回了类似 2017-03-13 00:00:00 的内容,但 Jackson 将其序列化为 2017-03-12 23:00:00(少一小时,这是夏令时对 EST 时间的影响)。

有什么办法克服这个问题吗?还有<code>java.sql。日期考虑到它没有对应的时间,是否使用正确的类型?我一直在考虑使用<code>java.time。改为LocalDate</code>,但我还不知道它是否会成功。

提前感谢!

共有1个答案

江温书
2023-03-14
    < li >切勿使用< code>java.sql.Date或< code>java.util.Date。< br >仅使用java.time类。 < li >对于仅包含日期的值,请使用< code>LocalDate。< br >您只会看到稳定的值,不受夏令时(DST)的影响。

例子:

LocalDate.parse( "2019-01-23" )

我不确定问题到底是什么,但我怀疑这是由于您使用了糟糕的java.sql.Date类,因此没有意义。

java.sql.Date类假装表示仅日期值,没有时间和时区。然而,由于一些难以想象的糟糕设计决策,该类扩展了java.util.Datejava.util.Date类确实有一天中的时间,并且是UTC。更令人困惑的是,java.util.Date在其源代码中隐藏了一个没有getter的时区

引用<code>java.sql的JavaDoc。日期类别:

毫秒值周围的一个薄薄的包装,允许JDBC将它识别为SQL日期值。毫秒值表示自1970年1月1日00:00:00.000 GMT以来经过的毫秒数。

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

顺便说一下,< code>java.sql.Timestamp也一样糟糕。它也笨拙地继承了< code>java.util.Date,为纳秒增加了一秒。也要避免这个类,现在用< code>java.time.Instant或< code > Java . time . offsetdatetime 代替。类似地,< code>java.sql.Time被替换为< code>java.time.LocalTime。

随着JSR 310和JDBC 4.2的采用,您可以使用现代业界领先的java.time类。到现在为止,Jackson可能已经更新到使用java.time了,如果没有,请参见这个问题,获取在Jackson中处理java.time的数据类型模块的链接。

看起来您的输入字符串采用标准 ISO 8601 格式,YYYY-MM-DD。java.time 类在解析/生成表示日期时间值的字符串时默认使用标准格式。对于仅日期使用,LocalDate 类确实是一个没有时间且没有区域/偏移量的日期。您将看到稳定的日期值,而不受夏令时 (DST) 的影响。

解析。

LocalDate ld = LocalDate.parse( "2019-01-23" ) ;

商店。

myPreparedStatement.setObject( … , ld ) ;

取回。

LocalDate ld = myResultSet.getObject( … , LocalDate.class ) ;

LocalDate类表示一个只包含日期的值,没有一天中的时间,也没有时区或与UTC的偏移量。

时区对确定日期至关重要。在任何特定时刻,日期在全球各地因地区而异。例如,法国巴黎午夜过后几分钟是新的一天,而魁北克蒙特利尔仍然是“昨天”。

如果没有指定时区,JVM将隐式应用其当前的默认时区。该默认值可能会在运行时的任何时刻发生变化。),因此您的结果可能会有所不同。最好将您想要/预期的时区明确指定为一个参数。如果非常重要,请与您的用户确认该区域。

以大陆/地区格式指定正确的时区名称,例如美洲/蒙特利尔、非洲/卡萨布兰卡太平洋/奥克兰切勿使用 2-4 个字母的缩写,例如 ESTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

ZoneId z = ZoneId.of( "America/Montreal" ) ;  
LocalDate today = LocalDate.now( z ) ;

如果您想使用JVM的当前默认时区,请询问它并作为参数传递。如果省略,代码将变得模棱两可,因为我们无法确定您是否打算使用默认值,或者您是否像许多程序员一样不知道这个问题。

ZoneId z = ZoneId.systemDefault() ;  // Get JVM’s current default time zone.

或指定日期。你可以用一个数字来设定月份,其中1-12是一月到十二月的数字。

LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ;  // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.

或者,更好的是使用预定义的 Month 枚举对象,一年中的每个月一个。提示: 在整个代码库中使用这些 Month 对象,而不仅仅是整数,以使代码更具自我文档性、确保有效值并提供类型安全性。同上 年份

LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;

java.time框架内置于Java8及更高版本中,这些类取代了麻烦的旧遗留日期时间类,如java.util.Date日历

要了解更多信息,请参阅Oracle教程。并搜索堆栈溢出以获得许多示例和解释。规范为JSR 310。

现在处于维护模式的JodaTime项目建议迁移到java。时间课程。

你可以交换java。时间对象直接与数据库关联。使用符合JDBC 4.2或更高版本的JDBC驱动程序。不需要字符串,也不需要<code>java.sql* 类。

从哪里获得java.time类?

    Java SE 8、Java SE 9、Java SE
  • 10、Java SE 11 及更高版本 - 标准 Java API 的一部分,具有捆绑实现。
    • Java 9添加了一些小功能和修复。
    • 大部分java。时间功能后移植到Java 6
    • Android的更高版本捆绑了java的实现。时间课程
    • 对于早期的Android(

    ThreeTen-Extra项目用额外的类扩展了java.time。这个项目是java.time未来可能增加的内容的试验场。您可能会在这里找到一些有用的类,如< code>Interval 、< code>YearWeek 、< code>YearQuarter等等。

 类似资料:
  • 轻触方格启用设定,即可将夏令时反映于时间显示中。

  • 问题内容: 中欧夏令时开始于三月的最后一个星期日。我们将时钟设置为02:00到03:00。如果我在数据库请求中进行时间戳计算会发生什么?比方说,在01:59? 结果是03:00还是02:00? 如果我们将时钟设置为03:00到02:00,那结束了呢? 时间从03:00更改为02:00之后…在02:00会发生什么?是02:59还是01:59? 应该如何处理?最佳实践以及Oracle Database

  • 问题内容: 我正在编写一个处理很多时区并跨越时区的程序。我最常处理的两件事是从“ now”创建一个datetime对象,然后本地化一个朴素的datetime对象。 要从现在开始在太平洋时区创建datetime对象,我目前正在执行此操作(python 2.7.2+) 关于DST,这是否正确?如果没有,我想应该这样做: 我的问题是为什么?谁能告诉我第一个错误而第二个秒正确的情况? 至于我的秒数问题,假

  • 我正在尝试使用Jackson将ISO8601格式的日期反序列化为Java8。我向ObjectMapper注册了JavaTimeModule,并关闭了设置。 但是,如果试图反序列化将不起作用,因为JavaTimeModule似乎只会反序列化使用UTC时区偏移量格式化的日期时间(例如)。然后我尝试使用注释,如下所示: 就像这样: 然而,这两种方法都不起作用,我得到了一个例外: 这意味着timezone

  • 问题内容: 我想知道用Java最简单的方法来获取将来的夏令时将改变的日期列表。 一种相当灵活的方法是简单地迭代一整年的时间,然后对它们进行TimeZone.inDaylightTime()测试。这将起作用,并且我不担心效率,因为这仅在我的应用每次启动时都需要运行,但是我想知道是否有更简单的方法。 如果您想知道为什么要这样做,那是因为我有一个javascript应用程序,该应用程序需要处理包含UTC

  • 问题内容: 如何检查夏令时是否有效? 问题答案: 您可以使用并查看返回值中的标志。 使用,您可以在任意时间问相同的问题,以了解DST在当前时区是否有效。