我们有一堆代码,它们从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.Date
、java.util.Calendar
、java.text.SimpleDateFormat
、java.sql.Timestamp
和java.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/Montreal
、Africa/Casablanca
或Pacific/Auckland
。千万不要使用3-4个字母的缩写,如EST
或IST
,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。
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.Date
、Calendar
、&CCD_ 30。
现在处于维护模式的JodaTime项目建议迁移到java.Time类。
要了解更多信息,请参阅Oracle教程。并在Stack Overflow中搜索许多示例和解释。规范是JSR310。
您可以直接与数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC驱动程序。不需要字符串,也不需要java.sql.*
类。
从哪里获得java.time类?
- Java SE 8、Java SE 9和更高版本
- 内置
- 标准Java API的一部分,带有捆绑实现
- Java 9添加了一些小功能和修复程序
- Java SE 6和Java SE 7
- 大部分Java.time功能都是向后移植到Java 6&7英寸ThreeTen背包
- Android
- java.time类的Android捆绑包的后续版本
- 对于早期的Android(<26),ThreeTenABP项目适用于ThreeTen Backport(如上所述)。请参阅如何使用ThreeTenABP…
ThreeTen Extra项目通过附加类扩展java.time。这个项目是将来可能添加到java.time的试验场。您可以在这里找到一些有用的类,如Interval
、YearWeek
、YearQuarter
等等。