IT源码网

Java8的最新时间类库讲解

wyy 2021年02月13日 编程语言 188 0

一、 日期类API导学

设计初衷:Java原本自带的 java.util.Datejava.util.Calendar类,实际上两种类有 线程不安全的风险(虽然学习的时候处于单线程环境并不会出现问题),但是之后到了企业中还是可能会增加学习成本,重新学习如何处理时间,所以推出了这个Java8的最新时间类库的讲解,希望降低学生的学习成本,能够更快的融入到企业开发实战中去。

二、 老版本API计算困难问题

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

JAVA面世之初,标准库就引入了两种用于处理日期和时间的类,它们是java.util.Datejava.util.Calendar。而前者堪称类糟糕的设计典范,浏览API可以发现,从Java1.1开始,Date 类中的所有方法就已经被弃用,Java1.1推荐采用Calendar类处理日期和时间,但是这个类同样存在不少问题。

对于日期的计算困难问题

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

 
import java.time.LocalDate; 
import java.time.temporal.ChronoUnit; 
import java.util.Calendar; 
import java.util.Date; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-01 下午 17:44 
 * 题目:程序员小李出生于1995年12月16日,计算在当前这个时间他已经出生了多少天? 
 * 步骤思路: 
 * 1、初始化 Date对象,无参构造(无参构造默认代表的就是当前时间) 
 * 2、获取当前时间距离1970年1月1日过了多少毫秒 
 * 3、初始化 Calendar对象并设时间为1995年12月16日,并将 Calendar对象转换成 Date对象, 
 *    再转换成1995年12月16日距离1970年1月1日过了多哦少毫秒 
 * 4、将两个毫秒数做详见操作,然后将毫秒数转换成天数 
 */ 
public class JavaUtilTimeCalculateDemo { 
    public static void main(String[] args) { 
        Date date = new Date(); 
        long time = date.getTime(); 
        System.out.println(time);//当前时间的时间戳 
 
        Calendar instance = Calendar.getInstance(); 
        instance.set(1995,11,16);  // 要想设置 12 月份,则需要写11,因为从 0 开始 
 
        Date time1 = instance.getTime(); 
        long time2 = time1.getTime(); 
        System.out.println(time2);//1995年12月16日的时间戳 
 
        Long l = (time - time2) / 1000 / 60 / 60 / 24;//时间戳是毫秒单位,需要除以1000 
        System.out.println("1995年12月16日距离1970年1月1日过了" + l);  // 结果 8953 
 
        // 使用 java8 新版本的API来完成题目要求 
        long l1 = ChronoUnit.DAYS.between(LocalDate.of(1995, 12, 16), LocalDate.now()); 
        System.out.println(l1); 
    } 
}

看结果

 

 结果还不一定正确

 

三、老版本API线程不安全问题

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

import java.text.ParseException; 
import java.text.SimpleDateFormat; 
import java.util.Date; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-01 下午 18:08 
 * 创建 10 个线程,将字符串"2018-12-12 12:12:12" 转换成 Date对象后打印到控制台上 
 */ 
public class SimpleDateFormatDemo { 
    final static SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 
 
    public static void main(String[] args) { 
//        循环10次,创建10个对象并启动 
        for (int i = 0; i < 10; i++) { 
            new Thread(new Runnable() { 
                @Override 
                public void run() { 
                    try { 
                        /*synchronized (SIMPLE_DATE_FORMAT) { 
                            Date date = SIMPLE_DATE_FORMAT.parse("2018-12-12 12:12:12"); 
                            System.out.println(date); 
                        }*/ 
                        Date date = SIMPLE_DATE_FORMAT.parse("2018-12-12 12:12:12"); 
                        System.out.println(date); 
                    } catch (ParseException e) { 
                        e.printStackTrace(); 
                    } 
                } 
            }).start(); 
        } 
    } 
}

看结果

另外一个问题就是在java.util.Date和java.util.Calendar类之前,枚举类型(ENUM)还没有出现,所以在字段中使用整数常量导致整数常量都是可变的,而不是线程安全的。


 四、老版本API使用规范问题

import java.util.Calendar; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-01 下午 18:29 
 */ 
public class CalendarUnsafeDemo { 
    public static void main(String[] args) { 
//        初始化Calendar对象 -> getInstance()方法 
        Calendar calendar = Calendar.getInstance(); 
//        通过 set 方法设置年/月/日参数 -> 开发规范:不允许使用没有定义的魔法数字 
        calendar.set(2008,Calendar.AUGUST,8); 
    } 
}

五、java.time包->常用类的概述和功能介绍

Instant类

    Instant类对时间轴上的单一瞬时点建模,可以用于记录应用程序中的事件时间戳,之后学习的类型转换中,均可以使用Instant类作为中间类完成转换。

Duration类

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

Period类

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

LocalDate类

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

LocalTime类

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

LocalDateTime类

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

ZonedDateTime类

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

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

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

 六、now方法在日期时间类中的应用1

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

import java.time.*; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-01 下午 19:42 
 * Date-Time API中的所有类均生成不可变实例,它们是线程安全的,并且这些类不提供公共构造函数, 
 * 也就是说没办法通过new的方式直接创建,需要采用工厂方式加以实例化。 
 * 
 * now方法可以根据当前日期或事件创建实例对象。 
 */ 
public class Java8TimeClassMethodDemo1 { 
    public static void main(String[] args) { 
        // 使用 now方法创建 Instant的实例对象 
        Instant instantNow = Instant.now(); 
        // 使用 now方法创建 LocalDate的实例对象 
        LocalDate localDateNow = LocalDate.now(); 
        // 使用 now方法创建 LocalTime的实例对象 
        LocalTime localTimeNow = LocalTime.now(); 
        // 使用 now方法创建 LocalDateTime的实例对象 
        LocalDateTime localDateTimeNow = LocalDateTime.now(); 
        // 使用 now方法创建 ZonedDateTime的实例对象 
        ZonedDateTime zonedDateTimeNow = ZonedDateTime.now(); 
 
        // 祖鲁时间(格林威治时间/国际标准时间) Instant:2020-05-02T09:01:58.930823200Z 
        System.out.println("Instant:" + instantNow); 
        // 年-月-日 yyyy-MM-dd LocalDate:2020-05-02 
        System.out.println("LocalDate:" + localDateNow); 
        // 时:分:秒 HH:mm:ss  LocalTime:17:01:58.954758600 
        System.out.println("LocalTime:" + localTimeNow); 
        // 年-月-日T时:分:秒  LocalDateTime:2020-05-02T17:01:58.954758600 
        System.out.println("LocalDateTime:" + localDateTimeNow); 
        // 年-月-日T时:分:秒+08:00[Asia/Shanghai] 表示时区 ZonedDateTime:2020-05-02T17:01:58.955756+08:00[Asia/Shanghai] 
        System.out.println("ZonedDateTime:" + zonedDateTimeNow); 
    } 
}

