Joda-Time:DateTime、DateMidnight 和 LocalDate 用法java.time关于 java.time

2022-09-01 10:13:38

Joda-Time 库包括不同的日期时间类

DateTime - JDK Calendar
DateMidnight 的不可变替换 - 表示时间强制为午夜
的日期的不可变类 LocalDateTime - 表示本地日期和时间(无时区)的不可变类

我想知道您如何在分层应用程序中使用这些类。

我看到了让几乎所有接口都使用LocalDateTime(至少在服务层)的优势,这样我的应用程序就不必管理时区,并且可以安全地假设Times始终采用UTC。然后,我的应用可以使用 DateTime 在执行流的最开始管理时区。

我也想知道在哪种情况下可以使用DateMidnight。


答案 1

我看到了让几乎所有接口都使用LocalDateTime(至少在服务层)的优势,这样我的应用程序就不必管理时区,并且可以安全地假设Times始终采用UTC。

我不确定我是否理解你在这里的思路。 并表示两个完全不同的概念。a具有一些隐式UTC时区的情况并非如此:它实际上没有时区(在内部,它可能表示为具有UTC时区,但它只是一个实现细节,对于使用它的程序员来说无关紧要)。LocalDateTimeDateTimeLocalDateTimeDateTime

您可以在API文档中看到,虽然DateTime是“即时”(世界时间线中的一个点,一个物理概念),但LocalDateTime不是这样的东西。它实际上是一个部分(一个“民事”概念),在不同的阶级层次结构中。不幸的是,类名称可能会让你认为这是一些专业化:好吧,它不是。LocalDateTimeLocalDateTimeDateTime

LocalDateTime 应被视为一对 {Date () ;时间()},一堆数字,对应于时间相关数据的“民事”标准表示。如果我们被赋予一个,我们不能直接将其转换为,我们需要指定一个时区;这种转换将我们带到另一种实体。(打个比方:Java中的字符串和字节流:要在它们之间转换,必须指定字符集编码,因为它们在概念上是不同的东西)Y/M/Dhh:mm:ss.msecLocalDateTimeDateTime

何时在应用程序中使用一个或另一个...它有时是有争议的,但一旦Jodatime概念被理解,它通常就足够清楚了。IMO与“层”的关系不大,也许更多的是用例或场景。

一个不平凡的边界示例:你在谷歌工作,为日历编程。您必须让用户管理(添加,查看,修改)包含日期时间的事件(让我们忽略经常性事件),并说“我在2019年7月3日上午10:00与我的医生预约”。在软件层中使用的时间日期实体是什么(对于此用例)?我会说:a.因为用户实际上不是在处理物理时间点,而是在处理文明时间:在他的手腕或家中显示时钟的日期和时间。他甚至不会想到时区(让我们忽略环游世界的用户的特殊情况......然后,在业务和表示层中,似乎是正确的实体。LocalDateTimeLocalDateTime

但假设您还必须编写一个不同的方案:提醒。当Google内部调度程序检测到用户存储的事件是从现在开始的将来的N分钟时,它必须向他发送提醒。在这里,“从现在开始的N分钟”是一个完全“物理”的时间概念,所以这里的“业务层”将处理一个.有几种替代方法,例如:事件作为一个存储在数据库中(即只有时间和日期而没有时区 - 人们经常使用UTC时间戳来表示它,但这是一个实现细节)。在这种情况下(仅在此情况下),我们必须将其加载为 ,我们使用时区(可能来自用户的配置文件)对其进行转换。DateTimeLocalDateTimeDateTime


答案 2

莱昂布洛伊的答案是正确的,也是至关重要的。我只是在翻译取代Joda-Time项目的java.time类。

java.time

特定时刻

对于时间轴上的特定时刻:

  • 始终采用 UTC 由即时表示。
  • 分配的偏移量来自 UTC 由 OffsetDateTime 表示。
  • 分配一个完整的时区,而不仅仅是偏移量,由 ZonedDateTime 表示。

这些都取代了Joda-Time中的&class。这些java.time类的分辨率都是纳秒,而Joda-Time使用的毫秒。InstantDateTime

午夜与一天的开始

对于午夜,Joda-Time项目得出结论,“午夜”是一个模糊且无用的概念。与午夜相关的课程和午夜在后来的Joda-Time版本中都被弃用,取而代之的是“一天中的第一刻”的实际概念。

java.time课程也上了同样的课,使用了“一天中的第一刻”方法。在 java.time 类(如 .atStartOfDayLocalDate

永远不要假设一天从00:00开始。夏令时 (DST) 等异常情况意味着一天可能在其他时间(如 01:00)开始。

ZonedDateTime zdt = 
    LocalDate.of( 2017 , Month.MARCH , 12 )                    // Instantiate a date-only value without time zone.
             .atStartOfDay( ZoneId.of( "America/Havana" ) ) ;  // Cuba jumps from 00:00 to 01:00 on Spring DST cut-over.

例如,了解古巴如何在春季夏令时切换的凌晨 1 点开始新的一天。

zdt: 2017-03-12T01:00-04:00[美国/哈瓦那]

未分区

要表示大约26-27小时范围内可能时刻的模糊概念,而不是时间轴上的实际时刻,请使用 。此类故意缺少任何与 UTC 或时区的偏移量。LocalDateTime

LocalDateTime ldt = LocalDateTime.of( 2017 , Month.JANUARY , 23 , 1 , 2 , 3 , 0 ) ;

如果您的业务环境暗示了特定的时区,则可以应用它来获得 .ZonedDateTime

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;  // Determine a specific point on timeline by providing the context of a time zone.

关于 java.time

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

Joda-Time 项目现在处于维护模式,建议迁移到 java.time 类。

要了解更多信息,请参阅 Oracle 教程。搜索 Stack Overflow 以获取许多示例和解释。规格是JSR 310

从哪里获取 java.time 类?

ThreeTen-Extra 项目通过其他类扩展了 java.time。这个项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuarter