Java常见JDK8日期时间API的概述和实操

目录

前言

案例导入

java.util.Date

java.text.SimpleDateFormat

java.util.Calendar

java.time

java.time.format.DateTimeFormatter

其他API

结束语


前言

        在本篇文章中,作者会向读者演示以下(包括但不仅限于)Java中的日期时间API的使用:

  • java.util.Date类
    • Date() / Date(long date)
    • getTime()
    • toString()
  • java.text.SimpleDateFormat类
    • SimpleDateFormat() / SimpleDateFormat(String pattern)
    • format(Date date)
    • parse(String source) 
  • java.util.Calendar(日历)类

    • Calendar.getInstance()

    • get(int field)

    • getTime()

  • java.time( LocalDate、LocalTime、LocalDateTime)

    • now()  /  now(ZoneId zone)

    • of()

    •  Instant

  • java.time.format.DateTimeFormatter 类

    • ofPattern(String pattern)

    • ofLocalizedDateTime(FormatStyle.LONG)

    • format(TemporalAccessor t)

    • parse(CharSequence text)

  • 其他API

    • ZoneId

    • Clock

    • Duration、Period

    • TemporalAdjuster

说明:

        1、  java.util.Date、java.text.SimpleDateFormat和java.util.Calendar理论上属于JDK8之前

        2、java.time、java.time.format.DateTimeFormatter和其他API理论上属于JDK8之后

        3、但JDK版本的迭代一般都是大版本兼容小版本,即在原有的版本上增加新内容,属于增量式开发,所以本文将两部分统一概述为JDK8的日期时间。

案例导入

        在开始讲述之前,我们先来看一个有趣的案例:

        渔夫按照最佳的打鱼方式“三天打鱼,两天晒网”,问:从1998年8月8日开始打鱼,至今2021年10月16日,渔夫在打鱼还是在晒网?

        此问题不难解决,只需要计算开始时间与结束时间的时间差,然后与5取余即可。余数为1,2,3,则渔夫在打鱼;余数为4和0,则渔夫在晒网。

        下面介绍两个计算时间间隔的方法:

  1. 使用java.util.Date类中的getTime()方法获实现。
    1. 实现思路:
      1. 调用getTime() 方法获得两个日期的时间戳
      2. 然后计算时间戳的差值,转换成天数+1,作为一共相差的天数dayDistance
      3. 将dayDistant % 5做判断
  2. 使用java.util.Calendar类来实现。
    1. 实现思路:
      1. 通过get(Calendar.DAY_OF_YEAR)方法来获取天(endDays、startDays),通过get(Calendar.YEAR)方法获取年(endYears、startYears)
      2. 首先判断是否是同一年,如果是同一年,直接返回(endDays-startDays)+1作为一共相差的天数dayDistance
      3. 如果不是同一年,根据平年和闰年的不同,计算不同的时间间距timeDistance,然后返回timeDistance + (day2-day1) + 1作为一共相差的天数dayDistance
      4. 将dayDistant % 5做判断

说明:

1、计算的天数为什么还要+1呢?

        举个例子来解释吧,假如渔夫10月01日开始打鱼,则10月09日后,一共经历9-1=8天,还是9-1+1=9天呢?显然应该是9天才对,即10月9日第9天渔夫在晒网。

2、如何判断是平年还是闰年呢?

  • 普通年能被4整除且不能被100整除的为闰年。(如2008年就是闰年,1904年不是闰年)
  • 世纪年能被400整除的是闰年。(如2000年是闰年,1900年不是闰年)
  • 否则就是平年,平年有365天,闰年有366天。

   代码演示:

