JDK8日期API

文章目录

前言:
本篇文章搬运于 B站 -> 黑马程序员 -> Java基础教程2020新版JDK8日期API解析
感谢黑马程序员的良心教育,祝黑马程序员越来越好!

1、为什么会出现新的日期类 API ?

在 Java 面世之初,标准库中就引入了两种用于处理日期和时间的类,分别是 java.util.Datejava.util.Calendar,但是由于很多问题,很多方法都已经弃用,在 JavaSE 8 中引入 java.time 包解决了长久以来存在的诸多弊端,java.time 包基于 Joda-Time 库构件,是一种免费的开源解决方法,多年来一直作为处理 Java 日期和时间的事实标准。Java 原本自带的 java.util.Datejava.util.Calendar 类,实际上这两种类有 线程不安全 的风险。

问题1:对于日期的计算困难问题

  • 毫秒值与日期直接转换比较繁琐,其次通过毫秒值来计算时间的差额步骤较多。

问题2:线程不安全问题

  • SimpleDateFormat 类是线程不安全的,在多线程的情况下,全局共享一个。
  • SimpleDateFormat 类中的 Calendar 对象有可能会出现异常。

问题3:使用规范问题

  • 另外的一个问题就是在 java.util.Datejava.util.Calendar 类之前,枚举类型(ENUM)还没有出现,所以在字段中使用整数常量导致整数常量都是可变的,而不是线程安全的。为了处理实际开发中遇到的问题,标准库随后引入了 java.sql.Date 作为 java.util.Date 的子类,但是还是没能彻底解决问题。

2、Date-Time API 中的基本类使用

常用类的概述与功能介绍

Instant 类

  • Instant 类对时间轴上的单一瞬时点建模,可以用于记录应用程序中的事件时间戳。

Duration 类

  • Duration 类表示秒或纳秒时间间隔,适合处理较短的时间,需要更高的精确性。

Period 类

  • Period 类表示一段时间的年、月、日。

LocalDate 类

  • LocalDate 类是一个不可变的日期时间对象,表示日期,通常被视为年月日。

LocalTime 类

  • LocalTime 类是一个不可变的日期时间对象,代表一个时间,通常被看作是时分秒,时间表示为纳秒精度。

LocalDateTime 类

  • LocalDateTime 类是一个不可变的日期时间对象,代表日期时间,通常被视为年月日时分秒。

ZonedDateTime 类

  • ZonedDateTime 类是具有时区的日期时间的不可变表示,此类存储所有日期和时间字段,精度为纳秒,时区为区域偏移量,用于处理模糊的本地日期时间。

now 方法在日期/时间类的使用

Date-Time API 中的所有类均生成不可变实例,它们是线程安全的,并且这些类不提供公共构造函数,也就是说没办法通过 new 的方式直接创建,需要采用工厂方法加以实例化。

now方法可以根据当前日期或时间创建实例。

public static void main(String[] args) {
	Instant instant = Instant.now();
	LocalDate localDate = LocalDate.now();
	LocalTime localTime = LocalTime.now();
	LocalDateTime localDateTime = LocalDateTime.now();
	ZonedDateTime zonedDateTime = ZonedDateTime.now();
}

不仅仅是刚才提供的几个类可以使用 now 方法,Java8 的 Time 包中还提供了其他的几个类可以更精准的获取某些信息。

  • Year 类(表示年)
  • YearMonth 类(表示年月)
  • MonthDay 类(表示月日)
public static void main(String[] args) {
	Year year = Year.now();
	YearMonth yearMonth = YearMonth.now();
	MonthDay monthDay = MonthDay.now();
}

of 方法在日期/时间类的应用

of 方法可以根据给定的参数生成对应的日期/时间对象,基本上每个基本类都有 of 方法用于生成的对应的对象,而且重载形式多变,可以根据不同的参数生成对应的数据。

