获取 JDBC 和 Saxon DateTime 数据作为 ZonedDateTime 对象



我们有一堆代码,它们从JDBC、Saxon(XPath)、dom4j、jway json路径(JPath)和;OData作为Date对象。我们现在学习Java 1.8,我的第一个问题是,我想现在尝试获取以前作为Date对象获取的任何数据,现在将其作为ZonedDateTime对象获取吗?或者我应该用别的东西?

我的第二个问题是,如何将JDBC、Saxon等中的数据作为ZonedDateTime对象读取?

tl;dr

  • 永远不要使用遗留类,只使用java.time
  • 如果必须,请使用添加到旧类中的新方法进行转换
  • 从JDBC 4.2开始,与数据库交换java.time对象,而不是字符串或java.sql类型
  • 在UTC中完成大部分工作。调整到时区仅用于演示
  • 将日期时间值作为文本进行通信时,请使用ISO 8601格式
  • 搜索堆栈溢出以获取更多信息

避免遗留日期时间类

非常麻烦的旧日期时间类,如java.util.Datejava.util.Calendarjava.text.SimpleDateFormatjava.sql.Timestampjava.sql.Date,都被java.time类完全取代了再也不用碰那些糟糕的旧课了

java.time类已经与Java8及更高版本捆绑了几年。他们已经证明自己是一个可靠的、业界领先的日期时间工作框架。他们从优秀的Joda Time项目(现在处于维护模式)中汲取了经验教训。因此,java.time类具有"古老的灵魂",并且不是一些有限的"1.0"草稿。

转换

为了与尚未更新到java.time类的旧代码进行互操作,您可以轻松地在遗留类和现代类之间来回转换。对于转换,请查看添加到旧类中的新方法。阅读此类问题以了解更多信息。

数据库

从JDBC 4.2及更高版本开始,您可以直接与数据库交换java.time对象。再也不需要为日期时间值使用设计糟糕的java.sql类了。

对于类似于SQL标准TIMESTAMP WITH TIME ZONE的类型的列中的值,通常最好使用Instant

myPreparedStatement.setObject( … , instant ) ;

以及检索。

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

ISO 8601

在JVM之外交换日期-时间值时,请使用标准ISO8601格式序列化为文本。这些格式被设计为有用且实用,易于机器解析,易于跨文化的人类阅读。

在解析/生成字符串时,java.time类默认使用ISO8601格式。ZonedDateTime类通过明智地将区域名称附加在方括号中来扩展标准。

分区

我过去作为Date对象获取的

数据现在作为ZonedDateTime对象获取?

java.util.Date类直接替换为Instant。两者都表示UTC中的一个时刻。现代类解析为纳秒而不是毫秒。

Instant instant = myJavaUtilDate.toInstant() ;  // Convert from legacy class to modern. 

在Postgres等数据库中,TIMESTAMP WITH TIME ZONE类型的列实际上不保存时区。相反,数据库会使用传入值传递的任何偏移量或区域来调整为UTC。生成的UTC时刻被保存到数据库中,并且原始区域/偏移被丢弃。如果需要原始分区/偏移,则必须手动将其保存到额外的列中。

因此,通常最好在时间轴上用数据库传递和获取Instant对象。

要了解时间线上日期时间而非的概念,请搜索LocalDateTime类,并阅读类似以下问题的帖子,Instant和LocalDateTime之间有什么区别

请注意,SQL标准几乎没有涉及到日期时间处理这一棘手的主题。它定义了一些类型,但很少涉及行为。因此,数据库在实现中差异很大。一定要进行研究和实验,以验证您对数据库和驱动程序的理解。

是否将JDBC、Saxon等中的数据作为ZonedDateTime对象读取?

通常,最佳做法是在UTC工作。这意味着Instant类而不是ZonedDateTime类。

如果接收到Date,则如上所示转换为Instant

通常,您希望在UTC中完成业务逻辑、存储、交换、日志记录和跟踪/调试。仅在业务要求或向用户演示时应用时区。

有了Instant,您可以通过指定时区来调整特定地区的人们使用的挂钟时间。应用ZoneId可获得ZonedDateTime

continent/region的格式指定适当的时区名称,例如America/MontrealAfrica/CasablancaPacific/Auckland。千万不要使用3-4个字母的缩写,如ESTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

搜索堆栈溢出

你的问题实际上是许多其他类似问题的重复。我建议您在Stack Overflow中搜索各种java.time类名。你会学到很多,因为已经发布了很多问题和答案。

兼容的库

许多Java库已经更新为使用Java.time类型。

查看您可能使用的库的最新版本,并阅读它们的文档以了解添加的支持。

如果不直接支持,接受转换器/格式化程序/插件的库可能已经编写了一些java.time。搜索它们,或者在姐妹网站上询问:软件推荐堆栈交换。


关于java.time

java.time框架构建在Java8及更高版本中。这些类取代了诸如java.util.DateCalendar、&CCD_ 30。

现在处于维护模式的JodaTime项目建议迁移到java.Time类。

要了解更多信息,请参阅Oracle教程。并在Stack Overflow中搜索许多示例和解释。规范是JSR310。

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

从哪里获得java.time类?

  • Java SE 8Java SE 9和更高版本
    • 内置
    • 标准Java API的一部分,带有捆绑实现
    • Java 9添加了一些小功能和修复程序
  • Java SE 6Java SE 7
    • 大部分Java.time功能都是向后移植到Java 6&7英寸ThreeTen背包
  • Android
    • java.time类的Android捆绑包的后续版本
    • 对于早期的Android(<26),ThreeTenABP项目适用于ThreeTen Backport(如上所述)。请参阅如何使用ThreeTenABP…

ThreeTen Extra项目通过附加类扩展java.time。这个项目是将来可能添加到java.time的试验场。您可以在这里找到一些有用的类,如IntervalYearWeekYearQuarter等等。

最新更新