Skip to main content
 首页 » 编程设计

介绍 Java 8 Date/Time API

2022年07月19日121think

介绍 Java 8 Date/Time API

1.概述

java8 引入新的日期时间API,为了解决原来java.util.Date , java.util.Calendar的一些缺陷。

本文首先介绍原Date,Calendar API的问题,然后来说明java8 Date , Time API是如何解决的。

同时,我们也了解java8中java.time包中一些常用类及其API,如LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Period, Duration.

2.原Date/Time APIs问题

  • 线程安全 —— Date和Calendar类不是线程安全的,在调试并发程序时让人头痛,开发者必须自己写额外的代码处理线程安全。相反,java8中引入新的Date和Time API是不可变且线程安全的,因此开发者无需担心并发问题。

  • 简单易懂 —— Date和Calendar类

  • 时区和时间 —— 使用原来的API开发者不得不写额外逻辑处理时区逻辑,因此新的API可以使用Local、ZoneDate/TimeAPI处理时区问题。

3.使用LocalDate,LocalTime,LocalDateTime类API

最常用的类是LocalDate, LocalTime, LocalDateTime,见名思意,它们分别表示当前上下文的本地日期/时间。
这些类主要用在时区无需显示指定的场景。本节让介绍其最常用的API.

3.1.使用LocalDate

LocalDate 表示ISO格式日期 (yyyy-MM-dd),没有时间。
可以用来存储日期,如生日,付款日期等。当前日期可以用系统时钟创建:
LocalDate localDate = LocalDate.now();

LocalDate表示特定年,月,日,可以使用of方法或parse方法创建。举例:

LocalDate.of(2015, 02, 20); 
 
LocalDate.parse("2015-02-20"); 

LocalDate提供多个工具方法可以获得不同信息。让我们快速了解下。
下面代码片段获得本地日期,然后加一天:

LocalDate tomorrow = LocalDate.now().plusDays(1);LocalDate tomorrow = LocalDate.now().plusDays(1); 

下面代码获得当前日期,然后减去一个月。注意其枚举时间单位参数:

LocalDate previousMonthSameDay = LocalDate.now().minus(1, ChronoUnit.MONTHS); 

下面两行代码解析“2016-06-12”,然后获取星期几和月中那一天。注意其返回值,第一个为DayOfWeek,第二个是int。

DayOfWeek sunday = LocalDate.parse("2016-06-12").getDayOfWeek(); 
 
int twelve = LocalDate.parse("2016-06-12").getDayOfMonth(); 

也可以轻松测试闰年,示例代码如下:

boolean leapYear = LocalDate.now().isLeapYear(); 

两个日期比较,before和after很便捷:

boolean notBefore = LocalDate.parse("2016-06-12").isBefore(LocalDate.parse("2016-06-11")); 
 
boolean isAfter = LocalDate.parse("2016-06-12").isAfter(LocalDate.parse("2016-06-11")); 

可以从日期中获取边界。下面示例分别获取当天的开始及当月的第一天。

LocalDateTime beginningOfDay = LocalDate.parse("2016-06-12").atStartOfDay(); 
LocalDate firstDayOfMonth = LocalDate.parse("2016-06-12").with(TemporalAdjusters.firstDayOfMonth()); 

下面我们看看LocalTime类。

3.2 使用LocalTime

LocalTime表示时间,没有日期。与LocalDate类似,LocalTime能通过of和parse方法从系统时钟创建。
下面通过示例了解下常用API.

LocalTime now = LocalTime.now(); 

下面代码示例,我们通过解析字符串创建LocalTime表示06:30AM。

LocalTime sixThirty = LocalTime.parse("06:30"); 

也可以使用工厂方法创建LocalTime。示例如下:

LocalTime sixThirty = LocalTime.of(6, 30); 

通过plus方法增加一小时。servenThirth为07:30AM.

LocalTime sevenThirty = LocalTime.parse("06:30").plus(1, ChronoUnit.HOURS); 

提供便捷的方法获取时间单元。

int six = LocalTime.parse("06:30").getHour(); 

比较日期,是否晚于或早于特定时间。示例代码:

boolean isbefore = LocalTime.parse("06:30").isBefore(LocalTime.parse("07:30")); 

LocalTime类中通过常量可以获得max,min,noon时间。在执行数据库时间范围查询时非常有用。下面代码表示23:59:59.99.

LocalTime maxTime = LocalTime.MAX 

下面看看LocalDateTime类。

3.3使用LocalDateTime

LocalDateTime表示日期和时间组合。这时最常用的类,提供了丰富的API.

通过从系统时钟创建:

LocalDateTime.now(); 

通过工厂方法of或parse创建:
LocalDateTime.of(2015, Month.FEBRUARY, 20, 06, 30);

LocalDateTime.parse("2015-02-20T06:30:00"); 

提供了工具API实现增加或减少单元日期或时间。如年,月,日,分钟等。

