模块  java.base

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 (例如“欧洲/巴黎”)执行日期和时间的准确计算,这将非常有用。 在可能的情况下,建议使用没有时区的更简单的类。 时区的广泛使用往往会给应用程序增加相当大的复杂性。

持续时间和期限

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

其他值类型

Month自己存储一个月。 这样可以隔离单个月份,例如“DECEMBER”。

DayOfWeek自己存储一周中的某一天。 这样可以隔离存储一个星期几,例如“星期二”。

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消息和其他形式的持久性中找到它,但包含的信息少于完整时区。

包装规格

除非另有说明,否则将null参数传递给此包中任何类或接口中的构造函数或方法将导致抛出NullPointerException Javadoc“@param”定义用于概括null行为。 每个方法都没有明确记录“ @throws NullPointerException ”。

所有计算都应检查数字溢出并抛出ArithmeticExceptionDateTimeException

设计说明(非规范性)

API旨在尽早拒绝null,并清楚这种行为。 一个关键的例外是任何获取对象并返回布尔值的方法,为了检查或验证,通常会返回false为null。

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

  • Instant - 时间戳
  • LocalDate - 没有时间的日期,或对偏移或时区的任何引用
  • LocalTime - 没有日期的时间,或对偏移或时区的任何引用
  • LocalDateTime - 结合日期和时间,但仍然没有任何偏移或时区
  • ZonedDateTime - “完整”日期时间,带有时区和已解决的UTC /格林威治偏移量

Instant是最接近的等效类java.util.Date ZonedDateTime是与ZonedDateTimejava.util.GregorianCalendar

如果可能的话,应用程序应该使用LocalDateLocalTimeLocalDateTime域更好的模型。 例如,生日应存储在代码LocalDate 请记住,任何使用time-zone (例如“欧洲/巴黎”)都会增加计算的复杂性。 许多应用程序只能使用被写入LocalDateLocalTimeInstant ,与在用户界面(UI)层添加的时区。

基于偏移的日期时间类型OffsetTimeOffsetDateTime主要用于网络协议和数据库访问。 例如,大多数数据库不能自动存储“欧洲/巴黎”这样的时区,但它们可以存储像'+02:00'这样的偏移量。

还提供了一个迄今为止最重要的子部分,包括类MonthDayOfWeekYearYearMonthMonthDay 这些可用于建模更复杂的日期时间概念。 例如, YearMonth对于表示信用卡到期非常有用。

请注意,尽管有大量类表示日期的不同方面,但处理时间的不同方面的相对较少。 遵循类型安全性的逻辑结论将产生小时 - 分钟,小时 - 分钟 - 秒和小时 - 分 - 秒 - 纳秒的类别。 虽然逻辑上是纯粹的,但这不是一个实用的选择,因为由于日期和时间的组合,它几乎会使类的数量增加三倍。 因此, LocalTime用于所有时间精度,零用于暗示较低的精度。

遵循完全类型安全性的最终结论也可能争论在日期时间内为每个字段分别设置一个类,例如HourOfDay的类和DayOfMonth的另一个类。 尝试了这种方法,但在Java语言中过于复杂,缺乏可用性。 句点出现类似的问题。 每个句点单元都有一个单独的类,例如“年”类型和“分钟”类型。 但是,这会产生很多类和类型转换问题。 因此,所提供的日期 - 时间类型集合是纯度和实用性之间的折衷。

就方法数量而言,API具有相对大的表面积。 这可以通过使用一致的方法前缀来管理。

  • of - 静态工厂方法
  • parse - 专注于解析的静态工厂方法
  • get - 获取某物的价值
  • is - 检查某些事情是否属实
  • with - setter的不可变等价物
  • plus - 向对象添加金额
  • minus - 从对象中减去一定数量
  • to - 将此对象转换为另一种类型
  • at - 将此对象与另一个对象组合在一起,例如date.atTime(time)

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

但是,有一些有限的用例,用户认为他们需要在整个应用程序中的任意日历系统中存储和使用日期。 ChronoLocalDate支持此功能 ,但在使用该接口之前,必须读取该接口的Javadoc中的所有相关警告。 总之,需要在多个日历系统之间进行通用互操作的应用程序通常需要以与使用ISO日历的方式非常不同的方式编写,因此大多数应用程序应该只使用ISO并避免使用ChronoLocalDate

API也是为用户可扩展性而设计的,因为有许多计算时间的方法。 字段unit API,通过访问TemporalAccessorTemporal提供了很大的灵活应用。 此外, TemporalQueryTemporalAdjuster接口提供日常功能,允许代码读取接近业务需求:

  LocalDate customerBirthday = customer.loadBirthdayFromDatabase();   LocalDate today = LocalDate.now();   if (customerBirthday.equals(today)) {     LocalDate specialOfferExpiryDate = today.plusWeeks(2).with(next(FRIDAY));     customer.sendBirthdaySpecialOffer(specialOfferExpiryDate);   } 
从以下版本开始:
1.8