public static void main(String[] args) {
    // 初始化一个2018年8月8日的LocalDate对象
    LocalDate localDate = LocalDate.of(2018, 8, 8);
    System.out.println("localDate : " + localDate);

    // 初始化晚上8点0分0秒的LocalDate对象,如果是晚上的时间,需要加上12个小时
    LocalTime localTime = LocalTime.of(20, 0, 0, 0);
    System.out.println("localTime : " + localTime);

    // 初始化2018年8月8日下午8点0分的LocalDateTime对象
    LocalDateTime localDateTime = LocalDateTime.of(2018,8,8,20,0);
    System.out.println("localDateTime : " + localDateTime);

    // LocalDateTime的of方法的特殊使用
    LocalDateTime localDateTime1 = LocalDateTime.of(localDate, localTime);
    System.out.println("localDateTime1 : " + localDateTime1);
}

为 LocalDateTime 添加时区信息(拓展)

ZonedDateTime 这个对象里面封装的不仅有时间日期,并且还有偏移量 + 时区,那么时区如何在 Java 中获取呢,通过提供的一个类 ZoneId 的 getAvailableZoneIds 方法可以获取到一个 set 集合,集合中封装了 608 个时区,同样也提供了获取当前系统默认的时区的方式 systemDefault() 方法。

public static void main(String[] args) {
    // 获取所有的时区信息
    Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
    for (String availableZoneId : availableZoneIds) {
        System.out.println(availableZoneId);
    }
    // 获取当前系统默认的时区信息
    ZoneId zoneId = ZoneId.systemDefault();
    System.out.println(zoneId);
}

我们可以通过给 LocalDateTime 添加时区信息来查看到不同时区的时间,比如说 LocalDateTime 中当前封装的是上海时间,那么想知道在此时此刻,纽约的时间是什么,就可以将纽约的时区 Id 添加进去,就可以查看到了,方式如下:

  • 封装时间 LocalDateTime 并添加时区信息。
  • 更改时区信息查看对应时间。
public static void main(String[] args) {
    // 初始化LocalDateTime对象
    LocalDateTime localDateTime = LocalDateTime.now();
    // 添加时区信息到对象中,使用atZone()方法
    ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("Asia/Shanghai"));
    System.out.println("Asia/Shanghai -> 当前时间 : " + zonedDateTime);
    // 更改时区查看其他时区的当前时间,通过方法
    ZonedDateTime zonedDateTime1 = zonedDateTime.withZoneSameInstant(ZoneId.of("Asia/Tokyo"));
    System.out.println("Asia/Tokyo -> 当前时间 : " + zonedDateTime1);
}

Month 枚举类的使用

java.time 包中引入了 Month 的枚举,Month 中包含标准日历中的 12 个月份的常量(从 JANURAY 到 DECEMEBER)也提供了一些方便的方法供我们使用。

推荐在初始化 LocalDate 和 LocalDateTime 对象的时候,月份的参数使用枚举的方式传入,这样更简单易懂而且不易出错,因为如果是老的思维,Calendar 传入 0 的话,那么会出现异常。

public static void main(String[] args) {
    // 初始化LocalDateTime对象,月份使用枚举
    LocalDateTime localDateTime = LocalDateTime.of(2018,Month.JUNE,15,11,11,11);
    System.out.println("localDateTime : " + localDateTime);

    // of方法可以根据传入的数字返回对应的月份
    Month month = Month.of(12);
    System.out.println("month : " + month);
}

3、根据现有实例创建曰期与时间对象

想要修改某个日期/时间对象的现有实例时,我们可以使用 plusminus 方法来完成操作。Java8 中日期时间相关的 API 中的所有实例都是不可改变的,一旦创建 LocalDate,LocalTime,LocalDateTime 就无法修改他们(类似于 String),这对于线程安全非常有利。

plus 方法在 LocalDate 与 LocalTime 中的使用

LocalDate 中定义了多种对日期进行增减操作的方法:

  • LocalDate plusDays(long days) :增加天数。
  • LocalDate plusWeeks(long weeks) :增加周数。
  • LocalDate plusMonths(long months) :增加月数。
  • LocalDate plusYears(long years) :增加年数。