看结果

 

七、now方法在日期时间类中的应用2

不仅仅是以上提供的及各类可以使用now方法,Java8的Time包种还提供了其它几个类可以更精准的获取某些信息。

Year类(表示年)

YearMonth类(表示年月)

MonthDay类(表示月日)

import java.time.MonthDay; 
import java.time.Year; 
import java.time.YearMonth; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-02 下午 17:18 
 */ 
public class Java8TimeClassMethodDemo2 { 
    public static void main(String[] args) { 
        // 使用 now方法创建 Year类的实例对象 
        Year year = Year.now(); 
        // 使用 now方法创建 YearMonth类的实例对象 
        YearMonth yearMonth = YearMonth.now(); 
        // 使用 now方法创建 MonthDay类的实例对象 
        MonthDay monthDay = MonthDay.now(); 
 
        // Year:2020 
        System.out.println("Year:" + year); 
        // YearMonth:2020-05 
        System.out.println("YearMonth:" + yearMonth); 
        // MonthDay:--05-02 
        System.out.println("MonthDay:" + monthDay); 
    } 
}

看结果

 

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

指定任意时间节点

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

import java.time.LocalDate; 
import java.time.LocalDateTime; 
import java.time.LocalTime; 
import java.time.Month; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-02 下午 17:29 
 */ 
public class Java8TimeClassMethodDemo3 { 
    public static void main(String[] args) { 
        // 初始化2018年8月8日的 LocalDate对象 
        LocalDate localDate = LocalDate.of(2018, Month.AUGUST, 8); 
        // LocalDate:2018-08-08 
        System.out.println("LocalDate:" + localDate); 
 
        /* 
        * 初始化晚上8点0分0秒的 LocalTime对象 -> 如果是晚上时间,需要加12。 
        * LocalTime.of方法的重载形式有以下几种,可以根据实际情况自行使用 
        * LocalTime.of(int hour, int minute) -> 根据小时/分钟生成对象 
        * LocalTime.of(int hour, int minute, int second) -> 根据小时/分钟/秒生成对象 
        * LocalTime.of(int hour, int minute, int second, int nanoOfSecond) -> 根据小时/分钟/毫秒/纳秒生成对象 
        * */ 
        LocalTime localTime = LocalTime.of(20, 0); 
        // LocalTime:20:00  若末尾秒为0则省略 
        System.out.println("LocalTime:" + localTime); 
 
        /* 
        * 初始化2018年8月8日下午8点0分的 LocalDateTime对象。 
        * LocalDateTime.of方法的重载形式有以下几种,可以根据实际情况自行使用 
        * LocalDateTime.of(int year, int month, int dayOfMonth, int hour, int minute, int second,int nanoOfSecond) ->根据年/月/日/时/分/秒/纳秒生成对象 
        * LocalDateTime.of(int year, int month, int dayOfMonth, int hour, int minute) -> 根据年/月/日/时/分生成对象 
        * */ 
        LocalDateTime localDateTime = LocalDateTime.of(2018, Month.AUGUST, 8, 8, 0); 
        // LocalDateTime2018-08-08T08:00 
        System.out.println("LocalDateTime:" + localDateTime); 
 
        /* 
        * LocalDateTime的 of方法的特殊使用: 
        * LocalDateTime.of(LocalDate date, LocalTime time) 
        * */ 
        LocalDateTime localDateTime1 = LocalDateTime.of(localDate, localTime); 
        // LocalDateTime1:2018-08-08T20:00 
        System.out.println("LocalDateTime1:" + localDateTime1); 
    } 
}

结果

 

九、时区信息的获取(拓展)

在学习ZonedDateTime的时候,发现这个对象里面封装的不仅有时间日期,并且还有偏移量+时区,那么时区如何在Java中获取呢?

通过提供的一个类ZonedId的getAvailableZoneIds方法可以获取到一个Set集合,集合中封装了600个时区。

import java.time.ZoneId; 
import java.util.Set; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-02 下午 17:55 
 */ 
public class Java8TimeClassMethodDemo4 { 
    public static void main(String[] args) { 
        // 获取所有的时区信息 
        Set<String> availableZoneIds = ZoneId.getAvailableZoneIds(); 
        // Europe/Monaco、America/Los_Angeles等等 
        for (String availableZoneId : availableZoneIds) { 
            //System.out.println(availableZoneId); 
        } 
        // 获取当前系统默认的时区信息 
        ZoneId zoneId = ZoneId.systemDefault(); 
        // 系统默认时区:Asia/Shanghai 
        System.out.println("系统默认时区:" + zoneId); 
    } 
}

结果

 

十、添加时区信息与获取其它时区时间

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

*    封装时间 LocalDateTime 并添加时区信息。

*    更改时区信息查看对应时间。

import java.time.LocalDateTime; 
import java.time.Month; 
import java.time.ZoneId; 
import java.time.ZonedDateTime; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-02 下午 18:07 
 * 为 LocalDateTime添加时区信息 
 */ 
public class Java8TimeClassMethodDemo5 { 
    public static void main(String[] args) { 
        // 1、封装 LocalDateTime对象,参数自定义 ->2018年11月11日 8点54分38秒 
        LocalDateTime localDateTime = LocalDateTime.of(2018, Month.NOVEMBER, 11, 8, 54, 38); 
        // 2、 localDateTime对象现在知识封装了一个时间,并没有时区相关的数据,所以要添加时区信息到对象中,使用 atZone()方法 
        ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("Asia/Shanghai")); 
//        上海当前的时间是:2018-11-11T08:54:38+08:00[Asia/Shanghai] 
        System.out.println("上海当前的时间是:" + zonedDateTime); 
        // 3、更改时区查看其它时区的当前时间,通过 withZoneSameInstant()方法即可 
        ZonedDateTime tokyoZonedDateTime = zonedDateTime.withZoneSameInstant(ZoneId.of("Asia/Tokyo")); 
//        在上海同一时刻,Asia/Tokyo的时间是:2018-11-11T09:54:38+09:00[Asia/Tokyo] 
        System.out.println("在上海同一时刻,Asia/Tokyo的时间是:" + tokyoZonedDateTime); 
    } 
}