localDateTime.plusDays(1); 
 
localDateTime.minusHours(2); 

通过get方法获取时间单元。

localDateTime.getMonth(); 

4.使用ZonedDateTime

java8提供了ZonedDateTime类,用于处理带时区的日期和时间。ZoneId表示不同的时区。大约有40不同的时区。

下面代码创建一个时区:

ZoneId zoneId = ZoneId.of("Europe/Paris"); 

获取所有时区集合:
Set allZoneIds = ZoneId.getAvailableZoneIds();

把LocalDateTime转换成特定的时区:

ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, zoneId); 

ZonedDateTime提供parse方法获得特定时区的dateTime:

ZonedDateTime.parse("2015-05-03T10:15:30+01:00[Europe/Paris]"); 

另外和时区一起使用的类是OffsetDateTime类,OffsetDateTime是不变的,表示date-time偏移,存储所有日期和时间字段,精确至纳秒,从UTC/Greenwich计算偏移。

可以通过OffSetDateTime实例结合ZoneOffset创建LocalDateTime。
LocalDateTime localDateTime = LocalDateTime.of(2015, Month.FEBRUARY, 20, 06, 30);

我们创建ZoneOffset,增加两个小时:

ZoneOffset offset = ZoneOffset.of("+02:00"); 
 
OffsetDateTime offSetByTwo = OffsetDateTime.of(localDateTime, offset); 

先localDateTime的值为 2015-02-20 06:30 +02:00.

下面我们看如何通过Period和Duration类修改日期和时间值。

5.使用Period 和 Duration

Period类代表年,月,日的时间量,Duration类代表秒和纳秒的数量。

5.1使用Period

Period类主要用来修改给定日期值,或获取两日期之间的差值:

LocalDate initialDate = LocalDate.parse("2007-05-10"); 

通过Period可以操作日期:

LocalDate finalDate = initialDate.plus(Period.ofDays(5)); 

Period类有不同的get方法,如getYears,getMonths,getDays可以获得不同周期值。下面代码返回5,反应日期间隔:

int five = Period.between(finalDate, initialDate).getDays(); 

也可以通过ChronoUnit实现通用功能:

int five = ChronoUnit.DAYS.between(initialDate , initialDate); 

使用Duration

与Period类似, Duration类用于处理时间, 下面代码创建LocalTime然后增加30秒。

LocalTime initialTime = LocalTime.of(6, 30, 0); 
 
LocalTime finalTime = initialTime.plus(Duration.ofSeconds(30)); 

两个时间之间间隔通过Duration类获得时间单元。
int thirty = Duration.between(finalTime, initialTime).getSeconds();
通用可以通过ChronoUnit 类获得。
int thirty = ChronoUnit.SECONDS.between(finalTime, initialTime);

兼容原Date and Calendar

java8已经提供了toInstant方法,可以转换Date和Calendar实例至新的DateTime。
下面是原Date类中新增的方法:

public static Date from(Instant instant) { 
    try { 
        return new Date(instant.toEpochMilli()); 
    } catch (ArithmeticException ex) { 
        throw new IllegalArgumentException(ex); 
    } 
} 
 
public Instant toInstant() { 
    return Instant.ofEpochMilli(getTime()); 
} 

示例转换:
LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
LocalDateTime.ofInstant(calendar.toInstant(), ZoneId.systemDefault());

也可以通过Epoch时间构建LocalDateTime,Epoch指的是一个特定的时间:1970-01-01 00:00:00 UTC。
结果为2016-06-13T11:34:50:
LocalDateTime.ofEpochSecond(1465817690, 0, ZoneOffset.UTC);

7.Date and Time 格式化

java8提供了非常简单的方式格式化日期和时间:

LocalDateTime localDateTime = LocalDateTime.of(2015, Month.JANUARY, 25, 6, 30); 

下面代码传入一个ISO日期格式去格式化一个本地时间,结果为2015-01-25:

LocalDate localDate = localDateTime.format(DateTimeFormatter.ISO_DATE); 

DateTimeFormatter 类提供了多个标准格式选项。也支持自定义的格式。下面示例代码结果为2015/01/25:

localDateTime.format(DateTimeFormatter.ofPattern("yyyy/MM/dd")); 

也可以通过格式样式格式化,如SHORT, LONG or MEDIUM 。下面代码输出为25-Jan-2015 06:30:00:

localDateTime 
  .format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM) 
  .withLocale(Locale.UK); 

总结

java8提供了丰富的API操作日期时间,相比较原来的API,使用更容易更便捷。如果使用jdk较低版本,可以使用joda库实现,本来java8API就是由joda提供。joda可以通过maven引入:

<dependency> 
    <groupId>joda-time</groupId> 
    <artifactId>joda-time</artifactId> 
    <version>2.9.4</version> 
</dependency> 

本文参考链接:https://blog.csdn.net/neweastsun/article/details/78626020
阅读延展