public static void main(String[] args) {
   // 初始化LocalDate对象
    LocalDate localDate = LocalDate.now();
    System.out.println("当前日期 : " + localDate);
    // 计算当前日期4天后的日期
    LocalDate localDate1 = localDate.plusDays(4);
    System.out.println("当前日期4天后的日期 : " + localDate1);
    // 计算当前日期3周后的日期
    LocalDate localDate2 = localDate.plusWeeks(3);
    System.out.println("当前日期3周后的日期 : " + localDate2);
    // 计算当前日期5个月后的日期
    LocalDate localDate3 = localDate.plusMonths(5);
    System.out.println("当前日期5个月后的日期 : " + localDate3);
    // 计算当前日期2年后的日期
    LocalDate localDate4 = localDate.plusYears(2);
    System.out.println("当前日期2年后的日期 : " + localDate4);
}

LocalTime 中定义了多种对日期进行增减操作的方法:

  • LocalTime plusNanos(long nanos) :增加纳秒。
  • LocalTime plusSeconds(long seconds) :增加秒。
  • LocalTime plusMinutes(long minutes) :增加分钟。
  • LocalTime plusHougs(long hours) :增加小时。

上面的示例都是使用 plusXx 方法进行演示的,实际上也有对应的减少方法,以 minus 开头的方法对应的即为减少,实际上 minus 方法调用的也是 plus 方法,只不过传入的参数是负数。

plus 和 minus 方法的应用

刚才学习到的 plusXx 相关的方法都是添加了数值到具体的某一项上,根据观察还有两个单独的plus方法,接下来我们来学习这两个单独的plus方法。

  • plus(TemporaAmount amountToAdd) :TemporaAmount 是一个接口,当接口作为方法的参数的时候,实际上传入的是接口的实现类对象,它的实现类有 Duration 和 Period 等。
public static void main(String[] args) {
    // 今天程序员小张查看自己的车辆保险记录的时候看到还有2年3月8天就到期了,计算到期的日期是什么时候?
    // 方法1
    LocalDate dueDate = LocalDate.now().plusYears(2).plusMonths(3).plusDays(8);
    System.out.println("到期日期 : " + dueDate);

    // 方法2
    Period period = Period.of(2,3,8);
    LocalDate dueDate1 = LocalDate.now().plus(period);
    System.out.println("到期日期 : " + dueDate1);
}
  • plus(long 1,TemporaUnit unit) :在实际开发过程中,可能还会更精准的去操作日期或者说增加一些特殊的时间,比如说1个世纪,1个半天,1千年,10年等,Java8 提供了这些日期的表示方式而不需要去单独进行计算了,TemporaUnit 是一个接口,通过查看体系接口发现,可以使用子类 ChronoUnit 来表示,ChronoUnit 封装了很多时间段供我们使用。
Enum Constant 描述
CENTURIES 代表一个世纪概念的单位。
DAYS 代表一天概念的单位。
DECADES 代表十年概念的单位。
ERAS 代表一个时代概念的单位。
FOREVER 代表永恒概念的人工单位。
HALF_DAYS 代表AM / PM中使用的半天概念的单位。
HOURS 表示一小时概念的单位。
MICROS 表示微秒概念的单位。
MILLENNIA 代表千年概念的单位。
MILLIS 表示毫秒概念的单位。
MINUTES 表示一分钟概念的单位。
MONTHS 代表一个月概念的单位。
NANOS 代表纳秒概念的单位,是支持的最小时间单位。
SECONDS 表示第二个概念的单位。
WEEKS 表示一周概念的单位。
YEARS 代表一年概念的单位。
public static void main(String[] args) {
    // 结婚10年称为锡婚,2020年2月2日11点11分11秒称为对称日,很多情侣准备在那天结婚,如果在那天结婚了,那么锡婚会发生在什么时候?
    LocalDateTime marryTime = LocalDateTime.of(2020,Month.FEBRUARY,2,11,11,11);
    LocalDateTime dateTime = marryTime.plus(1, ChronoUnit.DECADES);
    System.out.println("锡婚发生时间 : " + dateTime);
}