结果

 

十一、Month枚举类的使用

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

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

import java.time.LocalDateTime; 
import java.time.Month; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-02 下午 18:23 
 */ 
public class Java8TimeClassMethodDemo6 { 
    public static void main(String[] args) { 
        // 初始化 LocalDate 和 LocalDateTime 的时候月份传入枚举类 Month -> 2011年5月15日11时11分11秒 
        LocalDateTime localDateTime = LocalDateTime.of(2011, Month.JUNE, 15, 11, 11, 11); 
        // Month枚举类 -> of可以根据传入的数字返回对应的月份枚举 
        Month month = Month.of(12); 
//        DECEMBER 
        System.out.println(month); 
    } 
}

结果

 

十二、章节练习(1)

import java.time.*; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-02 下午 18:38 
 * 
 * 创建当前时间(不带时区) 
 * 创建当前时间(只包含年月日) 
 * 创建当前时间(包含年月日时分秒并且带有时区) 
 * 创建2012年12月31日7时38分46秒的日期对象,月份用枚举表示 
 * 创建2012年12月31日的日期对象,月份用枚举表示 
 * 创建7时38分46秒的时间对象 
 */ 
public class Java8TimeClassMethodTest01 { 
    public static void main(String[] args) { 
        // 创建当前时间(不带时区)  2020-05-02T18:45:11.843322800 
        LocalDateTime localDateTimeNow = LocalDateTime.now(); 
        System.out.println(localDateTimeNow); 
        // 创建当前时间(只包含年月日)  2020-05-02 
        LocalDate localDatenow = LocalDate.now(); 
        System.out.println(localDatenow); 
        // 创建当前时间(包含年月日时分秒并且带有时区)  2020-05-02T18:45:11.844320500+08:00[Asia/Shanghai] 
        ZonedDateTime zonedDateTimeNow = ZonedDateTime.now(); 
        System.out.println(zonedDateTimeNow); 
        // 创建2012年12月31日7时38分46秒的日期对象,月份用枚举表示  2012-12-31T07:38:46 
        LocalDateTime localDateTimeOf = LocalDateTime.of(2012, Month.DECEMBER, 31, 7, 38, 46); 
        System.out.println(localDateTimeOf); 
        // 创建2012年12月31日的日期对象,月份用枚举表示  2012-12-31 
        LocalDate localDate = LocalDate.of(2012, Month.DECEMBER, 31); 
        System.out.println(localDate); 
        // 创建7时38分46秒的时间对象  07:38:46 
        LocalTime localTime = LocalTime.of(7, 38, 46); 
        System.out.println(localTime); 
    } 
}

结果

 

 

十三、plus方法在LocalDate中的使用

想要修改某个日期/时间对象的现有实例时,我们可以使用 plusminus方法来完成操作。

Java8中日期时间相关的API中的所有实例都是不可改变的,一旦创建LocalDate,LocalTime,LocalDateTime就无法修改他们(类似于String),这对于线程安全时非常有利的。

plus方法在LocalDate与LocalTime中的使用

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

    LocalDate plusDay(long days) 增加天数

    LocalDate plusWeeks(long weeks) 增加周数

    LocallDate plusMonths(long months) 增加月数    

    LocalDate plusYears(long years) 增加年数

import java.time.LocalDate; 
import java.time.Month; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-03 下午 13:15 
 */ 
public class Java8TimeMethodPlusDemo1 { 
    public static void main(String[] args) { 
        // 封装 LocalDate 对象参数为2016年2月13日 
        LocalDate localDate = LocalDate.of(2016, Month.FEBRUARY, 13); 
//          当前时间是:2016-02-13 
        System.out.println("当前时间是:" + localDate); 
        // 计算当前时间的4天后的时间并打印    注意:返回的是一个新的对象 
        LocalDate localDate1 = localDate.plusDays(4); 
//          当前四天后的时间是:2016-02-17 
        System.out.println("当前四天后的时间是:" + localDate1); 
        // 计算当前时间的3周后的时间并打印 
        LocalDate localDate2 = localDate.plusWeeks(3); 
//          当前三周后的时间是:2016-03-05 
        System.out.println("当前三周后的时间是:" + localDate2); 
        // 计算当前时间的5个月后的实际教案并打印 
        LocalDate localDate3 = localDate.plusMonths(5); 
//          当前五个月后的时间是:2016-07-13 
        System.out.println("当前五个月后的时间是:" + localDate3); 
        // 计算当前时间的2年后的时间并打印 
        LocalDate localDate4 = localDate.plusYears(2); 
//          当前两年后的时间是:2018-02-13 
        System.out.println("当前两年后的时间是:" + localDate4); 
    } 
}

结果

 

minus方法与以上类似。

 

十四、plus方法在LocalTime中的使用

LocalTime中定义了多种对事件进行增减操作的方法

LocalTime plusNanos(long nanos) 增加纳秒

LocalTime plusSeconds(long seconds) 增加秒

LocalTime plusMinutes(long minutes) 增加分钟

LocalTime plusHours(long hours) 增加小时

import java.time.LocalTime; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-03 下午 13:29 
 */ 
public class Java8TimeMethodPlusDemo2 { 
    public static void main(String[] args) { 
        // 封装 LocalTime对象参数为8点14分39秒218纳秒 
        LocalTime localTime = LocalTime.of(8, 14, 39, 218); 
//        当前时间是:08:14:39.000000218 
        System.out.println("当前时间是:" + localTime); 
        // 计算当前事件500纳秒后的时间并打印 
        LocalTime localTime1 = localTime.plusNanos(500); 
//        当前时间500纳秒后是:08:14:39.000000718 
        System.out.println("当前时间500纳秒后是:" + localTime1); 
        // 计算当前时间45秒后的时间并打印 
        LocalTime localTime2 = localTime.plusSeconds(45); 
//        当前时间45秒后是:08:15:24.000000218 
        System.out.println("当前时间45秒后是:" + localTime2); 
        // 计算当前时间19分钟后的时间并打印 
        LocalTime localTime3 = localTime.plusMinutes(19); 
//        当前时间19分钟后是:08:33:39.000000218 
        System.out.println("当前时间19分钟后是:" + localTime3); 
        // 计算当前时间3小时后的时间并打印 
        LocalTime localTime4 = localTime.plusHours(3); 
//        当前时间3小时后是:11:14:39.000000218 
        System.out.println("当前时间3小时后是:" + localTime4); 
    } 
}

