Module java.base

Package java.time


package java.time

日期、时间、瞬间和持续时间的主要API。

此处定义的类代表主要的日期时间概念,包括瞬间、持续时间、日期、时间、时区和时段。它们基于ISO日历系统,这是遵循推测格里高利规则的事实世界日历。所有类都是不可变的且线程安全的。

每个日期时间实例由API方便地提供的字段组成。要访问字段的较低级别,请参考java.time.temporal包。每个类都包括支持打印和解析各种日期和时间的功能。有关自定义选项,请参考java.time.format包。

java.time.chrono包包含与日历无关的API ChronoLocalDateChronoLocalDateTimeChronoZonedDateTimeEra。这适用于需要使用本地化日历的应用程序。建议应用程序在系统边界(例如数据库或网络)之间使用此包中的ISO-8601日期和时间类。应将与用户交互的日历中立API保留给用户交互。

日期和时间

Instant本质上是一个数字时间戳。可以从Clock中检索当前Instant。这对于记录和持久化时间点很有用,过去曾与存储System.currentTimeMillis()的结果相关联。

LocalDate存储没有时间的日期。这样存储日期,如'2010-12-03',可以用来存储生日。

LocalTime存储没有日期的时间。这样存储时间,如'11:30',可以用来存储开放或关闭时间。

LocalDateTime存储日期和时间。这样存储日期时间,如'2010-12-03T11:30'。

ZonedDateTime存储带有时区的日期和时间。如果要进行准确的日期和时间计算,考虑到ZoneId,如'Europe/Paris',这很有用。在可能的情况下,建议使用不带时区的简单类。广泛使用时区会给应用程序增加相当大的复杂性。

持续时间和时段

除了日期和时间,API还允许存储时间段和持续时间。Duration是时间线上的简单时间度量,以纳秒为单位。Period表示人类有意义的时间量,如年或天。

附加值类型

Month单独存储一个月份。这样单独存储一年中的一个月,如'DECEMBER'。

DayOfWeek单独存储一周中的一天。这样单独存储一周中的一天,如'TUESDAY'。

Year单独存储一年。这样单独存储一年,如'2010'。

YearMonth存储一年和一个月,没有日期或时间。这样存储一年和一个月,如'2010-12',可以用于信用卡到期日。

MonthDay存储一个月和一天,没有年份或时间。这样存储一个月和一个月中的某一天,如'--12-03',可以用于存储类似生日这样的年度事件,而不存储年份。

OffsetTime存储时间和与UTC的偏移,没有日期。这样存储时间,如'11:30+01:00'。ZoneOffset的形式为'+01:00'。

OffsetDateTime存储日期、时间和与UTC的偏移。这样存储日期时间,如'2010-12-03T11:30+01:00'。这在XML消息和其他形式的持久化中有时会出现,但包含的信息比完整时区少。

包规范

除非另有说明,在此包中的任何类或接口的构造函数或方法中传递空参数将导致抛出NullPointerException。Javadoc的“@param”定义用于总结空值行为。在每个方法中未明确记录“@throws NullPointerException”。

所有计算应检查数值溢出,并抛出ArithmeticExceptionDateTimeException

设计注记(非规范性)

API被设计为尽早拒绝空值并明确说明此行为。一个关键例外是任何接受对象并返回布尔值的方法,用于检查或验证,通常会对空值返回false。

API被设计为在主要高级API中合理地具有类型安全性。因此,对于日期、时间和日期时间的不同概念,有单独的类,以及用于偏移和时区的变体。这可能看起来有很多类,但大多数应用程序可以从仅使用五种日期/时间类型开始。

  • Instant - 时间戳
  • LocalDate - 没有时间的日期,或任何偏移或时区的参考
  • LocalTime - 没有日期的时间,或任何偏移或时区的参考
  • LocalDateTime - 结合日期和时间,但仍没有偏移或时区
  • ZonedDateTime - 带有时区和从UTC/Greenwich解析的“完整”日期时间

Instantjava.util.Date的最接近等效类。ZonedDateTimejava.util.GregorianCalendar的最接近等效类。

在可能的情况下,应用程序应使用LocalDateLocalTimeLocalDateTime更好地建模领域。例如,生日应存储在LocalDate中。请记住,任何使用时区,如'Europe/Paris',都会给计算增加相当大的复杂性。许多应用程序只能使用LocalDateLocalTimeInstant编写,时区添加到用户界面(UI)层。

基于偏移的日期时间类型OffsetTimeOffsetDateTime,主要用于网络协议和数据库访问。例如,大多数数据库无法自动存储像'Europe/Paris'这样的时区,但可以存储像'+02:00'这样的偏移。