with 方法在 LocalDateTime 类的应用

如果不需要对日期进行加减而是要直接修改日期的话,那么可以使用 with 方法,with 方法提供了很多种修改时间的方式。

  • Loca1DateTime withNano(int i) :修改纳秒。
  • LocalDateTime withSecond(int i) :修改秒。
  • LocalDateTime withMinute(int i) :修改分钟。
  • LocalDateTime withHour(int i) :修改小时。
  • LocalDateTime withDayOfMonth(int i) :修改日。
  • LocalDateTime withMonth(int i) :修改月。
  • LocalDateTime withYear(int i) :修改年。
public static void main(String[] args) {
   LocalDateTime localDateTime = LocalDateTime.of(2020,Month.FEBRUARY,18,11,11,11);
    System.out.println("修改前:" + localDateTime);
    LocalDateTime localDateTime1 = localDateTime.withDayOfMonth(8);
    System.out.println("修改后:" + localDateTime1);
}
  • with(TemporalField field,long newValue) :TemporalField 是一个接口,通过查看体系结构,可以使用它的子类 ChronoField,ChronoField中 封装了一些日期时间中的组成部分,可以直接选择之后传入第二个参数进行修改。
    例:with(ChronoField.DAY_OF_MONTH,1) 就是将日期中的月份中的天数改为1。
    例:with(ChronoField. YEAR,2021) 就是将日期中的年份改为2021。
public static void main(String[] args) {
    LocalDateTime localDateTime = LocalDateTime.of(2020,Month.FEBRUARY,18,11,11,11);
    System.out.println("修改前:" + localDateTime);
    LocalDateTime localDateTime1 = localDateTime.with(ChronoField.DAY_OF_MONTH,8);
    System.out.println("修改后:" + localDateTime1);
}

4、调节器 TemporalAdjuster 与查询 TemporalQuery

在上一节学习的 with 方法中学习了可以通过 with 方法修改日期时间对象中封装的数据,但是有一些时候可能会做一些复杂的操作,比如说将时间调整到下个周的周日,下一个工作日,或者本月中的某一天,这个时候可以使用调节器 TemporalAdjuster 来更方便的处理日期。

Java 8 提供了一个叫做 TemporalAdjusters 的类可以给我们提供一些常用的方法,方法如下:

  • static TemporalAdjuster firstDayOfMonth() :本月的第一天。
  • static TemporalAdjuster firstDayOfNextMonth() :下个月的第一天。
  • static TemporalAdjuster firstDayOfYear() :本年的第一天。
  • static TemporalAdjuster firstDayOfNextYear() :下一年的第一天。
  • static TemporaAdjuste lastInMonth(DayOfweek dayOfweek) :当月的最后一个周x(通过参数确定)。
  • static TemporaAdjuster next(DayOfWeek dayOfweek) :下一个周x(通过参数确定)。
  • static TemporaAdjuster previous(DayOfweek dayOfweek) :上一个周x(通过参数确定)。
public static void main(String[] args) {
    LocalDate localDate = LocalDate.now();
    // 修改日期为本月的第一天
    LocalDate localDate1 = localDate.with(TemporalAdjusters.firstDayOfMonth());
    System.out.println("本月的第一天的日期:" + localDate1);
    // 修改日期为本月的最后一天
    LocalDate localDate2 = localDate.with(TemporalAdjusters.lastDayOfMonth());
    System.out.println("本月的最后一天的日期:" + localDate2);
    // 修改日期为下个月的第一天
    LocalDate localDate3 = localDate.with(TemporalAdjusters.firstDayOfNextMonth());
    System.out.println("下个月的第一天的日期:" + localDate3);
    // 修改日期为下一年的第一天
    LocalDate localDate4 = localDate.with(TemporalAdjusters.firstDayOfNextYear());
    System.out.println("下一年的第一天的日期:" + localDate4);
}

DayOfWeek 的使用

DayOfWeek 是一周中星期几的枚举类其中封装了从周一到周日。