结果

 

 

十五、plus的单独使用方式1

本文中都是使用plusXXX的方法进行演示,

实际上也有对应的减少方法,以minus开头的方法对应的即为减少,实际上也有对应的减少方法,以minus开头的方法对应的即为减少,实际上minus方法调用的也是plus方法,只不过传入的参数是负数。

plus 和 minus 方法的应用

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

plus(long amountToadd, TemporalUnit unit)  LocalTime

plus(TemporalAmount amoutToadd)       LocalTime

TemporalAmount 是一个接口,当接口作为方法的参数的时候,实际上传入的是接口的实现类对象,根据查看这个接口的体系,可以看到这个接口有一个实现类,名字叫做Period,在学习第一节的时候,说明了这个 类表示一段时间。

 
 

如何使用Period来表示一段时间呢?这个类本身提供了of(int year, int month, int day)来表示,例如:Period.of(1,2,3)返回的对象即为1年2个月3天这么一个时间段。

import java.time.LocalDateTime; 
import java.time.Period; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-03 下午 13:48 
 * 今天程序员小张查看自己的车辆保险记录的时候看到还有2年3月8天就到期了,计算到期的时间是什么时候 
 */ 
public class Java8TimeMethodPlusDemo3 { 
    public static void main(String[] args) { 
        // 1、封装当前时间  -> now方法 
        LocalDateTime now = LocalDateTime.now(); 
        // 2、在当前时间的基础上进行+2年,+3月,+8天的操作 
        // 然后获得一个截止日期对象,这个对象表示的时间就是保险到期的时间。 
        LocalDateTime endTime = now.plusYears(2).plusMonths(3).plusDays(8); 
//        当前的时间是:2020-05-03T13:52:34.316278400保险到期的时间是:2022-08-11T13:52:34.316278400 
        System.out.println("当前的时间是:" + now + "保险到期的时间是:" + endTime); 
 
        // plus(TemporalAmount amountToAdd) 
        // 1、首先封装 priod.of()方法传进去参数 
        Period period = Period.of(2, 3, 8); 
        // 2、通过 now()方法的 plus()方法传进去 
        LocalDateTime endTime1 = now.plus(period); 
//        当前的时间是:2020-05-03T14:06:16.239460900保险到期的时间是:2022-08-11T14:06:16.239460900 
        System.out.println("当前的时间是:" + now + "保险到期的时间是:" + endTime1); 
    } 
}

结果

 

十六、plus的单独使用方式2

plus(long amountToadd, TemporalUnit unit)

在实际开发过程中,可能还会更精准的去操作日期或者说增加一些特殊的时间,比如说1个世纪、1个半天,1千年,10年等,Java8提供了这些日期的表示方式而不需要去单独进行计算了。

TemporalUnit是一个接口,通过查看体系接口发现,可以使用子类ChronoUnit来表示,ChronoUnit封装了很多时间段供我们使用。

import java.time.LocalDateTime; 
import java.time.Month; 
import java.time.temporal.ChronoUnit; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-03 下午 14:41 
 * 
 * 结婚10年称为锡婚,2020年2月2日11点11分11秒成为对称日,如果在那天结婚了,那么锡婚会发生在什么时候? 
 */ 
public class Java8TimeMethodPlusDemo4 { 
    public static void main(String[] args) { 
        // 封装一个日期,表示结婚的时间电 
        LocalDateTime marriedTime = LocalDateTime.of(2020, Month.FEBRUARY, 2, 11, 11, 11); 
        // 使用 plus方法进行计算 
        LocalDateTime time = marriedTime.plus(1, ChronoUnit.DECADES); 
//        如果在2020-02-02T11:11:11,那么锡婚在:2030-02-02T11:11:11 
        System.out.println("如果在" + marriedTime + ",那么锡婚在:"  + time); 
        // 如果锡婚后的半天需要请所有的亲戚朋友吃饭,那么计算吃饭的时间节点\ 
        LocalDateTime eating = time.plus(1, ChronoUnit.HALF_DAYS); 
//          吃饭的时间是:2030-02-02T23:11:11 
        System.out.println("吃饭的时间是:" + eating); 
    } 
}

结果

 

十七、with方法的使用方式1

with方法在LocalDateTime类的应用

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

LocalDateTime 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) 修改年

import java.time.LocalDateTime; 
import java.time.Month; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-03 下午 14:59 
 */ 
public class Java8TimeMethodWithDemo1 { 
    public static LocalDateTime getTime(){ 
        return LocalDateTime.of(1999, Month.DECEMBER,12,12,12,0); 
    } 
    public static void main(String[] args) { 
        LocalDateTime time = getTime(); 
        // 经过使用之后发现time中的时间有错误,应该日期是1号 
        // 在不知道原有时间的基础山,无法进行增减操作,所以可以直接使用with方法进行修改 
        LocalDateTime resultTime = time.withDayOfMonth(1); 
//          修改前错误的时间是:1999-12-12T12:12,正确的时间是:1999-12-01T12:12 
        System.out.println("修改前错误的时间是:" + time + ",正确的时间是:" + resultTime); 
    } 
}

结果

 

十八、with方法的使用方式2

with(TemporalField field, long newValue)

temporalField是一个接口,通过查看体系结构,可以使用它的子类

ChronoField,ChronoField中封装了一些日期时间中的组成成分,可以直接选择之后传入第二个参数进行修改。

例如:with(ChronoField.DAY_OFMONTH,1);将日期中的月份中的天数改为1

例如:with(ChronoField.YEAR,2021);将日期中的年份改为2021。

import java.time.LocalDateTime; 
import java.time.Month; 
import java.time.temporal.ChronoField; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-03 下午 15:16 
 */ 