public void test2() throws ParseException {
        // 方法一
        String startTime = "1998-08-08";
        String endTime = "2021-10-16";
        int dayDistance = farmerDemo(startTime,endTime);
        System.out.printf("方式一:\n农夫%s开始打鱼,按照三天打鱼二天晒网,经过%d天后,即在%s,农夫的状态是", startTime, dayDistance, endTime);
        frame(dayDistance);

        // 方式二
        int dayDistance2 = differentDays(startTime, endTime);
        System.out.printf("方式二:\n农夫%s开始打鱼,按照三天打鱼二天晒网,经过%d天后,即在%s,农夫的状态是", startTime, dayDistance2, endTime);
        frame(dayDistance2);
}
 private void frame(int dayDistance) {
        switch (dayDistance % 5) {
            case 0:
            case 4:
                System.out.println("晒网。");
                break;
            case 1:
            case 2:
            case 3:
                System.out.println("打鱼。");
                break;
        }
    }

    public static int farmerDemo(String startTime, String endTime) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date d1 = sdf.parse(startTime);
        Date d2 = sdf.parse(endTime);
        long dayDistance = ((d2.getTime() - d1.getTime()) / (1000 * 60 * 60 * 24))+ 1;
        return (int) dayDistance;
    }

    public static int differentDays(String startTime, String endTime) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date1 = sdf.parse(startTime);
        Date date2 = sdf.parse(endTime);

        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(date1);

        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(date2);
        int startDays= cal1.get(Calendar.DAY_OF_YEAR);
        int endDays = cal2.get(Calendar.DAY_OF_YEAR);

        int startYear = cal1.get(Calendar.YEAR);
        int endYear = cal2.get(Calendar.YEAR);

        if(startYear != endYear) { //不同年
            int timeDistance = 0 ;
            for(int i = startYear ; i < endYear ; i ++) {
                // 普通年能被4整除且不能被100整除的为闰年。(如2004年就是闰年,1900年不是闰年)
                // 世纪年能被400整除的是闰年。(如2000年是闰年,1900年不是闰年)
                if(i%4==0 && i%100!=0 || i%400==0) { //闰年
                    timeDistance += 366;
                }
                else { //不是闰年,就是平年
                    timeDistance += 365;
                }
            }

            return timeDistance + (endDays-startDays) + 1;
        }
        else { //同年
            return endDays - startDays + 1;
        }
    }

     运行截图:

Java常见JDK8日期时间API的概述和实操_第1张图片

        通过上述例子,作者向读者展示了java.util.Date、java.util.Date和java.util.Calendar三个类的使用,下面将具体介绍其用法。

java.util.Date

        表示特定的瞬间,精确到毫秒

构造器:

  • Date():使用无参构造器创建的对象可以获取本地当前时间(精确到毫秒)。
  • Date(long date):分配 Date 对象并初始化此对象,以表示自从标准基准时间(称为“历元(epoch)”,即 1970 年 1 月 1 日 00:00:00 GMT)以来的指定毫秒数。

常用方法

  • getTime():返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。
  • toString():把此 Date 对象转换为以下形式的 String: dow、 mon、 dd、hh:mm:ss、 zzz、 yyyy。
    • dow 是一周中的某一天 (Sun, Mon, Tue,Wed, Thu, Fri, Sat)
    • mon 是月份 (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec)。
    • zzz 是时区(并可以反映夏令时)。
  • 其它很多方法都过时了。 

 代码演示:

备注:

        1、代码中 " // => xxxx" 表示输出结果

        2、买一赠一,代码中介绍了java.util.Date的子类java.sql.Date

 public void test1() {
        // 创建一个date实例
        Date date = new Date();
        System.out.println(date);   // => Sat Oct 16 17:49:16 CST 2021
        System.out.println(date.toString());    // => Sat Oct 16 17:49:16 CST 2021

        // 创建指定毫秒数的Date对象
        Date date1 = new Date(1633828407854L);
        System.out.println(date1);  // => Sun Oct 10 09:13:27 CST 2021

        // 创建java.sql.Date对象
        java.sql.Date date2 = new java.sql.Date(1633828407854L);
        System.out.println(date2);  // => 2021-10-10

        // 如何将java.util.Date对象转换为java.sql.Date对象
        java.sql.Date date3 = new java.sql.Date(date1.getTime());
        System.out.println(date3.toString());   // => 2021-10-10

        // 不可使用强转,因为java.sql.Date继承了java.util.Date类
        // 否则会报错:java.lang.ClassCastException: java.util.Date cannot be cast to java.sql.Date
        java.sql.Date date4 = (java.sql.Date) date1;    

    }

java.text.SimpleDateFormat

        Date类的API不易于国际化,大部分被废弃了,java.text.SimpleDateFormat类是一个不与语言环境有关的方式来格式化和解析日期的具体类。

        它允许进行格式化:①日期 --->文本        ②解析:文本--->日期