public static void main(String[] args) {
    LocalDate localDate = LocalDate.now();
    // 修改日期为下一个周日
    LocalDate localDate1 = localDate.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
    System.out.println("下一个周日的日期:" + localDate1);
    // 修改日期为上一个周三
    LocalDate localDate2 = localDate.with(TemporalAdjusters.previous(DayOfWeek.WEDNESDAY));
    System.out.println("上一个周三的日期:" + localDate2);
}

自定义 TemporalAdjuster 调节器

通过 Java 8 本身提供的 TemporalAdjusters 中的方法可以完成一些常用的操作,如果要自定义日期时间的更改逻辑,可以通过实现 TemporalAdjuster 类接口中的方式来完成。

  1. 创建类实现 TemporalAdjuster 接口。
  2. 实现 TemporalAdjuster 中的 adjustInto 方法,传入一个日期时间对象,完成逻辑之后返回日期时间对象。
  3. 通过 with 方法传入自定义调节器对象完成更改。

例:假如员工一个月中领取工资,发薪日是每个月的15号,如果发薪日是周末,则调整为周五。

package com.y2.test1.time;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAdjusters;

public class PayDayAdjuster implements TemporalAdjuster {
    @Override
    public Temporal adjustInto(Temporal temporal) {
        // 1.Temporal是日期时间类对象的父接口,实际上可以理解为传入的就是LocalDate或者是LocalTime等对象,需要将temporal转换为LocalDate对象
        LocalDate payDate = LocalDate.from(temporal);
        // 2.判断传入的日期是否为本月15日,如果不是,则修改为15日
        int day;
        if (payDate.getDayOfMonth() != 15) {
            day = 15;
        }else {
            day = payDate.getDayOfMonth();
        }
        // 3.判断传入日期是否为周末,如果为周末,则将日期修改为上一个周五
        LocalDate realPayDate = payDate.withDayOfMonth(day);
        if (realPayDate.getDayOfWeek() == DayOfWeek.SATURDAY || realPayDate.getDayOfWeek() == DayOfWeek.SUNDAY) {
            realPayDate = realPayDate.with(TemporalAdjusters.previous(DayOfWeek.FRIDAY));
        }
        return realPayDate;
    }
}
public static void main(String[] args) {
    LocalDate payDate = LocalDate.of(2021,5,18);
    LocalDate realPayDate = LocalDate.from(new PayDayAdjuster().adjustInto(payDate));
    System.out.println("实际发薪日:" + realPayDate);
}

TemporalQuery 的应用

学习的时态类对象(LocalDate,LocalTime)都有一个方法叫做 query,可以针对日期进行查询。

R query(TemporalQuery query),这个方法是一个泛型方法,返回的数据就是传入的泛型类的类型,TemporalQuery 是一个泛型接口,里面有一个抽象方法是 R queryFrom(TemporalAccessor temporal),TemporalAccessor 是 Temporal 的父接口,实际上也就是 LocalDate 和 LocalDateTime 相关类的*父接口,这个 queryFrom 的方法的实现逻辑就是传入一个日期/时间对象通过自定义逻辑返回数据。

如果要计划日期距离某一个特定天数差距多少天,可以自定义类实现 TemporalQuery 接口并且作为参数传入到 query 方法中。

例:计算当前时间距离下一个劳动节还有多少天?

package com.y2.test1.time;

import java.time.LocalDate;
import java.time.Month;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalQuery;

public class UtilDayQuery implements TemporalQuery<Long> {
    @Override
    public Long queryFrom(TemporalAccessor temporal) {
        // 1.TemporalAccessor是LocalDate和LocalDatetime的*父接口,相当于LocalDate就是这个接口的实现类,将temporal转换为LocalDate进行使用
        LocalDate now = LocalDate.from(temporal);
        // 2.初始化本年的劳动节日期
        LocalDate laborDate = LocalDate.of(now.getYear(), Month.MAY, 1);
        // 3.判断当前时间是否已经超过了当年的劳动节,如果超过了当年的劳动节,则laborDay+1年
        if (now.isAfter(laborDate)) {
            laborDate = laborDate.plusYears(1);
        }
        // 4.通过
        long days = ChronoUnit.DAYS.between(now, laborDate);
        return days;
    }
}
public static void main(String[] args) {
    LocalDate now = LocalDate.of(2021,5,2);
    Long days = new UtilDayQuery().queryFrom(now);
    System.out.println("距离下一个劳动节还有" + days + "天");
    LocalDate laborDate = now.plusDays(days);
    System.out.println("下一个劳动节的日期:" + laborDate);
}