public class Java8TimeMethoodWithDemo2 { 
    public static LocalDateTime getTime() { 
        return LocalDateTime.of(1999, Month.DECEMBER,12,12,12,0); 
    } 
    public static void main(String[] args) { 
        LocalDateTime time = getTime(); 
        // 经过使用之后发现time中的事件有错误,应该是1号 ->在不知道原有时间的基础上,无法进行增减操作,所以可以直接使用with方式进行修改 
        LocalDateTime resultTime = time.with(ChronoField.DAY_OF_MONTH, 1); 
//        修改前:1999-12-12T12:12 
        System.out.println("修改前:" + time); 
//        修改后:1999-12-01T12:12 
        System.out.println("修改后:" + resultTime); 
    } 
}

结果

 

十九、章节练习(2)

import java.time.LocalDateTime; 
import java.time.Month; 
import java.time.Period; 
import java.time.temporal.TemporalAdjuster; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-03 下午 15:23 
 * 
 * 使用三种方式计算2019年7月19日14时38分34秒后的3年7个月18天后是什么时候? 
 */ 
public class Java8TimeMethodTest { 
    public static void main(String[] args) { 
        // 封装一个当前时间 -> of方法 
        LocalDateTime time = LocalDateTime.of(2019, Month.JULY, 19, 14, 38, 34); 
        // 通过 Period 封装一个时间段表示3年7个月18天 
        Period period = Period.of(3, 7, 18); 
        LocalDateTime endTime = time.plus(period); 
//        当前时间时:2019-07-19T14:38:34,3年7个月18天的日期是:2023-03-09T14:38:34 
        System.out.println("当前时间时:" + time + ",3年7个月18天的日期是:" + endTime); 
    } 
}

结果

 

 二十、TemporalAdjuster调节器的使用

调节器TemporalAdjuster与查询TemporalQuery

with(TemporalAdjuster adjuster)

在上一节学习的with方法中学习了可以通过with方法修改日期时间对象中封装的数据,但是有一些时候可能会做一些复杂的操作,

比如说将时间调整到下个周的周日,下一个工作日,或者本月中的某一天,这个时候可以使用调节器TemporalAdjuster来更方便的处理日期。

with方法有一个重载形式,需要传入一个TemporalAdjuster对象,通过查看发现TemporalAdjuster是一个接口,那么实际上传入的是这个接口的实现类对象。

 

 

在以上的描述中,发现了一个叫做TemporalAdjusters的类可以给我们提供一些常用的方法,方法如下:

TemporalAdjusters类中常用静态方法的使用

static TemporalAdjuster firstDayofNextMonth()   下个月的第一天

static TemporalAdjuster firstDayOfNextYear()   下一年的第一天

static TemporalAdjuster firstDayOfYear()    当年的第一天

import java.time.LocalDate; 
import java.time.temporal.TemporalAdjusters; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-03 下午 15:46 
 */ 
public class Java8TimeTemporalAdjusterDemo1 { 
    public static void main(String[] args) { 
        // 封装日期时间对象为当前时间 
        LocalDate now = LocalDate.now(); 
 
        // 通过 with方法传入 TemporalAdjuster类的实现对象,就可以进行更改 
        // 实现类对象是由 TemporalAdjusters类的静态方法来提供。修改时间为当月的第一天 
        LocalDate firstDayOfMonth = now.with(TemporalAdjusters.firstDayOfMonth()); 
//        将时间修改为当月的第一天,具体时间为:2020-05-01 
        System.out.println("将时间修改为当月的第一天,具体时间为:" + firstDayOfMonth); 
        // 修改时间为下个月的第一天 
        LocalDate firstDayOfNextmonth = now.with(TemporalAdjusters.firstDayOfNextMonth()); 
//        下个月的第一天:2020-06-01 
        System.out.println("下个月的第一天:" + firstDayOfNextmonth); 
        // 修改时间为下一年的第一天 
        LocalDate firstDayOfNextyear = now.with(TemporalAdjusters.firstDayOfNextYear()); 
//        下一年的第一天:2021-01-01 
        System.out.println("下一年的第一天:" + firstDayOfNextyear); 
        // 修改时间为本年的第一天 
        LocalDate firstDayOfYear = now.with(TemporalAdjusters.firstDayOfYear()); 
//        本年的第一天:2020-01-01 
        System.out.println("本年的第一天:" + firstDayOfYear); 
        // 修改时间为本月的最后一天 
        LocalDate lastDayOfMonth = now.with(TemporalAdjusters.lastDayOfMonth()); 
//        本月的最后一天:2020-05-31 
        System.out.println("本月的最后一天:" + lastDayOfMonth); 
        // 修改时间为本年的最后一天 
        LocalDate lastDayOfYear = now.with(TemporalAdjusters.lastDayOfYear()); 
//        本年的最后一天:2020-12-31 
        System.out.println("本年的最后一天:" + lastDayOfYear); 
    } 
}

结果

注意:TemporalAdjusters 是一个接口,with方法实际上传入的是这个饥饿口的实现类对象,TemporalAdjusters并不是TemporalAdjuster的实现类,

只不过TemporalAdjusters的静态方法实现了TemporalAdjuster,并且将实现类对象返回了。

 

 二十一、DayOfWeek枚举类使用

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

import java.time.DayOfWeek; 
import java.time.LocalDate; 
import java.time.temporal.TemporalAdjusters; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-03 下午 16:07 
 */ 
public class Java8TimeTemporalAdjusterDemo2 { 
    public static void main(String[] args) { 
        // 封装日期对象为当前时间 
        LocalDate now = LocalDate.now(); 
        // 将当前时间修改为下一个周日 
        LocalDate s = now.with(TemporalAdjusters.next(DayOfWeek.SUNDAY)); 
//        下一个周日是:2020-05-10 
        System.out.println("下一个周日是:" + s); 
        // 将当前时间修改为上一个周三 
        LocalDate w = now.with(TemporalAdjusters.previous(DayOfWeek.WEDNESDAY)); 
//        上一个周三是:2020-04-29 
        System.out.println("上一个周三是:" + w); 
 
    } 
}

结果

 

二十二、自定义TemporalAdjuster调节器

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

1、创建类实现TemporalAdjuster接口

2、实现TemporalAdjuster中的 adjusterInto()方法,传入一个日期时间对象,完成逻辑之后返回日期事件对象。

