原文: https://howtodoinjava.com/java8/date-and-time-api-changes-in-java-8-lambda/

开发人员社区的很大一部分一直在抱怨日期和日历类。 原因很多,例如难以理解,难以使用和不灵活。 Date类甚至已经过时,并且 Java 文档建议使用Calendar类而不是Date类。 最重要的是,日期比较有很多问题,我过去也遇到过这样的问题。

Java 8 – 日期和时间示例 - 图1

展望未来,JAVA 8(Lambda)有望发布新的日期和时间 API / 类(JSR-310),也称为 ThreeTen ,它将仅更改您到目前为止的操作方式。 这的一个关键部分是提供一个新的 API,该 API 显着易于使用且不易出错。

它将提供一些非常需要的特性,例如:

  • 所有关键的公共类都是不可变的并且是线程安全的
  • 其他计算领域可以采用的定义的术语和行为

我在 2013 年 5 月 15 日撰写了这篇文章。 现在是 2014 年 3 月 18 日,今天终于可以发布 Java 8 了,可以早期使用。 我已经重新验证并验证了示例中的所有输出。 与去年 5 月一样,它们像魔术一样工作。 唯一遇到的更改是在TemporalAdjuster.java中。 以前是一个类,现在是@FunctionalInterface。 因此,我更正了相关示例,并使用了TemporalAdjusters.java类。

  1. Table of Contents
  2. New classes to represent local date and timezone
  3. New classes to represent timestamp and duration
  4. Added utility classes over existing enums
  5. Date adjusters introduced
  6. Building dates will be easier
  7. New class to simulate system/machine clock
  8. Timezone handling related changes
  9. Date formatting changes
  10. References

代表本地日期和时区的新类

打算替换Date类的新类是LocalDateLocalTimeLocalDateTime

LocalDate

LocalDate类表示日期。 没有时间或时区的表示。

  1. LocalDate localDate = LocalDate.now();
  2. System.out.println(localDate.toString()); //2013-05-15
  3. System.out.println(localDate.getDayOfWeek().toString()); //WEDNESDAY
  4. System.out.println(localDate.getDayOfMonth()); //15
  5. System.out.println(localDate.getDayOfYear()); //135
  6. System.out.println(localDate.isLeapYear()); //false
  7. System.out.println(localDate.plusDays(12).toString()); //2013-05-27

LocalTime

LocalTime类表示时间。 没有日期或时区的表示。

  1. //LocalTime localTime = LocalTime.now(); //toString() in format 09:57:59.744
  2. LocalTime localTime = LocalTime.of(12, 20);
  3. System.out.println(localTime.toString()); //12:20
  4. System.out.println(localTime.getHour()); //12
  5. System.out.println(localTime.getMinute()); //20
  6. System.out.println(localTime.getSecond()); //0
  7. System.out.println(localTime.MIDNIGHT); //00:00
  8. System.out.println(localTime.NOON); //12:00

LocalDateTime

LocalDateTime类表示日期时间。 没有时区的表示。

  1. LocalDateTime localDateTime = LocalDateTime.now();
  2. System.out.println(localDateTime.toString()); //2013-05-15T10:01:14.911
  3. System.out.println(localDateTime.getDayOfMonth()); //15
  4. System.out.println(localDateTime.getHour()); //10
  5. System.out.println(localDateTime.getNano()); //911000000

如果您想将日期特性与区域信息一起使用,则 Lambda 会为您提供额外的 3 类,类似于上面的一种,即OffsetDateOffsetTimeOffsetDateTime。 时区偏移可以以“+05:30”或“Europe/Paris”格式表示。 这是通过使用另一个类即ZoneId完成的。

  1. OffsetDateTime offsetDateTime = OffsetDateTime.now();
  2. System.out.println(offsetDateTime.toString()); //2013-05-15T10:10:37.257+05:30
  3. offsetDateTime = OffsetDateTime.now(ZoneId.of("+05:30"));
  4. System.out.println(offsetDateTime.toString()); //2013-05-15T10:10:37.258+05:30
  5. offsetDateTime = OffsetDateTime.now(ZoneId.of("-06:30"));
  6. System.out.println(offsetDateTime.toString()); //2013-05-14T22:10:37.258-06:30
  7. ZonedDateTime zonedDateTime =
  8. ZonedDateTime.now(ZoneId.of("Europe/Paris"));
  9. System.out.println(zonedDateTime.toString()); //2013-05-15T06:45:45.290+02:00[Europe/Paris]

代表时间戳和持续时间的新类

Instant

为了随时表示特定的时间戳,需要使用的类是InstantInstant类表示精确到纳秒的时间点。 对Instant的操作包括与另一个Instant的比较以及持续时间的增加或减少。

  1. Instant instant = Instant.now();
  2. System.out.println(instant.toString()); //2013-05-15T05:20:08.145Z
  3. System.out.println(instant.plus(Duration.ofMillis(5000)).toString()); //2013-05-15T05:20:13.145Z
  4. System.out.println(instant.minus(Duration.ofMillis(5000)).toString()); //2013-05-15T05:20:03.145Z
  5. System.out.println(instant.minusSeconds(10).toString()); //2013-05-15T05:19:58.145Z

Duration

Duration类是用 Java 语言首次带来的全新概念。 它表示两个时间戳之间的差异。

  1. Duration duration = Duration.ofMillis(5000);
  2. System.out.println(duration.toString()); //PT5S
  3. duration = Duration.ofSeconds(60);
  4. System.out.println(duration.toString()); //PT1M
  5. duration = Duration.ofMinutes(10);
  6. System.out.println(duration.toString()); //PT10M
  7. duration = Duration.ofHours(2);
  8. System.out.println(duration.toString()); //PT2H
  9. duration = Duration.between(Instant.now(), Instant.now().plus(Duration.ofMinutes(10)));
  10. System.out.println(duration.toString()); //PT10M

