介绍
Java 拥有丰富的Date库和 API,使得处理日期和时间操作变得更加容易,这要归功于 Java 8 中引入的 DateTime API。在此 API 之前,开发人员经常不得不解决旧 的Date类和Calendar类的不一致和错误。然而,新的 DateTime API 提供了一组更加一致、不可变且全面的类来处理日期、时间、持续时间和格式。
在这篇文章中,我们将深入研究使用 DateTime API 的复杂性,重点关注其核心组件和用法。
Java DateTime API 简介
软件开发世界在不断发展,Java 编程语言也是如此。Java 中发生重大变化的一个领域是日期和时间的管理方式。DateTime API 在 Java 8 中引入,旨在纠正旧 Date和Calendar类的不一致和限制。
背景
从历史上看,Java 开发人员在处理日期和时间操作时经常遇到些问题。遗留类是可变的,这会带来线程安全问题,并且它们的方法有时不直观。此外,日期运算、时区转换、格式化等操作繁琐且容易出错。
认识到这些挑战,Java 社区发起了 JSR 310 计划。主要目标是从头开始构建一个新的、全面的 DateTime API。该 API 将解决过去的缺点,并为面向未来的日期和时间操作提供基础。
DateTime API 的主要特性
- 不可变: 新 API 的基石之一是不可变性。与它们的前身不同,DateTime API 中的类是不可变的。对象一旦创建,其状态就无法更改。这种设计选择不仅确保了线程安全,而且还最大限度地减少了副作用,从而使代码更加可预测和可维护。
- 可链接方法: 根据现代编程实践,API 中的许多方法都被设计为可链接的。它们返回对象的新实例,允许开发人员以流畅直观的方式串联方法调用。这可能会使复杂
ini
LocalDateTime dateTime = LocalDateTime.now().plusDays( 5 ).minusHours( 2 );
- 清晰的分离: API 明确区分了机器时间和人类时间。机器时间是指以纳秒为单位测量的连续时间,而人类时间则涉及我们作为人类感知时间的方式------以年、月、日等为单位。这种区别确保了正确的工具可用于正确的上下文。
- 广泛的时区支持: 时区是日期时间操作的一个复杂方面。DateTime API 提供了强大的工具来处理时区,使开发人员能够轻松地在不同区域之间进行转换、使用偏移量,甚至考虑夏令时的变化。
- 全面的格式化和解析: 另一个显著功能是 API 对格式化和解析日期时间对象的全面支持。无论您是处理标准 ISO 格式还是自定义模式,DateTime API 都能满足您的需求。
Java 8 中的 DateTime API 代表了一种范式转变,为所有日期时间相关操作提供了一个多功能且高效的工具包。随着我们在后续部分中深入研究其组件,该 API 的真正强大功能和优雅将变得越来越明显。
Local Date, Time, and DateTime
在许多场景中,开发人员需要操作日期和时间,而不考虑时区。这就是 LocalDate、LocalTime 和 LocalDateTime 发挥作用的地方。
LocalDate
用途:LocalDate 类表示格式为 YYYY-MM-DD 的日期,不包含一天中的时间或时区。当只关心日期时间的日期部分时,它特别有用。
主要特征: 提取年、月、日等详细信息。 执行日期算术,例如添加天或月。
ini
LocalDate today = LocalDate.now(); // 获取当前日期
LocalDate birthDate = LocalDate.of(1995, Month.MARCH, 15); //构造日期
LocalDate nextMonth = today.plusMonths(1); //一个月后的时间
LocalTime
目的:LocalTime 体现了一天中的时间,没有日期或时区。它遵循 HH:MM:SS.nnnnnnnnn 格式,当重点仅在于与时间相关的操作时非常有用。
主要特征
- 提取小时、分钟和秒等详细信息。
- 时间算术运算,例如添加小时或分钟。
ini
LocalTime now = LocalTime.now(); // 获取当前时间
LocalTime lunchTime = LocalTime.of(12, 30); // 定义一个时间
LocalTime oneHourLater = now.plusHours(1); // 计算一个小时后的时间
LocalDateTime
用途:LocalDateTime 是一个组合了 LocalDate 和 LocalTime 的复合类。它表示日期和时间,不包括时区。将其视为 LocalDate 和 LocalTime 的并集。
主要特征
- 访问和操作日期和时间组件。
- 日期和时间算术运算,例如同时添加天和小时。
ini
LocalDateTime nowDateTime = LocalDateTime.now(); //获取当前日期和时间
LocalDateTime meetingTime = LocalDateTime.of(2023, Month.JANUARY, 20, 14, 30);//定义一个日期
LocalDateTime nextMeeting = meetingTime.plusWeeks(2).minusHours(2);
这些类的引入为开发人员提供了一种强大且直观的方式来处理本地日期和时间。它们易于使用、用途广泛,并且不受时区的复杂性影响。然而,虽然它们简化了许多任务,但必须记住它们的局限性:它们不处理时区细节。当需要全局或特定于时区的操作时,应考虑 DateTime API 中的其他类
使用时区和 OffsetDateTime
由于时区的变化、夏令时调整和其他区域考虑因素,处理世界不同地区的日期和时间可能是一项复杂的任务。值得庆幸的是,DateTime API 提供了全面的工具来应对这些挑战。
ZoneId
用途:ZoneId类表示时区标识符,用于LocalDateTime和ZonedDateTime之间的转换。
主要特征
- 提供可用时区的目录。
- 提供检索和操作时区的方法。
ini
ZoneId londonZone = ZoneId.of("Europe/London");
ZoneId defaultZone = ZoneId.systemDefault(); // 获取系统默认时区
Set<String> availableZones = ZoneId.getAvailableZoneIds(); // 检索所有可用时区
ZonedDateTime
用途:ZonedDateTime 类表示带有时区的日期时间。当您需要维护时区信息和日期时间(例如安排世界各地的活动)时,它就发挥了作用。
主要特征
- 将 LocalDateTime 与 ZoneId 结合起来以考虑时区偏移。
- 自动管理夏令时调整。
ini
ZonedDateTime nowInLondon = ZonedDateTime.now(londonZone); // 伦敦的当前时间.
ZonedDateTime meetingInLondon = LocalDateTime.of(2023, Month.MAY, 15, 14, 0).atZone(londonZone); // 伦敦日期
ZonedDateTime meetingInTokyo = meetingInLondon.withZoneSameInstant(ZoneId.of("Asia/ShangHai")); // // 将伦敦时间转换为上海时间。
OffsetDateTime
用途:OffsetDateTime 表示与格林威治/UTC 之间存在偏移的日期时间。与带有完整时区 ID 的 ZonedDateTime 不同,OffsetDateTime 仅捕获与 UTC 的小时和分钟偏移量。这使得它特别适合需要简单表示的数据库和 API 等系统。
主要特征
- 将 LocalDateTime 与偏移量结合起来以表示与 UTC/格林威治的差异。
- 通常用于不需要确切时区规则(如夏令时)的系统。
ini
OffsetDateTime specificOffsetDateTime =
LocalDateTime.of(2023, Month.APRIL, 10, 16, 0)
.atOffset(ZoneOffset.ofHours(2)); // 比UTC 偏移 +2 小时的日期时间。
了解并有效使用时区对于许多应用程序至关重要,尤其是在当今互联的世界中。 DateTime API 的 ZoneId、ZonedDateTime 和 OffsetDateTime 提供了一个强大的框架来轻松处理这些复杂性,确保跨不同地区和时区的准确且一致的日期时间操作。无论您是计划全局事件、记录时间戳还是在数据库中存储日期时间,这些类都可确保您拥有适合该作业的工具。
Periods and Durations
在 Java 中处理日期和时间时,经常需要表示和操作时间量。这就是"周期"和"持续时间"发挥作用的地方。两者都用于表示时间间隔,但它们的粒度和用例有所不同。
Period
目的:Period 类表示以年、月和日为单位的时间量。当您需要考虑基于日期的值时,它特别有用。
主要特征
- 表示日期间隔。
- 不考虑基于时间的值,例如小时、分钟或秒。
ini
Period tenDays = Period.ofDays(10); // 创建一个代表 10 天的期间。
Period twoMonthsThreeDays = Period.of(0, 2, 3); //创建 2 个月零 3 天的时间段。
LocalDate startDate = LocalDate.of(2023, Month.JANUARY, 1);
LocalDate endDate = startDate.plus(tenDays); // 指定日期增加间隔
Duration
目的:与Period相反,Duration类关注以小时、分钟、秒和纳秒为单位的精确持续时间。在处理基于时间的精确间隔时,这是您的首选。
主要特征
- 表示高精度的时间间隔。
- 捕获从几天到纳秒的值。
ini
Duration fiveHours = Duration.ofHours(5);
Duration ninetyMinutes = Duration.ofMinutes(90);
LocalTime startTime = LocalTime.of(9, 0);
LocalTime endTime = startTime.plus(fiveHours);
在Period和Duration之间进行选择
期间和持续时间之间的选择主要取决于上下文: 如果您正在处理以日期为中心的操作,
例如计算两个日期之间的差异或向日期添加月份,那么期间是更合适的选择。
另一方面,如果您的操作围绕精确的时间间隔进行,例如测量时间的长度或计算倒计时的剩余时间,那么持续时间将是最佳选择。
结论
Java 的 DateTime API 改变了开发人员处理日期和时间操作的方式,使它们更加直观、一致且防错误。无论是表示特定日期、时间、计算两个日期之间的时间段,还是管理时区,API 都提供了一组多功能工具来满足所有要求。如果您仍在使用旧的 Date 和 Calendar 类,那么是时候切换并享受 DateTime API 的好处了。
如果喜欢这篇文章,点赞支持一下,微信搜索:京城小人物,关注我第一时间查看更多内容,最近需要面试的同学,可以点击面试笔记获取面试笔记!感谢支持!