还提供了用于日期的最重要子部分的类,包括MonthDayOfWeekYearYearMonthMonthDay。这些可以用于建模更复杂的日期时间概念。例如,YearMonth用于表示信用卡到期日。

请注意,虽然有大量表示日期不同方面的类,但处理时间不同方面的类相对较少。将类型安全性推向逻辑结论将导致为小时-分钟、小时-分钟-秒和小时-分钟-秒-纳秒的每个组合创建单独的类。虽然在逻辑上是纯粹的,但这不是一个实际的选择,因为由于日期和时间的组合,这将使类的数量几乎增加三倍。因此,LocalTime用于所有时间精度,使用零来表示较低精度。

将完全的类型安全性推向最终结论也可能会要求为日期时间中的每个字段创建单独的类,例如为HourOfDay创建一个类,为DayOfMonth创建另一个类。尝试了这种方法,但在Java语言中过于复杂,缺乏可用性。周期也存在类似问题。有理由为每个周期单位创建单独的类,例如为Years创建一个类型,为Minutes创建一个类型。但这会产生大量类和类型转换问题。因此,提供的日期时间类型集是纯粹性和实用性之间的折衷。

API在方法数量方面具有相对较大的表面积。通过使用一致的方法前缀,这变得可管理。

  • of - 静态工厂方法
  • parse - 专注于解析的静态工厂方法
  • get - 获取某物的值
  • is - 检查某物是否为真
  • with - 不可变的设置器等效方法
  • plus - 将一定量添加到对象
  • minus - 从对象中减去一定量
  • to - 将此对象转换为另一种类型
  • at - 将此对象与另一个对象组合,如date.atTime(time)

多个日历系统是设计挑战中的一个尴尬添加。第一原则是大多数用户希望标准的ISO日历系统。因此,主要类仅限于ISO。第二原则是大多数希望非ISO日历系统的用户希望用于用户交互,因此这是一个UI本地化问题。因此,日期和时间对象应作为ISO对象保存在数据模型和持久存储中,仅在显示时转换为本地日历。日历系统将单独存储在用户首选项中。

然而,有一些有限的使用情况,用户认为他们需要在整个应用程序中存储和使用任意日历系统中的日期。这得到了ChronoLocalDate的支持,但在使用之前,务必阅读该接口的Javadoc中的所有相关警告。总的来说,需要在多个日历系统之间进行一般互操作的应用程序通常需要以非常不同的方式编写,因此大多数应用程序应该只使用ISO并避免ChronoLocalDate

该API还设计用于用户可扩展性,因为有许多计算时间的方式。通过TemporalAccessorTemporal访问的fieldunit API为应用程序提供了相当大的灵活性。此外,TemporalQueryTemporalAdjuster接口提供了日常强大的功能,允许代码接近业务需求:

   LocalDate customerBirthday = customer.loadBirthdayFromDatabase();
   LocalDate today = LocalDate.now();
   if (customerBirthday.equals(today)) {
     LocalDate specialOfferExpiryDate = today.plusWeeks(2).with(next(FRIDAY));
     customer.sendBirthdaySpecialOffer(specialOfferExpiryDate);
   }

 
自Java 1.8开始:
1.8
  • Class
    Description
    提供了一个时钟,可以使用时区访问当前时刻、日期和时间。
    用于指示计算日期时间时出现问题的异常。
    一周中的某一天,例如“星期二”。
    基于时间的时间量,例如“34.5秒”。
    时间线上的瞬时点。
    提供对当前时刻的访问。
    在ISO-8601日历系统中没有时区的日期,例如2007-12-03
    在ISO-8601日历系统中没有时区的日期时间,例如2007-12-03T10:15:30
    在ISO-8601日历系统中没有时区的时间,例如10:15:30
    一年中的某个月份,例如“七月”。
    ISO-8601日历系统中的月日,例如--12-03
    在ISO-8601日历系统中带有与UTC/Greenwich的偏移量的日期时间,例如2007-12-03T10:15:30+01:00
    在ISO-8601日历系统中带有与UTC/Greenwich的偏移量的时间,例如10:15:30+01:00
    ISO-8601日历系统中的基于日期的时间量,例如“2年3个月4天”。
    ISO-8601日历系统中的一年,例如2007
    ISO-8601日历系统中的年月,例如2007-12
    在ISO-8601日历系统中带有时区的日期时间,例如2007-12-03T10:15:30+01:00 Europe/Paris
    时区ID,例如Europe/Paris
    与格林威治/UTC的时区偏移量,例如+02:00