当前位置: 代码迷 >> 综合 >> 【JDK8】JDK8 新特性 - 新的时间和日期 API(LocalDate、LocalDateTime、Instant、Duration、Period、ZoneId)
  详细解决方案

【JDK8】JDK8 新特性 - 新的时间和日期 API(LocalDate、LocalDateTime、Instant、Duration、Period、ZoneId)

热度:108   发布时间:2023-11-19 15:58:52.0

JDK 8 由一个新增的特性就是引入了新的时间和日期 API,可以更方便的处理日期和时间。

LocalDate

LocalDate 类用来表示一个具体的日期,但不包含具体时间,可以使用 LocalDate 的静态方法 of() 来创建一个实例。LocalDate 也包含一些方法用来获取年份、月份、天、星期几等:

LocalDate localDate = LocalDate.of(2020, 9, 15);     // 初始化一个日期:2020-09-15
int year = localDate.getYear();                     // 年份:2020
Month month = localDate.getMonth();                 // 月份:SEPTEMBER
int dayOfMonth = localDate.getDayOfMonth();         // 月份中的第几天:15
DayOfWeek dayOfWeek = localDate.getDayOfWeek();     // 一周的第几天:TUESDAY
int length = localDate.lengthOfMonth();             // 月份的天数:30
boolean leapYear = localDate.isLeapYear();          // 是否为闰年:false

也可以调用静态方法 now() 来获取当前日期:

LocalDate now = LocalDate.now();

LocalDateTime

LocalDateTime 类是 LocalDateLocalTime 的结合体,可以通过 of() 方法创建,也可以通过 LocalDateatTime() 方法或 LocalTimeatDate() 方法将 LocalDateLocalTime 合并成一个 LocalDateTime

LocalDateTime localDateTime = LocalDateTime.of(2020, Month.JUNE, 15, 22, 25, 54); // 2020-06-15T22:25:54LocalDate localDate = LocalDate.now(); // 2020-09-15
LocalTime localTime = LocalTime.now(); // 22:31:15.210
LocalDateTime localDateTime = localDate.atTime(localTime); // 2020-09-15T22:31:15.210
LocalDateTime localTimeDate = localTime.atDate(localDate); // 2020-09-15T22:31:15.210LocalDate localDateTime = localDateTime.toLocalDate(); // 2020-09-15
LocalTime localDateTime = localDateTime.toLocalTime(); // 22:34:12.267

Instant

Instant 用来表示时间戳,与 System.currentTimeMillis() 类似,不过 Instant 可以精确到纳秒,System.currentTimeMillis() 方法只精确到毫秒。可以通过 now() 方法创建,也可以通过 ofEpochSecond 方法创建。Instant 有两个属性 sencondsnanos 可以分别获取秒和毫秒的时间戳。

Instant instant = Instant.now(); // 2020-09-15T14:40:47.910Z
Instant.ofEpochSecond(120, 100000); // 获取从 1970-01-01 00:00:00 后 120 秒的 10 万纳秒的时刻

Duration

Duration 的内部实现 Instant 类似,也包含 secondsnanos 两部分,不同的是 Duration 表示的是一个时间段,所以 Duration 类中没有 now() 方法,可以通过 Duration.between() 方法创建 Duration 对象:

LocalDateTime startLocalDateTime = LocalDateTime.of(2020, 9, 10, 12, 00, 01); // 2020-09-10T12:00:01
LocalDateTime endLocalDateTime = LocalDateTime.now(); // 2020-09-15T22:53:16.088
Duration duration = Duration.between(startLocalDateTime, endLocalDateTime);long days = duration.toDays(); // 5
long hours = duration.toHours(); // 130
long minutes = duration.toMinutes(); // 7853
long seconds = duration.getSeconds(); // 471195
long millis = duration.toMillis(); // 471195088
long nanos = duration.toNanos(); // 471195088000000

也可以使用 of() 创建一个时间段,用一个时间段长度,和一个时间单位创建

Duration duration1 = Duration.of(5, ChronoUnit.DAYS); // 5天
Duration duration2 = Duration.of(6, ChronoUnit.HOURS); // 6小时
Duration duration3 = Duration.of(7, ChronoUnit.MINUTES); //7分钟
Duration duration4 = Duration.of(8, ChronoUnit.MILLIS); //8秒

Period

PeriodDuration 类似,都表示一个时间段,Period 用年月日来表示:

Period of = Period.of(2, 10, 20);

也可以通过 between() 方法创建,获取两个 LocalDate 参数的时间间隔:

LocalDate localDate = LocalDate.of(2020, 9, 10);
LocalDate nowLocalDate = LocalDate.now();
Period period = Period.between(localDate, nowLocalDate); // P5D

增加和减少日期