Duration处理较小的时间单位,例如毫秒,秒,分钟和小时。 它们更适合与应用程序代码进行交互。

Period

要与人互动,您需要获得更大的持续时间,并以Period类给出。

  1. Period period = Period.ofDays(6);
  2. System.out.println(period.toString()); //P6D
  3. period = Period.ofMonths(6);
  4. System.out.println(period.toString()); //P6M
  5. period = Period.between(LocalDate.now(),
  6. LocalDate.now().plusDays(60));
  7. System.out.println(period.toString()); //P1M29D

在现有枚举上添加的工具类

当前的 Java SE 平台使用int常量表示月份,星期几和上午下午等。现在,添加了许多额外的工具类,它们在这些枚举的基础上起作用。 我以这样的类为例:DayOfWeek。 该类是每周日期枚举的包装,并且可以与其他类一致使用。

DayOfWeek

  1. //day-of-week to represent, from 1 (Monday) to 7 (Sunday)
  2. System.out.println(DayOfWeek.of(2)); //TUESDAY
  3. DayOfWeek day = DayOfWeek.FRIDAY;
  4. System.out.println(day.getValue()); //5
  5. LocalDate localDate = LocalDate.now();
  6. System.out.println(localDate.with(DayOfWeek.MONDAY)); //2013-05-13 i.e. when was monday in current week ?

其他此类类别是MonthMonthDayYearYearMonth等。

日期调整器

日期调节器是日期处理工具中另一个美观实用的特性。 它可以轻松解决以下问题:您如何查找一个月的最后一天? 还是下一个工作日? 还是星期二一个星期?

让我们看一下代码。

  1. LocalDate date = LocalDate.of(2013, Month.MAY, 15); //Today
  2. LocalDate endOfMonth = date.with(TemporalAdjusters.lastDayOfMonth());
  3. System.out.println(endOfMonth.toString()); //2013-05-31
  4. LocalDate nextTue = date.with(TemporalAdjusters.next(DayOfWeek.TUESDAY));
  5. System.out.println(nextTue.toString()); //2013-05-21

创建日期对象

现在也可以使用构建器模式创建日期对象。 构建器模式允许使用单例来构建您想要的对象。 这是通过使用以at为前缀的方法来实现的。

  1. //Builder pattern used to make date object
  2. OffsetDateTime date1 = Year.of(2013)
  3. .atMonth(Month.MAY).atDay(15)
  4. .atTime(0, 0)
  5. .atOffset(ZoneOffset.of("+03:00"));
  6. System.out.println(date1); //2013-05-15T00:00+03:00
  7. //factory method used to make date object
  8. OffsetDateTime date2 = OffsetDateTime.
  9. of(2013, 5, 15, 0, 0, 0, 0, ZoneOffset.of("+03:00"));
  10. System.out.println(date2); //2013-05-15T00:00+03:00

模拟系统/机器时钟的新类

在新版本中提出了新的类时钟。 该模拟系统时钟特性。 我最喜欢这个特性。 原因是在进行单元测试时。 您通常需要在将来的日期测试 API。 为此,我们已经将系统时钟转发到下一个日期,然后再次重新启动服务器并测试应用程序。

现在,无需这样做。 使用Clock类可以模拟这种情况。

  1. Clock clock = Clock.systemDefaultZone();
  2. System.out.println(clock); //SystemClock[Asia/Calcutta]
  3. System.out.println(clock.instant().toString()); //2013-05-15T06:36:33.837Z
  4. System.out.println(clock.getZone()); //Asia/Calcutta
  5. Clock anotherClock = Clock.system(ZoneId.of("Europe/Tiraspol"));
  6. System.out.println(anotherClock); //SystemClock[Europe/Tiraspol]
  7. System.out.println(anotherClock.instant().toString()); //2013-05-15T06:36:33.857Z
  8. System.out.println(anotherClock.getZone()); //Europe/Tiraspol
  9. Clock forwardedClock = Clock.tick(anotherClock, Duration.ofSeconds(600));
  10. System.out.println(forwardedClock.instant().toString()); //2013-05-15T06:30Z

时区变更

与时区相关的处理由 3 个主要类别完成。 这些是ZoneOffsetTimeZoneZoneRules

  • ZoneOffset类表示与 UTC 的固定偏移量,以秒为单位。 通常以±hh:mm格式的字符串表示。
  • TimeZone类表示在其中定义了指定时区规则的区域的标识符。
  • ZoneRules是定义区域偏移量何时更改的实际规则集。
  1. //Zone rules
  2. System.out.println(ZoneRules.of(ZoneOffset.of("+02:00")).isDaylightSavings(Instant.now()));
  3. System.out.println(ZoneRules.of(ZoneOffset.of("+02:00")).isFixedOffset());

日期格式化

日期格式化通过两个类别(主要是DateTimeFormatterBuilderDateTimeFormatter)支持。 DateTimeFormatterBuilder使用构建器模式来构建自定义模式,因为DateTimeFormatter为此提供了必要的输入。

  1. DateTimeFormatterBuilder formatterBuilder = new DateTimeFormatterBuilder();
  2. formatterBuilder.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
  3. .appendLiteral("-")
  4. .appendZoneOrOffsetId();
  5. DateTimeFormatter formatter = formatterBuilder.toFormatter();
  6. System.out.println(formatter.format(ZonedDateTime.now()));

这些是我能够识别并进行的重大更改。

参考文献

祝您学习愉快!