3、通过with方法传入自定义调节器对象完成更改。

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

/** 
 * @author LiuHuaXiong 
 * @create 2020-05-03 下午 16:17 
 * 
 * 假如员工一个月中领取工资,发薪日是每个月的15日,如果发薪日是周末,则调整为周五。 
 * 
 * 之后会传入一个日期时间对象,判断是不是15号,如果不是就修改为15号,如果是周六或者是周日,则改为周五(上一个) 
 */ 
public class PayDayAdjuster implements TemporalAdjuster { 
 
    @Override 
    public Temporal adjustInto(Temporal temporal) { 
        // Temporal 是time包下所有日期事件类对象的顶级父接口,实际上可以理解为传入的是 LocalDate或者 LocalTime对象 
        // 1、需要将 temporal 转换为 LocalDate 对象 
        LocalDate payDay = LocalDate.from(temporal); 
        // 2、判断当前封装的时间中的日期是不是当月15号,如果不是就修改为15 
        int day; 
        if(payDay.getDayOfMonth() != 15) { 
            day = 15; 
        }else { 
            day = payDay.getDayOfMonth(); 
        } 
        // 将 payDay中的值改为15 
        LocalDate realPayDay = payDay.withDayOfMonth(day); 
        // 3、判断 readPayDay 对象中封装的星期数是不是周六或者是周日,如果是就改为上一周周五 
        if (realPayDay.getDayOfWeek() == DayOfWeek.SUNDAY || 
                realPayDay.getDayOfWeek() == DayOfWeek.SATURDAY) { 
            // 如果发薪日是周末则修改为上一个周五 
            realPayDay = realPayDay.with(TemporalAdjusters.previous(DayOfWeek.FRIDAY)); 
        } 
        return realPayDay; 
    } 
}
import java.time.LocalDate; 
import java.time.Month; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-03 下午 16:33 
 */ 
public class Java8TimeTemporalAdjusterDemo3 { 
    public static void main(String[] args) { 
        // 封装 LocalDate 对象为2018年12月1日 
        LocalDate payDay = LocalDate.of(2018, Month.DECEMBER, 15); 
        // 计算 payDay 的真实发薪日是什么时候 
        LocalDate realPayDay = LocalDate.from(new PayDayAdjuster().adjustInto(payDay)); 
//        预计的发薪日是:2018-12-15 
        System.out.println("预计的发薪日是:" + payDay); 
//        真实的发薪日是:2018-12-14 
        System.out.println("真实的发薪日是:" + realPayDay); 
    } 
}

结果

 

二十三、TemporalQuery的应用

学习的时态类对象(LocalDate,LocalTime)都有一个方法叫做query,可以针对日期进行查询,R    query(TemporalQuery query)这个方法是一个泛型方法,返回的数据就是传入的泛型类的类型,TemporalQuery是一个泛型接口,里面有一个抽象方法是R    queryFrom(TemporalAccessor temporal)TemporalAccessor是Temporal的父接口,实际上也就是LocalDate,LocalDateTime相关类的顶级父接口,这个queryFrom的方法的实现逻辑就是,传入一个日期/时间对象通过自定义逻辑返回数据。

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

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

import java.time.LocalDate; 
import java.time.Month; 
import java.time.temporal.ChronoUnit; 
import java.time.temporal.TemporalAccessor; 
import java.time.temporal.TemporalQuery; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-02 下午 12:06 
 */ 
// 获取某一天距离下一个劳动节相隔天数的实现类 
public class UtilDayQueryImpl implements TemporalQuery<Long> { 
    @Override 
    public Long queryFrom(TemporalAccessor temporal) { 
        // 1、TemporalAccessor是LocalDateTime的顶级父接口,相当于LocalDate就是这个接口,将Temporal转换为 
        // LocalDate 进行使用 
        LocalDate now = LocalDate.from(temporal); 
        // 2、封装当年劳动节时间 
        LocalDate laborDay = LocalDate.of(now.getYear(), Month.MAY, 1); 
        // 3、判断当前时间是否已经超过了当年的劳动节 
        if (now.isAfter(laborDay)) { 
            laborDay = laborDay.plusYears(1); 
        } 
        // 4、通过ChronoUnit的between来计算两个时间电的差额 
        long days = ChronoUnit.DAYS.between(now, laborDay); 
        return days; 
    } 
}
import java.time.LocalDate; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-02 下午 12:35 
 */ 
public class Java8TimeTemporalQueryDemo1 { 
    public static void main(String[] args) { 
        // 计算距离下一个劳动节还有多少天 
        LocalDate now = LocalDate.now(); 
        // 调用now的query方法,然后将我们自己的实现类UtilDayQueryImpl作为参数传入 
        Long day = now.query(new UtilDayQueryImpl()); 
//        2020-05-03 
        System.out.println(now); 
//        363 
        System.out.println(day); 
    } 
}

结果

 

 

二十四、章节练习(3)

import java.time.LocalDate; 
import java.time.Month; 
import java.time.temporal.ChronoUnit; 
import java.time.temporal.TemporalAccessor; 
import java.time.temporal.TemporalQuery; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-02 下午 12:51 
 */ 
public class TestQueryImpl implements TemporalQuery<Long[]> { 
//    计算任意时间与下一个圣诞节/儿童节/劳动节各相差多少天 
 
    /** 
     * 
     * @param temporal 
     * @return 表示距离三个节日天数差额,0-圣诞节,1-儿童节,2-劳动节 
     */ 
    @Override 
    public Long[] queryFrom(TemporalAccessor temporal) { 
        // 1、将传入的参数转换为LocalDate对象 
        LocalDate date = LocalDate.from(temporal); 
        // 2、封装当年的圣诞节/儿童节/劳动节的日期时间对象 
        LocalDate d1 = LocalDate.of(date.getYear(), Month.DECEMBER, 25); 
        LocalDate d2 = LocalDate.of(date.getYear(), Month.JUNE, 1); 
        LocalDate d3 = LocalDate.of(date.getYear(), Month.MAY, 1); 
        // 3、判断date是否已经超过了d1/d2/d3 
        if (date.isAfter(d1)) { 
            d1 = d1.plusYears(1); 
        } 
        if (date.isAfter(d2)) { 
            d2 = d2.plusYears(1); 
        } 
        if (date.isAfter(d3)) { 
            d3 = d3.plusYears(1); 
        } 
        Long[] lon = {ChronoUnit.DAYS.between(date,d1),ChronoUnit.DAYS.between(date,d2), 
                        ChronoUnit.DAYS.between(date,d3)}; 
        return lon; 
    } 
}
import java.time.LocalDate; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-02 下午 13:04 
 */ 