LocalDate localDate = LocalDate.of(2020, 9, 15); // 2020-09-15
LocalDate localDate1 = localDate.withYear(2019); // 修改为 2019-09-15
LocalDate localDate2 = localDate.withMonth(8); // 修改为 2020-08-15
LocalDate localDate3 = localDate.withDayOfMonth(13); // 修改为 2020-09-13LocalDate localDate4 = localDate.plusYears(1); // 增加一年 2021-09-15
LocalDate localDate5 = localDate.minusMonths(2);// 减少两个月 2020-07-15
LocalDate localDate6 = localDate.plus(3, ChronoUnit.DAYS); // 增加5天 2020-09-18

对于一些比较复杂的操作,可以使用 TemporalAdjusters 类,可以灵活的调整日期:

LocalDate localDate7 = localDate.with(TemporalAdjusters.next(DayOfWeek.FRIDAY)); // 返回下一个距离当前时间最近的星期五,不包括今天
LocalDate localDate8 = localDate.with(TemporalAdjusters.nextOrSame(DayOfWeek.TUESDAY));// 返回下一个距离当前时间最近的星期五,如果今天是星期五就是今天
LocalDate localDate10 = localDate.with(TemporalAdjusters.lastInMonth(DayOfWeek.FRIDAY)); // 返回本月的最后一个星期五

TemporalAdjusters 类中包含了很多静态方法可以直接使用:

方法名 描述
dayOfWeekInMonth 返回同一个月中每周的第几天
firstDayOfMonth 返回当月的第一天
firstDayOfNextMonth 返回下月的第一天
firstDayOfNextYear 返回下一年的第一天
firstDayOfYear 返回本年的第一天
firstInMonth 返回同一个月中第一个星期几
lastDayOfMonth 返回当月的最后一天
lastDayOfNextMonth 返回下月的最后一天
lastDayOfNextYear 返回下一年的最后一天
lastDayOfYear 返回本年的最后一天
lastInMonth 返回同一个月中最后一个星期几
next / previous 返回后一个/前一个给定的星期几
nextOrSame / previousOrSame 返回后一个/前一个给定的星期几,如果这个值满足条件,直接返回

如果上面的接口还是不能满足需求,可以自定义 TemporalAdjuster 的接口实现:

@FunctionalInterface
public interface TemporalAdjuster {
    Temporal adjustInto(Temporal temporal);
}

这是一个函数式接口,可以使用 Lmabda 表达式实现,比如给定一个日期,计算该日期的下一个工作日(不包括星期六和星期天):

LocalDate localDate = LocalDate.of(2020, 9, 14);
LocalDate localDate1 = localDate.with(temporal -> {
    // 当前日期DayOfWeek dayOfWeek = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK));// 正常情况下,每次增加一天int dayToAdd = 1;// 如果是星期五,增加三天if (dayOfWeek == DayOfWeek.FRIDAY) {
    dayToAdd = 3;}// 如果是星期六,增加两天if (dayOfWeek == DayOfWeek.SATURDAY) {
    dayToAdd = 2;}return temporal.plus(dayToAdd, ChronoUnit.DAYS);
});

格式化日期

JDK8 中提供了一个 DateTimeFormatter 类用于处理日期格式化操作,日期类有一个 format() 方法用于将日期格式化为字符串,该方法接受一个 DateTimeFormatter 类型参数:

LocalDateTime dateTime = LocalDateTime.now();
String strDate1 = dateTime.format(DateTimeFormatter.BASIC_ISO_DATE);    // 20200915
String strDate2 = dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE);    // 2020-09-15
String strDate3 = dateTime.format(DateTimeFormatter.ISO_LOCAL_TIME);    // 23:33:16.998
String strDate4 = dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));   // 2020-09-15
String strDate5 = dateTime.format(DateTimeFormatter.ofPattern("今天是:YYYY年 MMMM DD日 E", Locale.CHINESE)); // 今天是:2020年 一月 05日 星期四

日期类也支持将一个字符串解析成一个日期对象,例如:

String strDate6 = "2020-09-15";
String strDate7 = "2020-09-15 23:34:05";LocalDate date = LocalDate.parse(strDate6, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
LocalDateTime dateTime1 = LocalDateTime.parse(strDate7, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

时区 ZoneId

Java8 中可以使用 ZoneId 很方便的操作时区。

  • ZoneId.systemDefault() 获取系统默认时区:
    ZoneId systemZoneId = ZoneId.systemDefault();
    
  • ZoneId.of() 接受一个 区域/城市 的字符串作为参数,可以通过 getAvaliableZoneIds() 方法获取所有合法的 区域/城市 字符串:
    Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
    ZoneId zoneId = ZoneId.of("Asia/Shanghai");
    
  • 有了 ZoneId 就可以将一个 LocalDateLocalTimeLocalDateTime 对象转换为 ZonedDateTime 对象:
    LocalDateTime localDateTime = LocalDateTime.now();
    ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, ZoneId.systemDefault());
    // 输出
    2020-09-15T23:42:56.147+08:00[Asia/Shanghai]
    
  相关解决方案