格式化:

  • SimpleDateFormat() :默认的模式和语言环境创建对象
  • public SimpleDateFormat(String pattern):该构造方法可以用参数pattern指定的格式创建一个对象
  • public String format(Date date):方法格式化时间对象date

解析:

  • public Date parse(String source):从给定字符串的开始解析文本,以生成一个日期。
字母 日期或时间元素 示例
G Era 标志符 AD
y 1996; 96
M 年中的月份 July; Jul; 07
w 年中的周数 27
W 月份中的周数 2
D 年中的天数 189
d 月份中的天数 10
F 月份中的星期 2
E 星期中的天数 Tuesday; Tue
a Am/pm 标记 PM
H 一天中的小时数(0-23) 0
k 一天中的小时数(1-24) 24
K am/pm 中的小时数(0-11) 0
h am/pm 中的小时数(1-12) 12
m 小时中的分钟数 30
s 分钟中的秒数 55
S 毫秒数 978
z 时区 Pacific Standard Time; PST; GMT-08:00
Z 时区 -0800

java.util.Calendar

        Calendar是一个抽象基类,主用用于完成日期字段之间相互操作的功能。

获取Calendar实例的方法

  • 使用Calendar.getInstance()方法
  • 调用它的子类GregorianCalendar的构造器。

        一个Calendar的实例是系统时间的抽象表示,通过get(int field)方法来取得想要的时间信息。比如YEAR、MONTH、DAY_OF_WEEK(一个星期中的某天)、HOUR_OF_DAY 、MINUTE、SECOND

常用方法

  • public void set(int field,int value):将给定的日历字段(field)设置为给定值(value)
  • public void add(int field,int amount):根据日历的规则,为给定的日历字段添加或减去指定的时间量。
  • public final Date getTime():返回一个表示此 Calendar 时间值(从历元至现在的毫秒偏移量)的 Date 对象
  • public final void setTime(Date date) :使用给定的 Date 设置此 Calendar 的时间。

注意:

  • 获取月份时:一月是0,二月是1,以此类推,12月是11
  • 获取星期时:周日是1,周二是2 ,以此类推,周六是7

 代码演示:

public void testCalendar() {
        // 获取日历类的实例
        Calendar instance = Calendar.getInstance(TimeZone.getTimeZone("PRC"));
        // 使用给定的 Date 设置此 Calendar 的时间
        Date date = new Date(1634378890294L);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd EEE a HH:mm:ss");

        instance.setTime(date);

        System.out.println("当前时区的ID: " + instance.getTimeZone().getID());
        System.out.println("当前时间: "+ sdf.format(instance.getTime()));
        System.out.println("一个星期中的第 " + instance.get(Calendar.DAY_OF_WEEK) + "天");
        System.out.println("一年中的第 " + instance.get(Calendar.DAY_OF_YEAR) + "天");
        System.out.println("获取月份 " + instance.get(Calendar.MONTH));

        instance.set(Calendar.DAY_OF_MONTH, 8);
        System.out.println("当前时间日设置为8后,时间是:" + sdf.format(instance.getTime()));

        instance.add(Calendar.HOUR, 2);
        System.out.println("当前时间加2小时后,时间是:" + sdf.format(instance.getTime()));

        instance.add(Calendar.MONTH, -2);
        System.out.println("当前日期减2个月后,时间是:" + sdf.format(instance.getTime()));
    }

输出结果如图:

Java常见JDK8日期时间API的概述和实操_第2张图片

说明:

        1、星期六为7,10月为9(与前面所述一致)

        2、看到这,读者是否会产生疑问,时间应该是一个不可变(不能任意修改)的值,但Calendar类对时间进行了修改,导致当前时间不再是当前时间,这暴露了Calendar的缺陷。

Calendar类与Date类的不足:

        JDK 1.0中包含了一个java.util.Date类,但是它的大多数方法已经在JDK 1.1引入Calendar类之后被弃用了。而Calendar并不比Date好多少。它们面临的问题是:

  • 可变性:像日期和时间这样的类应该是不可变的。
  • 偏移性:Date中的年份是从1900开始的,而月份都从0开始。
  • 格式化:格式化只对Date有用,Calendar则不行。
  • 此外,它们也不是线程安全的;不能处理闰秒等。

         这些问题,随着JDK8的问世而得以解决。