public class Java8TimeTemporalQueryTest2 { 
    public static void main(String[] args) { 
 
        // 1、封装任意日期 
        LocalDate date = LocalDate.of(2020, 5, 30); 
        // 2、调用date 对象的query方法查询距离三个节日的差额 
        Long[] query = date.query(new TestQueryImpl()); 
        // 3、打印结果 
//        209 
        System.out.println(query[0]); 
//        2 
        System.out.println(query[1]); 
//        336 
        System.out.println(query[2]); 
    } 
}

结果

 

二十五、java.util.Date转换为java.time.LocalDate(1)

对于老项目的改造,需要将Date或者Calendar转换为java.util包中相应的类的,可以根据本小节中提供的方法进行改造。

Java8中的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对象,通过给Instan添加时区信息之后就可以转换为LocalDate对象。

import java.time.Instant; 
import java.time.LocalDate; 
import java.time.ZoneId; 
import java.time.ZonedDateTime; 
import java.util.Date; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-02 下午 13:14 
 */ 
public class Java8DateToLocalDateDemo1 { 
    public static void main(String[] args) { 
        // 初始化Date()对象 
        Date d = new Date(); 
        // 1、将Date()对象转换成Instant对象 
        Instant i = d.toInstant(); 
        // 2、Date类包含日期和时间信息,但是不提高时区信息,和Instant一样,通过Instant的anZone()来进行添加时区信息 
        ZonedDateTime zonedDateTime = i.atZone(ZoneId.systemDefault()); 
        // 3、通过LocalDate方法转换 
        LocalDate date = zonedDateTime.toLocalDate(); 
//        转换之前Sun May 03 17:21:18 CST 2020 
        System.out.println("转换之前" + d); 
//        转换之后2020-05-03 
        System.out.println("转换之后" + date); 
 
    } 
}

结果

 

二十六、java.sql.Date与java.sql.Timestamp的转换方式

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

java.sql.Timestamp类是时间戳对象,通过传入一个毫秒值对象进行初始化

 

import java.sql.Date; 
import java.sql.Timestamp; 
import java.time.LocalDate; 
import java.time.LocalDateTime; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-02 下午 13:21 
 */ 
public class Java8DateToLocalDemo2 { 
    public static void main(String[] args) { 
        // 初始化 java.sql.Date 对象 
        Date d = new Date(System.currentTimeMillis()); 
        // java.sql.Date 自带了转换成LocalDate 的方法, toLocalDate. 
        LocalDate date = d.toLocalDate(); 
//        转换前的java.sql.Date对象是:2020-05-03 
        System.out.println("转换前的java.sql.Date对象是:" + d); 
//        转换后的java.time.LocalDate对象是:2020-05-03 
        System.out.println("转换后的java.time.LocalDate对象是:" + date); 
 
        // 初始化java.sql.Timestamp对象,  世界戳对象 
        Timestamp timestamp = new Timestamp(System.currentTimeMillis()); 
        // java.sql.Timestamp 中也自带了转换成LocalDate 的方法  toLocalDate 
        LocalDateTime localDateTime = timestamp.toLocalDateTime(); 
//        转换之前的java.sql.Timestamp对象是:2020-05-03 17:25:29.057 
        System.out.println("转换之前的java.sql.Timestamp对象是:" + timestamp); 
//        转换之后的java.time.LocalDateTime对象是:2020-05-03T17:25:29.057 
        System.out.println("转换之后的java.time.LocalDateTime对象是:" + localDateTime); 
    } 
}

结果

 

二十七、java.util.Date转换为java.time.LocalDate方式(2)

将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()方法获取到。

import java.time.LocalDate; 
import java.util.Date; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-03 下午 17:34 
 */ 
public class Java8DateToLocalDateDemo4 { 
    public static void main(String[] args) { 
        // 初始化 Date对象 
        Date d = new Date(); 
        /* 
        * java.sql.Date类提供了转换为LocalDate的方法,那么可以将java.util.Date先转换为java.sql.Date 
        * 通过java.sql.Date提供的方式转换为LocalDate. 
        * java.sql.Date类构造的时候需要毫秒值, -> java.Util.Date类中提供了一个获取毫秒值的方法, getTime() 
        * */ 
        java.sql.Date date = new java.sql.Date(d.getTime()); 
        LocalDate localDate = date.toLocalDate(); 
//        转换前的java.util.Date对象是:Sun May 03 17:39:46 CST 2020 
        System.out.println("转换前的java.util.Date对象是:" + d); 
//        转换前的java.sql.Date对象是:2020-05-03 
        System.out.println("转换前的java.sql.Date对象是:" + date); 
//        转换前的java.time.LocalDate对象是:2020-05-03 
        System.out.println("转换前的java.time.LocalDate对象是:" + localDate); 
    } 
}

看结果

 

二十八、Calendar转换为ZonedDateTime

Calendar对象字Java1.1开始提供了一个方法获取时区对象的方法,getTimeZone(),要将Calendar对象转换为ZonedDateTime需要先获取到时区对象。

从Java1.8开始TimeZone类提供了一个方法可以获取到ZonedId。

获取到ZonedId之后就可以初始化ZOnedDateTime对象了,ZonedDateTime类有一个ofInstant()方法,可以将一个Instant对象和ZonedId对象作为参数传入构造一个ZonedDateTime对象。

 

import java.time.ZoneId; 
import java.time.ZonedDateTime; 
import java.util.Calendar; 
import java.util.TimeZone; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-02 下午 13:47 
 */ 