5、java.util.Date 与 java.time.LocalDate 的转换

Java 8 中的 java.time 包中并没有提供太多的内置方式来转换 java.util 包中用预处理标准曰期和时间的类,我们可以使用 Instant 类作为中介,也可以使用 java.sql.Date 和 java.sql.Timestamp 类提供的方法进行转换。

使用 Instant 类将 java.util.Date 转换为 java.time.LocalDate

java.time 包中并没有提供很多的方式来进行直接转换,但是给之前的 Date 类,Calendar 类在 Java1.8 都提供了一个新的方法, 叫做 toInstant,可以将当前对象转换为 Instant 对象,通过给 Instant 添加时区信息之后就可以转换为 LocalDate对象。

public static void main(String[] args) {
    // 初始化Date对象
    Date date = new Date();
    // 1.将Date对象转换为Instant对象
    Instant instant = date.toInstant();
    // 2.Date类包含日期和时间信息,但是并不提供时区信息,和Instant类一样,通过Instant类的atZone方法添加时区信息进行转换
    ZonedDateTime zonedDateTime = instant.atZone(ZoneId.systemDefault());
    // 3.将ZonedDateTime通过toLocalDate方法转换为LocalDate对象
    LocalDate localDate = zonedDateTime.toLocalDate();
    System.out.println("date : " + date);
    System.out.println("localDate : " + localDate);
}

java.sql.Date 类中的转换方法使用

java.sql.Date 类中提供直接转换为 LocalDate 的方法 toLocalDate

public static void main(String[] args) {
    // 初始化java.sql.Date对象
    Date date = new Date(System.currentTimeMillis());
    LocalDate localDate = date.toLocalDate();
    System.out.println("date : " + date);
    System.out.println("localDate : " + localDate);
}

java.sql.Timestamp 类中的转换方法使用

TimeStamp 是时间戳对象,通过传入一个毫秒值对象进行初始化。

public static void main(String[] args) {
    // 初始化java.sql.Timestamp对象
    Timestamp timestamp = new Timestamp(System.currentTimeMillis());
    LocalDateTime localDateTime = timestamp.toLocalDateTime();
    System.out.println("timestamp : " + timestamp);
    System.out.println("localDateTime : " + localDateTime);
}

将 java.util.Date 类转换为 java.time.LocalDate 类的第二种方法

java.sql.Date 类提供了转换为 LocalDate 的方法,那么可以将 java.util.Date 先转换为 java.sql.Date。

通过 java.sql.Date 的构造方法直接传入一个毫秒值可以构造一个 java.sql.Date 对象,毫秒值可以通过 java.util.Date 对象的 getTime 方法获取到。

public static void main(String[] args) {
    Date date = new Date();
    java.sql.Date date1 = new java.sql.Date(date.getTime());
    LocalDate localDate = date1.toLocalDate();
    System.out.println("java.util.date : " + date);
    System.out.println("java.sql.date : " + date1);
    System.out.println("localDate : " + localDate);
}

将 java.util.Calendar 类转换为 java.time.ZonedDateTime 类

Calendar 对象自 Java1.1 开始提供了一个方法获取时区对象的方法 getTimeZone,要将 Calendar 对象转换为 ZonedDateTime 需要先获取到时区对象。从 Java 1.8 开始 TimeZone 类提供了一个方法可以获取到 ZonedId。获取到 ZoneId 之后就可以初始化 ZonedDateTime 对象了,ZonedDateTime 类有一个 ofInstant 方法,可以将一个 Instant 对象和 ZonedId 对象作为参数传入构造一个 ZonedDateTime 对象。

