原文: https://howtodoinjava.com/java8/date-and-time-api-changes-in-java-8-lambda/
开发人员社区的很大一部分一直在抱怨日期和日历类。 原因很多,例如难以理解,难以使用和不灵活。 Date
类甚至已经过时,并且 Java 文档建议使用Calendar
类而不是Date
类。 最重要的是,日期比较有很多问题,我过去也遇到过这样的问题。
展望未来,JAVA 8(Lambda)有望发布新的日期和时间 API / 类(JSR-310),也称为 ThreeTen ,它将仅更改您到目前为止的操作方式。 这的一个关键部分是提供一个新的 API,该 API 显着易于使用且不易出错。
它将提供一些非常需要的特性,例如:
- 所有关键的公共类都是不可变的并且是线程安全的
- 其他计算领域可以采用的定义的术语和行为
我在 2013 年 5 月 15 日撰写了这篇文章。 现在是 2014 年 3 月 18 日,今天终于可以发布 Java 8 了,可以早期使用。 我已经重新验证并验证了示例中的所有输出。 与去年 5 月一样,它们像魔术一样工作。 唯一遇到的更改是在TemporalAdjuster.java
中。 以前是一个类,现在是@FunctionalInterface
。 因此,我更正了相关示例,并使用了TemporalAdjusters.java
类。
Table of Contents
New classes to represent local date and timezone
New classes to represent timestamp and duration
Added utility classes over existing enums
Date adjusters introduced
Building dates will be easier
New class to simulate system/machine clock
Timezone handling related changes
Date formatting changes
References
代表本地日期和时区的新类
打算替换Date
类的新类是LocalDate
,LocalTime
和LocalDateTime
。
LocalDate
LocalDate
类表示日期。 没有时间或时区的表示。
LocalDate localDate = LocalDate.now();
System.out.println(localDate.toString()); //2013-05-15
System.out.println(localDate.getDayOfWeek().toString()); //WEDNESDAY
System.out.println(localDate.getDayOfMonth()); //15
System.out.println(localDate.getDayOfYear()); //135
System.out.println(localDate.isLeapYear()); //false
System.out.println(localDate.plusDays(12).toString()); //2013-05-27
LocalTime
LocalTime
类表示时间。 没有日期或时区的表示。
//LocalTime localTime = LocalTime.now(); //toString() in format 09:57:59.744
LocalTime localTime = LocalTime.of(12, 20);
System.out.println(localTime.toString()); //12:20
System.out.println(localTime.getHour()); //12
System.out.println(localTime.getMinute()); //20
System.out.println(localTime.getSecond()); //0
System.out.println(localTime.MIDNIGHT); //00:00
System.out.println(localTime.NOON); //12:00
LocalDateTime
LocalDateTime
类表示日期时间。 没有时区的表示。
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime.toString()); //2013-05-15T10:01:14.911
System.out.println(localDateTime.getDayOfMonth()); //15
System.out.println(localDateTime.getHour()); //10
System.out.println(localDateTime.getNano()); //911000000
如果您想将日期特性与区域信息一起使用,则 Lambda 会为您提供额外的 3 类,类似于上面的一种,即OffsetDate
,OffsetTime
和OffsetDateTime
。 时区偏移可以以“+05:30
”或“Europe/Paris
”格式表示。 这是通过使用另一个类即ZoneId
完成的。
OffsetDateTime offsetDateTime = OffsetDateTime.now();
System.out.println(offsetDateTime.toString()); //2013-05-15T10:10:37.257+05:30
offsetDateTime = OffsetDateTime.now(ZoneId.of("+05:30"));
System.out.println(offsetDateTime.toString()); //2013-05-15T10:10:37.258+05:30
offsetDateTime = OffsetDateTime.now(ZoneId.of("-06:30"));
System.out.println(offsetDateTime.toString()); //2013-05-14T22:10:37.258-06:30
ZonedDateTime zonedDateTime =
ZonedDateTime.now(ZoneId.of("Europe/Paris"));
System.out.println(zonedDateTime.toString()); //2013-05-15T06:45:45.290+02:00[Europe/Paris]
代表时间戳和持续时间的新类
Instant
为了随时表示特定的时间戳,需要使用的类是Instant
。 Instant
类表示精确到纳秒的时间点。 对Instant
的操作包括与另一个Instant
的比较以及持续时间的增加或减少。
Instant instant = Instant.now();
System.out.println(instant.toString()); //2013-05-15T05:20:08.145Z
System.out.println(instant.plus(Duration.ofMillis(5000)).toString()); //2013-05-15T05:20:13.145Z
System.out.println(instant.minus(Duration.ofMillis(5000)).toString()); //2013-05-15T05:20:03.145Z
System.out.println(instant.minusSeconds(10).toString()); //2013-05-15T05:19:58.145Z
Duration
Duration
类是用 Java 语言首次带来的全新概念。 它表示两个时间戳之间的差异。
Duration duration = Duration.ofMillis(5000);
System.out.println(duration.toString()); //PT5S
duration = Duration.ofSeconds(60);
System.out.println(duration.toString()); //PT1M
duration = Duration.ofMinutes(10);
System.out.println(duration.toString()); //PT10M
duration = Duration.ofHours(2);
System.out.println(duration.toString()); //PT2H
duration = Duration.between(Instant.now(), Instant.now().plus(Duration.ofMinutes(10)));
System.out.println(duration.toString()); //PT10M
Duration
处理较小的时间单位,例如毫秒,秒,分钟和小时。 它们更适合与应用程序代码进行交互。
Period
要与人互动,您需要获得更大的持续时间,并以Period
类给出。
Period period = Period.ofDays(6);
System.out.println(period.toString()); //P6D
period = Period.ofMonths(6);
System.out.println(period.toString()); //P6M
period = Period.between(LocalDate.now(),
LocalDate.now().plusDays(60));
System.out.println(period.toString()); //P1M29D
在现有枚举上添加的工具类
当前的 Java SE 平台使用int
常量表示月份,星期几和上午下午等。现在,添加了许多额外的工具类,它们在这些枚举的基础上起作用。 我以这样的类为例:DayOfWeek
。 该类是每周日期枚举的包装,并且可以与其他类一致使用。
DayOfWeek
//day-of-week to represent, from 1 (Monday) to 7 (Sunday)
System.out.println(DayOfWeek.of(2)); //TUESDAY
DayOfWeek day = DayOfWeek.FRIDAY;
System.out.println(day.getValue()); //5
LocalDate localDate = LocalDate.now();
System.out.println(localDate.with(DayOfWeek.MONDAY)); //2013-05-13 i.e. when was monday in current week ?
其他此类类别是Month
,MonthDay
,Year
和YearMonth
等。
日期调整器
日期调节器是日期处理工具中另一个美观实用的特性。 它可以轻松解决以下问题:您如何查找一个月的最后一天? 还是下一个工作日? 还是星期二一个星期?
让我们看一下代码。
LocalDate date = LocalDate.of(2013, Month.MAY, 15); //Today
LocalDate endOfMonth = date.with(TemporalAdjusters.lastDayOfMonth());
System.out.println(endOfMonth.toString()); //2013-05-31
LocalDate nextTue = date.with(TemporalAdjusters.next(DayOfWeek.TUESDAY));
System.out.println(nextTue.toString()); //2013-05-21
创建日期对象
现在也可以使用构建器模式创建日期对象。 构建器模式允许使用单例来构建您想要的对象。 这是通过使用以at
为前缀的方法来实现的。
//Builder pattern used to make date object
OffsetDateTime date1 = Year.of(2013)
.atMonth(Month.MAY).atDay(15)
.atTime(0, 0)
.atOffset(ZoneOffset.of("+03:00"));
System.out.println(date1); //2013-05-15T00:00+03:00
//factory method used to make date object
OffsetDateTime date2 = OffsetDateTime.
of(2013, 5, 15, 0, 0, 0, 0, ZoneOffset.of("+03:00"));
System.out.println(date2); //2013-05-15T00:00+03:00
模拟系统/机器时钟的新类
在新版本中提出了新的类时钟。 该模拟系统时钟特性。 我最喜欢这个特性。 原因是在进行单元测试时。 您通常需要在将来的日期测试 API。 为此,我们已经将系统时钟转发到下一个日期,然后再次重新启动服务器并测试应用程序。
现在,无需这样做。 使用Clock
类可以模拟这种情况。
Clock clock = Clock.systemDefaultZone();
System.out.println(clock); //SystemClock[Asia/Calcutta]
System.out.println(clock.instant().toString()); //2013-05-15T06:36:33.837Z
System.out.println(clock.getZone()); //Asia/Calcutta
Clock anotherClock = Clock.system(ZoneId.of("Europe/Tiraspol"));
System.out.println(anotherClock); //SystemClock[Europe/Tiraspol]
System.out.println(anotherClock.instant().toString()); //2013-05-15T06:36:33.857Z
System.out.println(anotherClock.getZone()); //Europe/Tiraspol
Clock forwardedClock = Clock.tick(anotherClock, Duration.ofSeconds(600));
System.out.println(forwardedClock.instant().toString()); //2013-05-15T06:30Z
时区变更
与时区相关的处理由 3 个主要类别完成。 这些是ZoneOffset
,TimeZone
,ZoneRules
。
ZoneOffset
类表示与 UTC 的固定偏移量,以秒为单位。 通常以±hh:mm
格式的字符串表示。TimeZone
类表示在其中定义了指定时区规则的区域的标识符。ZoneRules
是定义区域偏移量何时更改的实际规则集。
//Zone rules
System.out.println(ZoneRules.of(ZoneOffset.of("+02:00")).isDaylightSavings(Instant.now()));
System.out.println(ZoneRules.of(ZoneOffset.of("+02:00")).isFixedOffset());
日期格式化
日期格式化通过两个类别(主要是DateTimeFormatterBuilder
和DateTimeFormatter
)支持。 DateTimeFormatterBuilder
使用构建器模式来构建自定义模式,因为DateTimeFormatter
为此提供了必要的输入。
DateTimeFormatterBuilder formatterBuilder = new DateTimeFormatterBuilder();
formatterBuilder.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.appendLiteral("-")
.appendZoneOrOffsetId();
DateTimeFormatter formatter = formatterBuilder.toFormatter();
System.out.println(formatter.format(ZonedDateTime.now()));
这些是我能够识别并进行的重大更改。
参考文献
- https://jdk8.java.net/lambda/
- http://sourceforge.net/apps/mediawiki/threeten/index.php?title=User_Guide
祝您学习愉快!