public class Java8TimeCalendarToZoneedDateTimeDemo1 { 
    public static void main(String[] args) { 
 
//        1、初始化一个Calendar对象 
        Calendar calendar = Calendar.getInstance(); 
//        2、Calendar对象自java1.1以后开始提供了一个方法用于获取时区对象getTimeZone()方法,要将Calendar转换为 
//        ZoneedDateTime对象需要先获取到时区对象 
        TimeZone timeZone = calendar.getTimeZone(); 
//        3、从java1.8开始TimeZone类提供了一个方法可以获取到ZoneId -> 拿拿ZoneId对象来构建ZonedDateTime 
        ZoneId zoneId = timeZone.toZoneId(); 
//        4、zonedDateTime类有一个ofInstant方法。可以将Instant对象和ZoneId对象封装为一个ZonedDateTime 
        ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(calendar.toInstant(), zoneId); 
//        转换之前的Calendar对象是:java.util.GregorianCalendar[time=1588499141905,areFieldsSet=true,areAll 
//        FieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Shanghai",....... 
        System.out.println("转换之前的Calendar对象是:" + calendar); 
//        转换之后的ZonedDateTime对象是:2020-05-03T17:45:41.905+08:00[Asia/Shanghai] 
        System.out.println("转换之后的ZonedDateTime对象是:" + zonedDateTime); 
    } 
}

结果

 

二十九、Calendar转换为LocalDateTime

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

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

import java.time.LocalDateTime; 
import java.util.Calendar; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-02 下午 14:07 
 */ 
public class Java8TimeCalendarToLocalDateTimeDemo1 { 
    public static void main(String[] args) { 
 
        // 1、初始化Calendar对象 
        Calendar calendar = Calendar.getInstance(); 
        // 2、通过get获取Calendar对象中封装的数据 
        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); 
        // 3、将以上获取的六个参数作为LocalDateTime的of方法的参数传递,封装的月份是从0开始的,所以month要加1 
        LocalDateTime localDateTime = LocalDateTime.of(year, month + 1, day, hour, minute, second); 
//        2020-05-03T05:49:23 
        System.out.println(localDateTime); 
    } 
}

结果

 

三十、新日期实践类的parse和format方法

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

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

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

LocalDate类定义的parse和format方法

import java.time.LocalDateTime; 
import java.time.format.DateTimeFormatter; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-02 下午 14:16 
 */ 
public class java8TimeFormatAndParseDemo1 { 
    public static void main(String[] args) { 
        // 对LoacalDateTime进行格式化和解析,初始化LocalDateTime对象 
        LocalDateTime localDateTime = LocalDateTime.now(); 
        // localDateTime对象可以直接调用format方法进行格式化 
        String s1 = localDateTime.format(DateTimeFormatter.ISO_DATE); 
        String s2 = localDateTime.format(DateTimeFormatter.ISO_DATE_TIME); 
//        LocalDateTime:2020-05-03T17:55:04.194526800 
        System.out.println("LocalDateTime:" + localDateTime); 
//        ISO_DATE:2020-05-03 
        System.out.println("ISO_DATE:" + s1); 
//        ISO_DATE_TIME:2020-05-03T17:55:04.1945268 
        System.out.println("ISO_DATE_TIME:" + s2); 
        // 解析字符串的方式通过LocalDateTime类的静态方法parse传入需要解析的字符串即可 
        LocalDateTime parse = LocalDateTime.parse(s2); 
//        2020-05-03T17:55:04.194526800 
        System.out.println(parse); 
 
    } 
}

结果

 

 三十一、ofLocalizedDate方法

对日期进行格式化

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

public static DateTimeFormatter ofLocalizedDate(FormatStyle dateStyle) { 
 
    Objects.requireNonNull(dataStyle, message:"dateStyle"); 
 
    return new DateTimeFormatterBuilder().appendLocalized(dateStyle,timeStyle:"null") 
 
            .toFormatter(ResolverStyle.Smart, IsoChronology.Instance); 
 
} 

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

Full:全显示(年月日+星期) Long:全显示(年月日) Medium:缩略显示(没有年月日汉字) SHORT:精简显示(精简年+月日)

import java.time.LocalDateTime; 
import java.time.format.DateTimeFormatter; 
import java.time.format.FormatStyle; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-02 下午 14:25 
 */ 
public class Java8TimeFormatAndParseDemo2 { 
    public static void main(String[] args) { 
        LocalDateTime localDateTime = LocalDateTime.now(); 
        // 通过DateTimeFormatter 的 ofLocalizedDate指定解析格式 
        String r1 = localDateTime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL)); 
        String r2 = localDateTime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG)); 
        String r3 = localDateTime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)); 
        String r4 = localDateTime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT)); 
 
//        FULL:2020年5月3日星期日 
        System.out.println("FULL:" + r1); 
//        LONG:2020年5月3日 
        System.out.println("LONG:" + r2); 
//        MEDIUM:2020年5月3日 
        System.out.println("MEDIUM:" + r3); 
//        SHORT:2020/5/3 
        System.out.println("SHORT:" + r4); 
    } 
}

结果

 

 三十二、自定义格式化器

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

 

import java.time.LocalDateTime; 
import java.time.format.DateTimeFormatter; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-02 下午 14:31 
 */ 
public class Java8TimeFormatAndParseDemo3 { 
    public static void main(String[] args) { 
        LocalDateTime now = LocalDateTime.now(); 
        // 通过DateTimeFormatter 提供的ofPattern方法自定义格式化方式 
        String s = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS")); 
//        2020/05/03 18:07:44:859 
        System.out.println(s); 
    } 
}

结果

 

 三十三、章节练习(4)

import java.time.LocalDateTime; 
import java.time.format.DateTimeFormatter; 
 
/** 
 * @author LiuHuaXiong 
 * @create 2020-05-02 下午 14:35 
 *  将1998年3月18日17时19分28秒转换成以下格式: 1998-03月-18---17:19分28秒 -> yyyy-MM月-dd---HH:mm分ss秒 
 */ 
public class Java8TimeFormatAndParseTest1 { 
    public static void main(String[] args) { 
        // 初始化一个LocalDateTime对象 
        LocalDateTime time = LocalDateTime.of(1998, 3, 18, 17, 19, 28); 
        // 通过time 对象的 format方法自定义格式化器完成格式化 
        String s = time.format(DateTimeFormatter.ofPattern("yyyy-MM月-dd---HH:mm分ss秒")); 
//        1998-03月-18---17:19分28秒 
        System.out.println(s); 
    } 
}

结果

 

 


作者:XT_fc0f
链接:https://www.jianshu.com/p/7a1b367ae95f
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
发布评论
IT源码网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

Java源码分析: HashMap 1.8讲解
你是第一个吃螃蟹的人
发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。