public static void main(String[] args) {
    Calendar calendar = Calendar.getInstance();
    TimeZone timeZone = calendar.getTimeZone();
    ZoneId zoneId = timeZone.toZoneId();
    ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(calendar.toInstant(), zoneId);
    System.out.println("calendar : " + calendar);
    System.out.println("zonedDateTime : " + zonedDateTime);
}

将 java.util.Calendar 类转换为 java.time.LocalDateTime 类

Calendar 对象可以获取到年月日时分秒的信息,这些信息可以作为 LocalDateTime 构造方法的参数。

public static void main(String[] args) {
    Calendar calendar = Calendar.getInstance();
    int year = calendar.get(Calendar.YEAR);
    int month = calendar.get(Calendar.MONTH);
    int day = calendar.get(Calendar.DAY_OF_MONTH);
    int hour = calendar.get(Calendar.HOUR);
    int minute = calendar.get(Calendar.MINUTE);
    int second = calendar.get(Calendar.SECOND);
    LocalDateTime localDateTime = LocalDateTime.of(year, month + 1, day, hour, minute, second);
    System.out.println("calendar : " + calendar);
    System.out.println("localDateTime : " + localDateTime);
}

6、日期的解析与格式化 DateTimeFormatter

SimpleDateFormat 类在刚开始的讲过了是线程不安全的,所以 Java8 提供了新的格式化类 DateTimeFormatter。

DateTimeFormatter 类提供了大量预定义格式化器,包括常量(如 ISO_LOCAL_DATE),模式字母(如 yyyy-MM-dd)以及本地化样式。

与 SimpleDateFormat 不同的是,新版本的日期/时间 API 的格式化与解析不需要在创建转换器对象再进行转换了,通过时间日期对象的 parse/format 方法可以直接进行转换。

LocalDate 类定义的 parse 和 format 方法

public static void main(String[] args) {
    // 格式化
    LocalDateTime now = LocalDateTime.now();
    String s1 = now.format(DateTimeFormatter.ISO_DATE_TIME);
    String s2 = now.format(DateTimeFormatter.ISO_DATE);
    System.out.println("now : " + now);
    System.out.println("ISO_DATE_TIME格式化:" + s1);
    System.out.println("ISO_DATE格式化:" + s2);

    // 解析
    LocalDateTime localDateTime = LocalDateTime.parse(s1);
    LocalDate localDate = LocalDate.parse(s2);
    System.out.println("localDateTime : " + localDateTime);
    System.out.println("localDate : " + localDate);
}

对日期解析格式化

通过 DateTimeFormatter 的 ofLocalizedDate 的方法也可以调整格式化的方式。

此方法需要传入一个 FormatStyle 类对象,查看后发现 FormatStyle 对象是一个枚举类,其中有几种方式如下:

  • Full:全显示(年月日 + 星期)
  • Long:全显示(年月日)
  • Medium:缩略显示(没有年月日汉字)
  • SHORT:精简显示(精简年 + 月日)
public static void main(String[] args) {
    // 格式化
    LocalDateTime now = LocalDateTime.now();
    String r1 = now.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL));
    String r2 = now.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG));
    String r3 = now.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM));
    String r4 = now.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT));
    System.out.println("FULL : " + r1);
    System.out.println("LONG : " + r2);
    System.out.println("MEDIUM : " + r3);
    System.out.println("SHORT : " + r4);
}

注意此种方式在不同时区的显示方式不一样,在其他时区不会显示中文,会根据当前系统的默认时区来进行区别显示。

自定义格式化格式

除了系统的自带的方式之外,也可以通过 DateTimeFormatter 类提供的 ofPattern 方式创建自定时格式化器,格式化的写法与之前使用的 SimpleDateFormat 相同。

public static void main(String[] args) {
    // 格式化
    LocalDateTime now = LocalDateTime.now();
    String s = now.format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss:SSS"));
    System.out.println("格式化后:" + s);
}

欢迎观看,感谢支持!!!

上一篇:JDK8中新日期时间API


下一篇:lottie 显示json格式的动画