备注:什么是润秒?

        目前国际标准时间,是以铯原子的震动周期作为参考,而依据地球自转为准的时间尺度是叫做世界时,专用天文观测。因为地球自转受到月球潮汐产生不稳定,为使国际标准时间跟世界时差异接近,所以要校时。

        世界协调时(UTC)为目前的国际标准时间,系以铯原子振动周期作为参考的高精度原子时。另一种则根据地球自转为准的时间尺度,称为世界时,属天文观测时间。

        当前几乎所有操作系统都假定 1 天 = 24 × 60 × 60 = 86400 秒。但对于 UTC,大约每一两年出现一次额外的一秒,称为“闰秒”。闰秒始终作为当天的最后一秒增加,并且始终在 12 月 31 日或 6 月 30 日增加。

java.time

        Java 8 吸收了 Joda-Time 的精华,以一个新的开始为 Java 创建优秀的 API。新的 java.time 中包含了所有关于本地日期(LocalDate)、本地时间(LocalTime)、本地日期时间(LocalDateTime)、时区(ZonedDateTime)和持续时间(Duration)的类。

JDK8针对之前版本的不足,做出了如下改变

  • 解决可变性:调用修改日期值后返回新的对象
  • 解决偏移性:java.time将月份和星期都改成了enum
  • 解决格式化:使用 DateTimeFormatter类
  • 解决线程安全:java.time中的日期和时间和最基本的String一样,是不变类型,不但线程安全,而且不能修改。
  • 解决润秒:使用ISO-8601日历系统

        历史悠久的 Date 类新增了 toInstant() 方法,用于把 Date 转换成新的表示形式。这些新增的本地化时间日期 API 大大简化了日期时间和本地化的管理。

        LocalDate、LocalTime、LocalDateTime 类是其中较重要的几个类,它们的实例
是不可变的对象
,分别表示使用 ISO-8601日历系统的日期、时间、日期和时间。它们提供了简单的本地日期或时间,并不包含当前的时间信息,也不包含与时区相关的信息。该类不存储或表示时区,而仅仅只是描述。

  • LocalDate代表IOS格式(yyyy-MM-dd)的日期,可以存储 生日、纪念日等日期。
  • LocalTime表示一个时间,而不是日期。
  • LocalDateTime是用来表示日期和时间的,这是一个最常用的类之一。

注:ISO-8601日历系统是国际标准化组织制定的现代公民的日期和时间的表示法,也就是公历;它适用于闰年规则并一直用于日常生活中公历日历系统。

        下面列举一些常用的方法,在代码中并不会都体现。

常用方法
方法 描述

now()

now(ZoneId zone)

静态方法,根据当前时间创建对象指定时区的对象)

of() 静态方法,根据指定日期/时间创建对象

getDayOfMonth()

getDayOfYear()

获得月份天数(1-31)

获得年份天数(1-366)

getDayOfWeek() 获得星期几(返回一个 DayOfWeek 枚举值)
getMonth() 获得月份, 返回一个 Month 枚举值

getMonthValue()

getYear()

获得月份(1-12)

获得年份

getHour()

getMinute()

getSecond()

获得当前对象对应的小时、分钟、秒
withDayOfMonth()
withDayOfYear()
withMonth()/withYear()
将月份天数、年份天数、月份、年份修改为指定的值并返回新的对象
plusDays()
plusWeeks()
plusMonths()
plusYears()
plusHours()
向当前对象添加几天、几周、几个月、几年、几小时
minusMonths()
minusWeeks()
minusDays()
minusYears()
minusHours()
从当前对象减去几月、几周、几天、几年、几小时

代码演示:

public void testLocal() {
        Date date = new Date();
        System.out.println(date.toString()); // => Sat Oct 16 18:46:01 CST 2021
        // 此方法获取的时间会比实际时间晚8小时
        // 可以设置时区来获取对应的时间
        Instant instant = date.toInstant();
        System.out.println(instant.toString()); // => 2021-10-16T10:46:01.208Z
        ZonedDateTime prc = instant.atZone(ZoneId.of("PRC"));
        System.out.println(prc);    // => 2021-10-16T16 18:46:01.208+08:00[PRC]

        //now():获取当前的日期、时间、日期+时间
        System.out.println(LocalDate.now()); // => 2021-10-16
        System.out.println(LocalTime.now()); // => 18:46:01.208
        LocalDateTime nowDate = LocalDateTime.now();
        System.out.println(nowDate); // => 2021-10-16T18:46:01.208

        //DayOfWeek 是一个枚举类
        DayOfWeek dayOfWeek = nowDate.getDayOfWeek();
        System.out.println(dayOfWeek);  // => SATURDAY

        //of():设置指定的年、月、日、时、分、秒、纳秒。没有偏移量
        // 1秒 = 1000毫秒 =10^6微秒=10^9纳秒
        LocalDateTime localDateTime1 = LocalDateTime.of(2021, 10, 6, 13, 23, 43);
        LocalDateTime localDateTime2 = LocalDateTime.of(2021, 10, 6, 13, 23, 43, 295 * 1000000);
        System.out.println(localDateTime1); // 2021-10-06T13:23:43
        System.out.println(localDateTime2); // 2021-10-06T13:23:43.295

        // of扩展
        //获取秒数
        Long second = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
        //获取毫秒数
        Long milliSecond = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();


        // 修改时间后,以新的对象返回,不会影响原时间
        LocalDateTime newDate = localDateTime1.withDayOfMonth(30);
        System.out.println("原来时间:" + localDateTime1); // => 原来时间:2021-10-06T13:23:43
        System.out.println("修改后的时间:" + newDate);    // => 修改后的时间:2021-10-30T13:23:43
        LocalDateTime newDate2 = localDateTime1.plusDays(10L);
        System.out.println("修改后的时间:" + newDate2);   // => 修改后的时间:2021-10-16T13:23:43
    }

备注:补充瞬时——Instant

  • Instant:时间线上的一个瞬时点。 这可能被用来记录应用程序中的事件时间戳。
  • 在处理时间和日期的时候,我们通常会想到年,月,日,时,分,秒。然而,这只是时间的一个模型,是面向人类的。第二种通用模型是面向机器的,或者说是连续的。在此模型中,时间线中的一个点表示为一个很大的数,这有利于计算机处理。在UNIX中,这个数从1970年开始,以秒为的单位;同样的,在Java中,也是从1970年开始,但以毫秒为单位。
  • java.time包通过值类型Instant提供机器视图,不提供处理人类意义上的时间单位。Instant表示时间线上的一点,而不需要任何上下文信息,例如,时区。概念上讲,它只是简单的表示自1970年1月1日0时0分0秒(UTC)开始的秒数。因为java.time包是基于纳秒计算的,所以Instant的精度可以达到纳秒级。 
  • (1 ns = 10-9 s) 1秒 = 1000毫秒 =10^6微秒=10^9纳秒

java.time.format.DateTimeFormatter

        该类提供了三种格式化方法:

预定义的标准格式

  • ISO_LOCAL_DATE_TIME
  • ISO_LOCAL_DATE
  • ISO_LOCAL_TIME

本地化相关的格式

  • ofLocalizedDateTime(FormatStyle.LONG)
    • FormatStyle.LONG:长的文本样式,有很多的细节。
    • FormatStyle.FULL:完整的文本样式,最详细的
    • FormatStyle.MEDIUM:中文本风格,有一定的细节。
    • FormatStyle.SHORT:短文本样式,通常是数字。

自定义的格式

  • ofPattern(“yyyy-MM-dd hh:mm:ss”)

常用的方法

  • ofPattern(String pattern) 静态方法 , 返 回 一 个 指 定 字 符 串 格 式 的DateTimeFormatter
  • format(TemporalAccessor t) 格式化一个日期、时间,返回字符串
  • parse(CharSequence text) 将指定格式的字符序列解析为一个日期、时间

代码演示:

public void testDTF() {
        //方式一:预定义的标准格式。如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME
        DateTimeFormatter isoLocalDate = DateTimeFormatter.ISO_LOCAL_DATE;
        //格式化:日期-->字符串
        LocalDateTime localDateTime = LocalDateTime.now();
        System.out.println(localDateTime + "-->" + isoLocalDate.format(localDateTime)); // => 2021-10-16T19:20:14.506-->2021-10-16
        //解析:字符串 -->日期
        DateTimeFormatter isoLocalDateTime = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
        System.out.println(isoLocalDateTime.parse("2021-10-10T12:34:27.121")); // => {},ISO resolved to 2021-10-10T12:34:27.121

        // 方式二:
        //  本地化相关的格式。如:ofLocalizedDateTime()
        //   FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT :适用于LocalDateTime

        DateTimeFormatter dateTimeFormatter0 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL)
                .withZone(ZoneId.of("Asia/Shanghai"));
        System.out.println("FULL: " + dateTimeFormatter0.format(LocalDateTime.now())); // => FULL:2021年10月10日 星期日 下午01时10分24秒 CT

        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);
        System.out.println("MEDIUM: " + dateTimeFormatter.format(LocalDateTime.now()));   // => MEDIUM: 2021-10-10 12:56:17

        DateTimeFormatter dateTimeFormatter1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);
        System.out.println("LONG: " + dateTimeFormatter1.format(LocalDateTime.now()));  // => LONG: 2021年10月10日 下午12时56分17秒

        DateTimeFormatter dateTimeFormatter2 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);
        System.out.println("SHORT: " + dateTimeFormatter2.format(LocalDateTime.now())); // => SHORT:21-10-10 下午12:58

        // 解析
        TemporalAccessor parse = dateTimeFormatter1.parse("2021年10月10日 下午12时56分17秒");
        System.out.println(dateTimeFormatter2.format(parse));   // => 21-10-10 下午12:56

        // 重点: 方式三:自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”)
        DateTimeFormatter pa = DateTimeFormatter.ofPattern("yyyy-MM-dd EEE HH:mm:ss");
        TemporalAccessor parse1 = pa.parse("2021-10-09 星期六 05:57:58");

        System.out.println(dateTimeFormatter0.format(parse1));  // => 2021年10月9日 星期六 上午05时57分58秒 CT

    }

其他API

  • ZoneId:该类中包含了所有的时区信息,一个时区的ID,如 Europe/Paris
  • ZonedDateTime:一个在ISO-8601日历系统时区的日期时间,如 2021-10-16T20:15:30+01:00 Europe/Paris。 其中每个时区都对应着ID,地区ID都为“{区域}/{城市}”的格式,例如:Asia/Shanghai等。
  • Clock:使用时区提供对当前即时、日期和时间的访问的时钟。以前用到System.currentTimeInMillis()和TimeZone.getDefault()的地方都可用Clock替换。
  • 持续时间:Duration,用于计算两个“时间”间隔
  • 日期间隔:Period,用于计算两个“日期”间隔
  • TemporalAdjuster : 时间校正器。有时我们可能需要获取例如:将日期调整到“下一个工作日”等操作。
  • TemporalAdjusters : 该类通过静态方法(firstDayOfXxx()/lastDayOfXxx()/nextXxx())提供了大量的常用TemporalAdjuster 的实现。

代码演示:

public void testNewAPI(){
        //以前用到System.currentTimeInMillis()和TimeZone.getDefault()的地方都可用Clock替换。
        // Z 代表世界时(协调时,UTC)
        Clock clock = Clock.systemDefaultZone();
        Clock clock1 = Clock.systemUTC();
        // 可以自由设置时区,获取相应的时间
        Clock clock2 = Clock.system(ZoneId.of("Asia/Tokyo"));

        System.out.println(clock.getZone() + "\t" + clock1.getZone() + " \t" + clock2.getZone()); // =>Asia/Shanghai Z 	Asia/Tokyo
        System.out.println(clock + "\t" + TimeZone.getDefault().getID());  // =>SystemClock[Asia/Shanghai]  Asia/Shanghai
        System.out.println(clock.millis() + "\t" + System.currentTimeMillis());  // => 1634440421440	1634440421440

        // 打印上海时间、UTC时间和东京时间
        LocalDateTime nowShanghai = LocalDateTime.now(clock);
        LocalDateTime nowUTC = LocalDateTime.now(clock1);
        LocalDateTime nowTokyo = LocalDateTime.now(clock2);
        System.out.println(nowShanghai);    // => 2021-10-16T11:16:00.246
        System.out.println(nowUTC);         // => 2021-10-16T03:16:00.246
        System.out.println(nowTokyo);       // => 2021-10-16T12:16:00.246

        //ZoneId:类中包含了所有的时区信息
        // ZoneId的getAvailableZoneIds():获取所有的ZoneId
        Set zoneIds = ZoneId.getAvailableZoneIds();
        System.out.println("所有的时区信息: ");
        for (String s : zoneIds) {
            System.out.print(s + "\t");
        }
        System.out.println();


        // ZoneId的of():获取指定时区的时间
        LocalDateTime localDateTime = LocalDateTime.now(ZoneId.of("Asia/Tokyo"));
        System.out.println(localDateTime);  // => 2021-10-17T00:50:57.604

        //ZonedDateTime:带时区的日期时间
        // ZonedDateTime的now():获取本时区的ZonedDateTime对象
        ZonedDateTime zonedDateTime = ZonedDateTime.now();
        System.out.println(zonedDateTime);  // => 2021-10-16T23:50:57.718+08:00[Asia/Shanghai]

        // ZonedDateTime的now(ZoneId id):获取指定时区的ZonedDateTime对象
        ZonedDateTime zonedDateTime1 = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
        System.out.println(zonedDateTime1); // => 2021-10-17T00:50:57.719+09:00[Asia/Tokyo]

        //Duration:用于计算两个“时间”间隔,以秒和纳秒为基准
        LocalTime localTime = LocalTime.now();
        LocalTime localTime1 = LocalTime.of(15, 23, 32);
        //between():静态方法,返回Duration对象,表示两个时间的间隔
        Duration duration = Duration.between(localTime1, localTime);
        System.out.println(duration);   // => PT8H27M25.719S
        System.out.println(duration.getSeconds());  // => 30445
        System.out.println(duration.getNano()); // => 719000000
        LocalDateTime localDateTime1 = LocalDateTime.of(2016, 6, 12, 15, 23, 32);
        LocalDateTime localDateTime2 = LocalDateTime.of(2027, 9, 12, 15, 23, 32);
        Duration duration1 = Duration.between(localDateTime1, localDateTime2);
        System.out.println(duration1.toDays());     // => 365

        //Period:用于计算两个“日期”间隔,以年、月、日衡量
        LocalDate localDate = LocalDate.now();
        LocalDate localDate1 = LocalDate.of(2028, 3, 18);
        Period period = Period.between(localDate, localDate1);
        System.out.println(period); // => P6Y5M2D
        System.out.println(period.getYears());  // => 6
        System.out.println(period.getMonths());// => 5
        System.out.println(period.getDays()); // => 2
        Period period1 = period.withYears(2);
        System.out.println(period1);    // => P2Y5M2D

        // TemporalAdjuster:时间校正器
        // 获取当前日期的下一个周日是哪天?
        TemporalAdjuster temporalAdjuster = TemporalAdjusters.next(DayOfWeek.SUNDAY);
        LocalDateTime localDateTime3 = LocalDateTime.now().with(temporalAdjuster);
        System.out.println(localDateTime3); // => 2021-10-17T23:50:57.735

        // 获取下一个工作日是哪天?
        LocalDate localDate3 = LocalDate.now().with(new TemporalAdjuster() {
            @Override
            public Temporal adjustInto(Temporal temporal) {
                LocalDate date = (LocalDate) temporal;
                if (date.getDayOfWeek().equals(DayOfWeek.FRIDAY)) {
                    return date.plusDays(3);
                } else if (date.getDayOfWeek().equals(DayOfWeek.SATURDAY)) {
                    return date.plusDays(2);
                } else {
                    return date.plusDays(1);
                } }
        });
        System.out.println("下一个工作日是:" + localDate3); // => 下一个工作日是:2021-10-18
    }

结束语

        以上内容是作者对JDK8的日期时间API的理解和实操,难免会有错误和不足,还望读者能发现其中的错误,及时留言评论,一同进步。

        最后,具体的学习还应该返璞归真,查阅API文档。

路漫漫其修远兮,吾将上下而求索。                ---屈原

你可能感兴趣的:(java,ide,api)