java获取月末日期_JavaSE原理-日期类API

学习目标

掌握Java8中的提供的java.time包中的常用日期类与相关方法

可以从java.util包的下的日期类相关类过渡到java.time包下的日期类

掌握Java8中的日期与字符串之间的相互转换

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

将java.util.Date类束之高阁才是正确之道 -> Tim Yates

在Java面世之初,标准库就引入了两种用于处理日期和时间的类,它们是

java.util.Date和java.util.Calendar,而前者堪称类糟糕设计的典范,浏览

API可以发现,从Java1.1开始,Date类中的所有方法就已经被弃用,Java1.1推

荐采用Calendar类处理日期和时间,但是这个类同样存在不少问题.

对于日期的计算困难问题.

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

package com.itheima.time;

import java.util.Calendar;

import java.util.Date;

/**

* 计算当前时间距离2000年6月1日相差了多少天.

*

* 通过距离1970年1月1日的毫秒差值,可以计算出两个日期之间相隔的天数.

*/

public class JavaUtilTimeDemo01 {

public static void main(String[] args) {

//1.初始化Date对象,无参构造(无参构造默认代表的就是当前时间)

Date dateNow = new Date();

//2.获取当前时间的距离1970年1月1日过了多少毫秒.

long dateTimeNow = dateNow.getTime();

//3.初始化Calendar对象并设时间为2006年6月1日并且将Calendar对象转换

为Date对象.

Calendar paramterTime = Calendar.getInstance();

paramterTime.set(2000, Calendar.JUNE, 1);

线程安全问题

SimpleDateFormat类是线程不安全的,在多线程的情况下,全局共享一个

SimpleDateFormat类中的Calendar对象有可能会出现异常.

Date paramterDateTime = paramterTime.getTime();

//4.计算paramterDateTime与dateTimeNow之间的毫秒差额.

Long intervalTime = dateTimeNow -

paramterDateTime.getTime();

//5.对intervalTime进行计算获取差额,毫秒值/1000->/60->/60->/24

long intervalDay = intervalTime / 1000 / 60 / 60 / 24;

System.out.println("当前时间距离2000年6月1日已经过了" +

intervalDay+"天.");

}

}

package com.itheima.time;

import java.text.ParseException;

import java.text.SimpleDateFormat;

public class JavaUtilTimeDemo02 {

//创建SimpleDateFormat的对象(单例)

static SimpleDateFormat SIMPLEDATEFORMAT = new

SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

public static void main(String[] args) {

//创建10个线程并启动.

for (int i = 0; i < 10; i++) {

new Thread(() -> {

try {

System.out.println(SIMPLEDATEFORMAT.parse("2018-12-12 12:12:12"));

} catch (ParseException e) {

e.printStackTrace();

}

}).start();

}

}

}

另外的一个问题就是在java.util.Date和java.util.Calendar类之前,枚举

类型(ENUM)还没有出现,所以在字段中使用整数常量导致整数常量都是可变的,

而不是线程安全的.为了处理实际开发中遇到的问题,标准库随后引入了

java.sql.Date作为java.util.Date的子类,但是还是没能彻底解决问题.

最终JavaSE 8中引入了java.time包,这种全新的包从根本上解决了长久以来的

存在的诸多弊端,java.time包基于Joda-Time库构件,是一种免费的开源解决

方案,实际上在Java 8没有出现之前,公司中已经广泛使用Joda-Time来解决

Java中的日期与时间问题,Joda-Time的设计团队也参与了java.time包的开

发.

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

常用类的概述与功能介绍

Instant类

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

后学习的类型转换中,均可以使用Instant类作为中间类完成转换.

Duration类

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

Period类

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

LocalDate类

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

LocalTime类

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

示为纳秒精度.

LocalDateTime类

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

时-分-秒.

ZonedDateTime类

ZonedDateTime是具有时区的日期时间的不可变表示,此类存储所有日期和时间字段,精

度为纳秒,时区为区域偏移量,用于处理模糊的本地日期时间。

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

Date-Time API中的所有类均生成不可变实例,它们是线程安全的,并且这些类

不提供公共构造函数,也就是说没办法通过new的方式直接创建,需要采用工厂方

法加以实例化.

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

package com.itheima.time;

import java.time.*;

各个类封装时间所表示的特点

Instant封装的时间为祖鲁时间并非当前时间.

祖鲁时间也是格林尼治时间,也就是国际标准时间.

LocalDate封装的只有年月日,没有时分秒,格式为yyyy-MM-dd.

LocalTime封装的只有时分秒,没有年月日,格式为hh:mm:ss.sss,最

后的sss是纳秒.

LocalDateTime将LocalDate和LocalTime合二为一,在年月日与时分

秒中间使用T作为分隔.

ZonedDateTime中封装了年月日时分秒,以及UTC(祖鲁时间)偏移量,并

且还有一个地区名.

+8:00代表中国是东八区,时间比国际标准时间快八小时.

不仅仅是刚才提供的几个类可以使用now方法,Java8的Time包中还提供了其他的几个类可以更精

准的获取某些信息.

Year类(表示年)

YearMonth类(表示年月)

MonthDay类(表示月日)

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();

//将实例对象打印到控制台.

System.out.println("Instant:"+instantNow);

System.out.println("LocalDate:"+localDateNow);

System.out.println("LocalTime:"+localTimeNow);

System.out.println("LocalDateTime:"+localDateTimeNow);

System.out.println("ZonedDateTime:"+zonedDateTimeNow);

}

}

package com.itheima.time;

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

of方法可以根据给定的参数生成对应的日期/时间对象,基本上每个基本类都有

of方法用于生成的对应的对象,而且重载形式多变,可以根据不同的参数生成对

应的数据.

import java.time.*;

public class Java8TimeClassMethodDemo2 {

public static void main(String[] args) {

//初始化Year的实例化对象.

Year year = Year.now();

//初始化YearMonth的实例化对象

YearMonth month = YearMonth.now();

//初始化MonthDay的实例化对象.

MonthDay day = MonthDay.now();

}

}

package com.itheima.time;

import java.time.LocalDate;

import java.time.LocalDateTime;

import java.time.LocalTime;

public class Java8TimeClassMethodDemo3 {

public static void main(String[] args) {

//初始化2018年8月8日的LocalDate对象.

LocalDate date = LocalDate.of(2018, 8, 8);

System.out.println("LocalDate:" + date);

/*

初始化晚上7点0分0秒的LocalTime对象.

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) ->

根据小时/分钟/毫秒/纳秒生成对象.

注意:如果秒和纳秒为0的话,那么默认不会封装这些数据,只显示小时和分钟.

*/

LocalTime time = LocalTime.of(19, 0, 0, 0);

System.out.println("LocalTime:" + time);

/*

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

在学习ZonedDateTime的时候,发现了这个对象里面封装的不仅有时间日期,并且还有偏移量+时

区,那么时区如何在Java中获取呢,通过提供的一个类ZoneId的getAvailableZoneIds方法可以

获取到一个Set集合,集合中封装了600个时区.

初始化2018年8月8日下午7点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 of(LocalDate date, LocalTime time)方法可以将一个

LocalDate对象和一个LocalTime对象合并封装为一个LocalDateTime对象.

*/

LocalDateTime.of(2018, 8, 8, 19, 0, 0, 0);

LocalDateTime localDateTime = LocalDateTime.of(date, time);

System.out.println("LocalDateTime:" + localDateTime);

}

}

//获取所有的时区信息

Set availableZoneIds = ZoneId.getAvailableZoneIds();

for (String zoneId : availableZoneIds) {

System.out.println(zoneId);

}

同样也提供了获取当前系统默认的时区的方式systemDefault()方法.

//获取当前系统默认的时区信息

ZoneId zoneId = ZoneId.systemDefault();

System.out.println(zoneId);

我们可以通过给LocalDateTime添加时区信息来查看到不同时区的时间,比如说LocalDateTime中

当前封装的是上海时间,那么想知道在此时此刻,纽约的时间是什么,就可以将纽约的时区Id添加进

去,就可以查看到了,方式如下.

封装时间LocalDateTime并添加时区信息.

更改时区信息查看对应时间.

Month枚举类的使用

java.time包中引入了Month的枚举,Month中包含标准日历中的12个月份的常

量(从JANURAY到DECEMEBER)也提供了一些方便的方法供我们使用.

推荐在初始化LocalDate和LocalDateTime对象的时候,月份的参数使用枚举的

方式传入,这样更简单易懂而且不易出错,因为如果是老的思维,Calendar传入0

的话,那么会出现异常.

package com.itheima.time;

import java.time.LocalDateTime;

import java.time.ZoneId;

import java.time.ZonedDateTime;

/**

* 为LocalDateTime添加时区信息.

*/

public class Java8TimeClassMethodDemo5 {

public static void main(String[] args) {

//1.封装LocalDateTime对象,参数自定义 -> 2018年11月11日 8点54分38秒

LocalDateTime time = LocalDateTime.of(2018, 11, 11, 8, 54, 38);

//2.封装完成后的time对象只是封装的是一个时间,并没有时区相关的数据,所以添加时区到

对象中,使用atZone方法.

ZonedDateTime zonedDateTime =

time.atZone(ZoneId.of("Asia/Shanghai"));

System.out.println("Asia/Shanghai的时间是:" + zonedDateTime);

//3.更改时区查看其它时区的当前时间,通过withZoneSameInstant方法即可更改.

ZonedDateTime otherZonedTime =

zonedDateTime.withZoneSameInstant(ZoneId.of("Asia/Tokyo"));

System.out.println("在同一时刻,Asia/Tokyo的时间是:" + otherZonedTime);

}

}

/**

* Month枚举类的使用.

练习

按照要求创建对应的时间日期对象并且打印到控制台输出.

创建当前时间(不带时区)

创建当前时间(只包含年月日) 月份使用枚举表示

创建当前时间(包含年月日时分秒并且带有时区) 月份使用枚举表示

创建2012年12年31日7时38分46秒的日期对象 月份使用枚举表示

创建2012年12年31日的日期对象 月份使用枚举表示

创建7时38分46秒的时间对象

通过键盘录入的方式创建2014年11月11日 11时11分11秒的日期对象打印到控制台输出.

3.根据现有实例创建日期与时间对象

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

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) 增加年数

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

LocalTime plusNanos(long nanos) 增加纳秒

LocalTime plusSeconds(long seconds) 增加秒

LocalTime plusMinutes(long minutes) 增加分钟

*/

public class Java8TimeClassMethodDemo6 {

public static void main(String[] args) {

//在初始化LocalDate和LocalDateTime的时候,月份的参数传入枚举类(2011年5月15日

11时11分11秒)

LocalDateTime.of(2011, Month.JUNE,15,11,11,11);

//of方法可以根据传入的数字返回对应的月份.

Month month = Month.of(12);

System.out.println(month);

}

}

LocalTime plusHours(long hours) 增加小时

package com.itheima.time.plus;

import org.junit.Test;

import java.time.LocalDate;

import java.time.Month;

public class Java8TimeMethodPlusDemo1 {

public static void main(String[] args) {

//封装LocalDate对象参数为2016年2月13日.

LocalDate date = LocalDate.of(2016, Month.FEBRUARY, 13);

//计算当前时间的4天后的时间.

LocalDate plusDaysTime = date.plusDays(4);

//计算当前时间的周后的时间.

LocalDate plusWeeksTime = date.plusWeeks(3);

//计算当前时间的5个月后的时间.

LocalDate plusMonthsTime = date.plusMonths(5);

//计算当前时间的2年后的时间.

LocalDate plusYearsTime = date.plusYears(2);

System.out.println("当前的时间是:"+date);

System.out.println("4天后的时间是:"+plusDaysTime);

System.out.println("3周后的时间是:"+plusWeeksTime);

System.out.println("5个月后的时间是:"+plusMonthsTime);

System.out.println("2年后的时间是:"+plusYearsTime);

}

}

package com.itheima.time.plus;

import java.time.LocalTime;

public class Java8TimeMethodPlusDemo2 {

public static void main(String[] args) {

//封装LocalTime对象参数为8时14分39秒218纳秒.

LocalTime time = LocalTime.of(8, 14, 39, 218);

//计算当前时间500纳秒后的时间.

LocalTime plusNanosTime = time.plusNanos(500);

//计算当前时间45秒后的时间.

LocalTime plusSecondsTime = time.plusSeconds(45);

//计算当前时间19分钟后的时间.

LocalTime plusMinutesTime = time.plusMinutes(19);

//计算当前时间3小时后的时间.

LocalTime plusHoursTime = time.plusHours(3);

System.out.println("当前的时间是:" + time);

System.out.println("45秒后的时间是:" + plusSecondsTime);

System.out.println("19分钟后的时间是:" + plusMinutesTime);

System.out.println("500纳秒后的时间是:" + plusNanosTime);

System.out.println("3小时后的时间是:" + plusHoursTime);

}

}

本文中都是使用plusXXX的方法进行演示,实际上也有对应的减少

方法,以minus开头的方法对应的即为减少,实际上minus方法调用

的也是plus方法,只不过传入的参数是负数.

plus和minus方法的应用

刚才学习到的plusXXX相关的方法都是添加了数值到具体的某一项上,根据观察

还有两个单独的plus方法,接下来我们来学习这两个单独的plus方法.

plus(TemporaAmount amountToAdd)

TemporaAmount是一个接口,当接口作为方法的参数的时候,实际上传入的是接口的实现

类对象,根据查看这个接口的体系,可以看到这个接口有一个实现类,名字叫做Period,

在学习第一节的时候,说明了这个类表示一段时间.

如何使用Period来表示一段时间呢?这个类本身提供了of(int year,int month,int

day)来表示,例: Period.of(1,2,3)返回的对象表示的即为1年2个月3天

这么一个时间段,我们可以使用plus方法添加这个时间段.

plus(long l,TemporaUnit unit)

在实际开发过程中,可能还会更精准的去操作日期或者说增加一些特殊的时间,比如说1

个世纪,1个半天,1千年,10年等,Java8提供了这些日期的表示方式而不需要去单独进行

计算了.

TemporaUnit是一个接口,通过查看体系接口发现,可以使用子类ChronoUnit来表

示,ChronoUnit封装了很多时间段供我们使用.

package com.itheima.time.plus;

import java.time.LocalDate;

import java.time.Period;

/*

今天程序员小郝在查看自己的车辆保险记录的时候查看到还有2年3个月零8天保险就到期了,

计算2年3个月零8天后的时间是多少.

*/

public class Java8TimeMethodPlusDemo4 {

public static void main(String[] args) {

LocalDate date = LocalDate.now(); //date表示当前时间.

//固然可以使用对于年月日依次+2,+3,+8的方式来操作,但是有些繁琐,首先我

们先将2年3月8天封装为一段时间,也就是封装为一个Period对象.

Period time = Period.of(2, 3, 8);

//使用plus方法对于date对象直接进行增加的操作.

LocalDate endDate = date.plus(time);

System.out.println("今天是" + date + ",保险到期的时间是" +

endDate + ".");

}

}

package com.itheima.time.plus;

import java.time.LocalDate;

import java.time.LocalDateTime;

import java.time.Month;

import java.time.Period;

import java.time.temporal.ChronoUnit;

/*

结婚10年称为锡婚,2020年2月2日11点11分11秒称为对称日,很多情侣准备在那天结婚,如果在那

天结婚了,那么锡婚会发生在什么时候.

*/

public class Java8TimeMethodPlusDemo5 {

public static void main(String[] args) {

LocalDateTime marryTime = LocalDateTime.of(2020,

Month.FEBRUARY, 2, 11, 11, 11);

//使用plus方法进行计算,添加1个,ChronoUnit.DECADES(十年).

LocalDateTime time = marryTime.plus(1, ChronoUnit.DECADES);

System.out.println("如果在" + marryTime + "结婚,那么锡婚是" +

time);

注意第一个参数为单位,第二个参数为时间长度.

例:plus(1, ChronoUnit.DECADES)加1个10年.

plus(1, ChronoUnit.CENTURIES)加1个100年.

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

//如果锡婚后的半天准备要请所有亲戚朋友吃饭,那么吃饭的时间是.

LocalDateTime eatTime = time.plus(1, ChronoUnit.HALF_DAYS);

System.out.println("半天后吃饭,吃饭的时候是:" + eatTime);

}

}

package com.itheima.time.with;

import java.time.LocalDateTime;

public class Java8TimeMethodWithDemo1 {

public static void main(String[] args) {

LocalDateTime time = LocalDateTime.now();

//经过使用发现time中的时间有错误,应该是1日,在不知道原有时间的基础上,无法进

行增减操作,所以可以直接使用with方法进行修改.

LocalDateTime endTime = time.withDayOfMonth(1);

System.out.println("修改前错误的时间是:" + time);

System.out.println("修改完成之后的时间是:" + endTime);

}

}

with(TemporalField field, long newValue)

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

ChronoField,ChronoField中封装了一些日期时间中的组成部分,可以直接选择之后传

入第二个参数进行修改.

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

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

练习

使用三种方式计算2019年7月19日14时38分34秒后的3年7个月18天后是什么时候?

4.调节器TemporalAdjuster与查询TemporalQuery

在上一节学习的with方法中学习了可以通过with方法修改日期时间对象中封装的数

据,但是有一些时候可能会做一些复杂的操作,比如说将时间调整到下个周的周日,下

一个工作日,或者本月中的某一天,这个时候可以使用调节器TemporalAdjuster来

更方便的处理日期.

with方法有一个重载形式,需要传入一个TemporalAdjuster对象,通过查看发现TemporalAdjuster是

一个接口,方法的参数是一个接口,那么实际上传入的是这个接口的实现类对象.

package com.itheima.time.with;

import java.time.LocalDateTime;

import java.time.temporal.ChronoField;

public class Java8TimeMethodWithDemo2 {

public static void main(String[] args) {

LocalDateTime time = LocalDateTime.now();

//经过使用发现time中的时间有错误,应该是1日,在不知道原有时间的基础上,

无法进行增减操作,所以可以直接使用with方法进行修改.

LocalDateTime endTime =

time.with(ChronoField.DAY_OF_MONTH,1);

System.out.println("修改前错误的时间是:" + time);

System.out.println("修改完成之后的时间是:" + endTime);

}

}

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

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

static TemporalAdjuster firsyDayOfNextMonth()

下个月的第一天

static TemporalAdjuster firstDayOfNextYear()

下一年的第一天

static TemporalAdjuster firstDayOfYear()

当年的第一天

static TemporaAdjuster firstInMonth(DayOfWeek dayOfWeek)

当月的第一个周x(通过参数确定)

static TemporaAdjuster lastDayOfMonth()

当月的最后一天

static TemporaAdjuster lastDayOfYear()

当年的最后一天

static TemporaAdjuste lastInMonth(DayOfWeek dayOfWeek)

当月的最后一个周x(通过参数确定)

static TemporaAdjuster next(DayOfWeek dayOfWeek)

下一个周x(通过参数确定)

static TemporaAdjuster previous(DayOfWeek dayOfWeek)

上一个周x(通过参数确定)

TemporalAdjuster是一个函数式接口,里面有一个抽象方法叫做Temporal

adjustInto(Temporal temporal);传入一个Temporal对象通过实现逻辑返回

一个Temporal对象,Temporal是LocalDate,LocalTime相关日期类的父接口,

实际上传入的就是一个时间日期对象返回一个时间日期对象.

package com.itheima.time;

import java.time.LocalDate;

import java.time.Month;

import java.time.temporal.TemporalAdjuster;

import java.time.temporal.TemporalAdjusters;

public class Java8TimeTemporalAdjusterDemo1 {

public static void main(String[] args) {

//封装日期时间对象为当前时间,LocalDate.

LocalDate time = LocalDate.now();

/*

with方法可以修改time对象中封装的数据,需要传入一个TemporalAdjuster对象,

通过查看发现TemporalAdjuster是一个接口,方法的参数是一个接口,那么实际上传入的是

这个接口的实现类对象.

TemporalAdjusters的类可以给我们提供一些常用的方法.

*/

//with方法传入了TemporalAdjuster类的实现对象,是由TemporalAdjusters类的方

法实现了adjustInto方法,当前的逻辑是:将时间修改为当月的第一天.

LocalDate firstDayOfMonth =

time.with(TemporalAdjusters.firstDayOfMonth());

//将时间修改为下个月的第一天.

DayOfWeek的使用

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

LocalDate firstDayOfNextMonth =

time.with(TemporalAdjusters.firstDayOfNextMonth());

//将时间修改为下一年的第一天.

LocalDate firstDayOfNextYear =

time.with(TemporalAdjusters.firstDayOfNextYear());

//将时间修改为本年的第一天.

LocalDate firstDayOfYear =

time.with(TemporalAdjusters.firstDayOfYear());

//将时间修改为本月的最后一天.

LocalDate lastDayOfMonth =

time.with(TemporalAdjusters.lastDayOfMonth());

//将时间修改为本年的最后一天.

LocalDate lastDayOfYear =

time.with(TemporalAdjusters.lastDayOfYear());

System.out.println("当月的第一天是:" + firstDayOfMonth);

System.out.println("下个月的第一天是:" + firstDayOfNextMonth);

System.out.println("下一年的第一天是:" + firstDayOfNextYear);

System.out.println("本年的第一天是:" + firstDayOfYear);

System.out.println("本月的最后一天是:" + lastDayOfMonth);

System.out.println("本年的最后一天是:" + lastDayOfYear);

}

}

package com.itheima.time;

import java.time.DayOfWeek;

import java.time.LocalDate;

import java.time.temporal.TemporalAdjusters;

public class Java8TimeTemporalAdjusterDemo2 {

public static void main(String[] args) {

//封装日期时间对象为当前时间,LocalDate.

LocalDate time = LocalDate.now();

/*

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

*/

//将当前时间修改为下一个周日

LocalDate nextSunday =

time.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));

//将当前时间修改为上一个周三

自定义TemporalAdjuster调节器

通过Java8本身提供的TemporalAdjusters中的方法可以完成一些常用的操作,如果要自定义日期

时间的更改逻辑,可以通过实现TemporalAdjuster类接口中的方式来完成.

创建类实现TemporalAdjuster接口

实现TemporalAdjuster中的adjustInto方法,传入一个日期时间对象,完成逻辑之后返回日

期时间对象.

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

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

LocalDate previousWednesday =

time.with(TemporalAdjusters.previous(DayOfWeek.WEDNESDAY));

System.out.println("下一个周日是:"+nextSunday);

System.out.println("上一个周三是:"+previousWednesday);

}

}

package com.itheima.time.impl;

import java.time.DayOfWeek;

import java.time.LocalDate;

import java.time.temporal.*;

/**

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

*/

public class PayDayAdjuster implements TemporalAdjuster {

@Override

public Temporal adjustInto(Temporal temporal) {

//1.将temporal转换为子类对象LocalDate,from方法可以将任何时态对象转换为

LocalDate.

LocalDate payDay = LocalDate.from(temporal);

//2.判断当前封装的时间中的日期是不是当月15日,如果不是,则更改为15日.

int day;

if (payDay.getDayOfMonth() != 15) {

day = 15;

} else {

day = payDay.getDayOfMonth();

}

LocalDate realPayDay = payDay.withDayOfMonth(day);

//3.判断realPayDay对象中封装的星期数是不是周六或者是周日,如果是周末或者是周日则

更改为周五.

if (realPayDay.getDayOfWeek() == DayOfWeek.SUNDAY ||

realPayDay.getDayOfWeek() == DayOfWeek.SATURDAY) {

//说明发薪日是周末,则更改为周五.

realPayDay =

realPayDay.with(TemporalAdjusters.previous(DayOfWeek.FRIDAY));

}

return realPayDay;

TemporalQuery的应用

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

R query(TemporalQuery query)这个方法是一个泛型方法,返回的数据就是传入的泛型类的类

型,TemporalQuery是一个泛型接口,里面有一个抽象方法是

R queryFrom(TemporalAccessor temporal),TemporalAccessor是Temporal的父接口,实际

上也就是LocalDate,LocalDateTime相关类的顶级父接口,这个queryFrom的方法的实现逻辑就

是,传入一个日期/时间对象通过自定义逻辑返回数据.

}

}

package com.itheima.time;

import com.itheima.time.impl.PayDayAdjuster;

import java.time.DayOfWeek;

import java.time.LocalDate;

import java.time.temporal.TemporalAdjusters;

public class Java8TimeTemporalAdjusterTest1 {

public static void main(String[] args) {

//封装LocalDate对象为2018年12月1日.

LocalDate payDay = LocalDate.of(2019, 12, 1);

//2018年12月15日为周末,所以要提前到周五发放工资,通过自定义调节器完成对时间的修

改.

LocalDate realPayDay = LocalDate.from(new

PayDayAdjuster().adjustInto(payDay));

System.out.println("预计的发薪日是2018年12月15日,实际的发薪日为:" +

realPayDay);

}

}

如果要计划日期距离某一个特定天数差距多少天,可以自定义类实现TemporalQuery接口并且作为

参数传入到query方法中.

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

package com.itheima.time.impl;

import java.time.LocalDate;

import java.time.Month;

import java.time.temporal.ChronoField;

import java.time.temporal.ChronoUnit;

import java.time.temporal.TemporalAccessor;

import java.time.temporal.TemporalQuery;

/**

* 获取某一天距离下一个劳动节的相隔天数的实现类.

*/

public class UntilDayQueryImpl implements TemporalQuery {

@Override

public Long queryFrom(TemporalAccessor temporal) {

//获取当前的年/月/日信息.

int year = temporal.get(ChronoField.YEAR);

int month = temporal.get(ChronoField.MONTH_OF_YEAR);

int day = temporal.get(ChronoField.DAY_OF_MONTH);

//将获取到的数据封装为一个LocalDate对象.

LocalDate time = LocalDate.of(year, month, day);

//封装劳动节的时间,年参数传递year,month和day是5和1.

LocalDate laborDay = LocalDate.of(year, Month.MAY,1);

//判断当前时间是否已经超过了当年的劳动节,如果超过了,则laborDay+1年.

if (time.isAfter(laborDay)){

laborDay = laborDay.plusYears(1);

}

//通过ChronoUnit的between方法计算两个时间点的差额.

long l = ChronoUnit.DAYS.between(time, laborDay);

return l;

}

}

package com.itheima.time;

import com.itheima.time.impl.UntilDayQueryImpl;

import java.time.LocalDate;

public class Java8TimeTemporalQueryDemo1 {

public static void main(String[] args) {

//封装LocalDate对象为当前时间.

LocalDate time = LocalDate.now();

//调用time对象的query方法查询距离下一个五一劳动节还有多少天.

Long l = time.query(new UntilDayQueryImpl());

System.out.println("距离下一个五一劳动节还有:" + l + "天.");

}

}

练习

计算2018年5月30号与下一个的圣诞节/儿童节/劳动节各相差多少天?

假如员工一个月中领取工资,发薪日是每个月的15号,如果发薪日是周六,如果发薪日是周日,

则调整为下周五,如何实现?

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

对于老项目的改造,需要将Date或者Calendar转换为java.time包中相应的类的,可

以根据本小节中提供的方法进行改造.

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对象,通过给

Instant添加时区信息之后就可以转换为LocalDate对象.

package com.itheima.time.convert;

import java.time.Instant;

import java.time.LocalDate;

import java.time.ZoneId;

import java.time.ZonedDateTime;

import java.util.Date;

public class Java8TimeDateToLocalDateDemo1 {

public static void main(String[] args) {

//初始化Date对象.

Date d = new Date();

//将Date类对象转换为Instant类对象.

Instant i = d.toInstant();

//Date类包含日期和时间信息,但是并不提供时区信息,和Instant类一样,可以通过

Instant类的atZone方法添加时区信息之后进行转换.

ZonedDateTime zonedDateTime = i.atZone(ZoneId.systemDefault());

//将ZonedDateTime通过toLocalDate方法转换为LocalDate对象.

LocalDate localDate = zonedDateTime.toLocalDate();

System.out.println("转换之前的Date对象是:" + d);

System.out.println("转换之后的LocalDate对象是:" + localDate);

}

}

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

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

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

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

package com.itheima.time.convert;

import java.time.*;

import java.sql.Date;

public class Java8TimeDateToLocalDateDemo2 {

public static void main(String[] args) {

//初始化java.sql.Date对象.

Date d = new Date(System.currentTimeMillis());

//将java.sql.Date对象通过toLocalDate方法转换为LocalDate对象.

LocalDate localDate = d.toLocalDate();

System.out.println("转换前的java.sql.Date对象是:" + d);

System.out.println("转换后的LocalDate对象是:" + localDate);

}

}

package com.itheima.time.convert;

import java.sql.Date;

import java.sql.Time;

import java.sql.Timestamp;

import java.time.LocalDate;

import java.time.LocalDateTime;

public class Java8TimeDateToLocalDateDemo3 {

public static void main(String[] args) {

//初始化java.sql.Timestamp对象.

Timestamp t = new Timestamp(System.currentTimeMillis());

//将java.sql.Timestamp对象通过toLocalDateTime方法转换为LocalDateTime对

象.

LocalDateTime localDateTime = t.toLocalDateTime();

System.out.println("转换之前的Timestamp对象是:" + t);

System.out.println("转换之后的LocalDateTime对象是:" + localDateTime);

}

}

将java.util包中的类转换为java.time包中的相应类

通过编写转换工具类达到传入Date对象直接进行转换的转换或者将新的日期时间类转换为Date对

象.

package com.itheima.time.convert;

import java.time.LocalDate;

import java.time.LocalDateTime;

import java.time.ZoneId;

import java.time.ZonedDateTime;

import java.util.Date;

/**

* 编写工具类传入不同的对象可以转换为对应的对象.

*/

public class Java8TimeConvertTool {

/**

* 将java.sql.Date转换为LocalDate

*

* @param date

* @return

*/

public static LocalDate convertFromSqlDateToLocalDate(java.sql.Date

date) {

return date.toLocalDate();

}

/**

* 将LocalDate转换为java.sql.Date

* @param date

* @return

*/

public static java.sql.Date convertFromLocalDateToSqlDate(LocalDate

date) {

return java.sql.Date.valueOf(date);

}

/**

* 将java.util.Date转换为LocalDate

* @param date

* @return

*/

public static LocalDate convertFromUtilDateToLocalDate(java.util.Date

date) {

return

date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

}

/**

将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方法获取到.

* 将java.sql.Timestamp转换为LocalDateTime

* @param timestamp

* @return

*/

public static LocalDateTime

convertFromTimestampToLocalDateTime(java.sql.Timestamp timestamp) {

return timestamp.toLocalDateTime();

}

/**

* 将LocalDateTime转换为java.sql.Timestamp

* @param localDateTime

* @return

*/

public static java.sql.Timestamp

convertFromLocalDateTimeToTimestamp(LocalDateTime localDateTime) {

return java.sql.Timestamp.valueOf(localDateTime);

}

/**

* 将LocalDate转换为java.util.Date

* @param date

* @return

*/

public static java.util.Date convertFromLocalDateToUtilDate(LocalDate

date){

ZonedDateTime zonedDateTime =

date.atStartOfDay(ZoneId.systemDefault());

return Date.from(zonedDateTime.toInstant());

}

}

package com.itheima.time.convert;

import java.time.Instant;

import java.time.LocalDate;

import java.time.ZoneId;

import java.time.ZonedDateTime;

import java.util.Date;

public class Java8TimeDateToLocalDateDemo4 {

public static void main(String[] args) {

//初始化Date对象.

Date d = new Date();

/*

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

为java.sql.Date.

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

Calendar对象自Java1.1开始提供了一个方法获取时区对象的方法,getTimeZone,要将Calendar

对象转换为ZonedDateTime需要先获取到时区对象.从Java1.8开始TimeZone类提供了一个方法可

以获取到ZonedId.获取到zoneId之后就可以初始化ZonedDateTime对象了,ZonedDateTime类有

一个ofInstant方法,可以将一个Instant对象和ZonedId对象作为参数传入构造一个

ZonedDateTime对象.

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

毫秒值可以通过java.util.Date对象的getTime方法获取到.

*/

java.sql.Date date = new java.sql.Date(d.getTime());

//将java.sql.Date转化为LocalDate.

LocalDate localDate = date.toLocalDate();

System.out.println("转换前的java.util.Date类对象是:" + d);

System.out.println("转换后的LocalDate类对象是:" + localDate);

}

}

package com.itheima.time.convert;

import java.time.LocalDate;

import java.time.ZoneId;

import java.time.ZonedDateTime;

import java.util.Calendar;

import java.util.Date;

import java.util.TimeZone;

public class Java8TimeCalendarToLocalDateDemo1 {

public static void main(String[] args) {

//初始化Canlendar对象.

Calendar cal = Calendar.getInstance();

//Calendar对象自Java1.1开始提供了一个方法获取时区对象的方法,getTimeZone,要将

Calendar对象转换为ZonedDateTime需要先获取到时区对象.

TimeZone timeZone = cal.getTimeZone();

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

ZoneId zoneId = timeZone.toZoneId();

//获取到zoneId之后就可以初始化ZonedDateTime对象了,ZonedDateTime类有一个

ofInstant方法,可以将一个Instant对象和ZonedId对象作为参数传入构造一个ZonedDateTime对

象.

ZonedDateTime zonedDateTime =

ZonedDateTime.ofInstant(cal.toInstant(), zoneId);

System.out.println("转换前的Calendar对象是:" + cal);

System.out.println("转换后的ZonedDateTime对象是:" + zonedDateTime);

}

}

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

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

数.

注意Calendar获取到的月份依旧是从0开始的,需要在原有的基础上+1,如果不

加1,轻则月份少算了1个月,重则出现异常.

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

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

式化类 DateTimeFormatter.

DateTimeFormatter类提供了大量预定义格式化器,包括常量(如

ISO_LOCAL_DATE),模式字母(如yyyy-MM-dd)以及本地化样式.

package com.itheima.time.convert;

import java.time.LocalDateTime;

import java.time.ZoneId;

import java.time.ZonedDateTime;

import java.util.Calendar;

import java.util.TimeZone;

public class Java8TimeCalendarToLocalDateTimeDemo1 {

public static void main(String[] args) {

//初始化Canlendar对象.

Calendar cal = Calendar.getInstance();

//通过Getter方法获取到Calendar对象中封装的数据.

int year = cal.get(Calendar.YEAR);

int month = cal.get(Calendar.MONTH);

int day = cal.get(Calendar.DAY_OF_MONTH);

int hour = cal.get(Calendar.HOUR);

int minute = cal.get(Calendar.MINUTE);

int second = cal.get(Calendar.SECOND);

//将以上获取到的数据作为LocalDateTime的of方法的参数进行对象的封装.

LocalDateTime localDateTime = LocalDateTime.of(year, month + 1, day,

hour, minute, second);

System.out.println("转换前的Calendar对象是:" + cal);

System.out.println("转换后的LocalDateTime对象是:" + localDateTime);

}

}

与SimpleDateFormat不同的是,新版本的日期/时间API的格式化与解析不需要在创

建转换器对象再进行转换了,通过时间日期对象的parse/format方法可以直接进行

转换.

LocalDate类定义的parse和format方法

format方法需要传入一个DateTimeFormatter对象,实际上查看DateTimeFormatter类之后,指定

DateTimeFormatter中的常量即可指定格式化方法,常用的格式化方式有ISO_DATE_TIME/ISO_DATE.

package com.itheima.time;

import java.time.LocalDateTime;

import java.time.format.DateTimeFormatter;

public class Java8TimeFormatAndParseDemo1 {

public static void main(String[] args) {

//对LocalDateTime进行格式化与解析,初始化LocalDateTime对象.

LocalDateTime time = LocalDateTime.now();

//DateTimeFormatter类中定义了很多方式,通过常量名可以指定格式化方式.

String result = time.format(DateTimeFormatter.ISO_DATE_TIME);

System.out.println("ISO_DATE_TIME格式化之后的String是:" + result);

String result1 = time.format(DateTimeFormatter.ISO_DATE);

System.out.println("ISO_DATE格式化之后的String是:" + result1);

//解析字符串的方式通过LocalDateTime类的静态方法parse方法传入需要解析的字符串即可.

LocalDateTime localDateTime = LocalDateTime.parse(result);

System.out.println("解析了字符串之后的LocalDateTime是:" + localDateTime);

对日期进行格式化

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

式.

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

种方式如下.

Full:全显示(年月日+星期) Long:全显示(年月日) Medium:缩略显示(没有年

月日汉字) SHORT:精简显示(精简年+月日)

}

}

package com.itheima.time;

import java.time.LocalDateTime;

import java.time.format.DateTimeFormatter;

import java.time.format.FormatStyle;

public class Java8TimeFormatAndParseDemo2 {

public static void main(String[] args) {

//对LocalDateTime进行格式化与解析,初始化LocalDateTime对象.

LocalDateTime time = LocalDateTime.now();

//通过DateTimeFormatter的ofLocalizedDate指定解析格式也可以格式化日期

String r1 =

time.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL));

String r2 =

time.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG));

String r3 =

time.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM));

String r4 =

time.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相同.

练习

将1998年3月18日17时19分28秒格式化为以下格式

package com.itheima.time;

import java.time.LocalDateTime;

import java.time.format.DateTimeFormatter;

import java.time.format.FormatStyle;

public class Java8TimeFormatAndParseDemo3 {

public static void main(String[] args) {

//对LocalDateTime进行格式化与解析,初始化LocalDateTime对象.

LocalDateTime time = LocalDateTime.now();

//通过通过DateTimeFormatter的ofPattern方法可以自定义格式化模式.

String result = time.format(DateTimeFormatter.ofPattern("yyyy/MM/dd

HH:mm:ss:SSS"));

System.out.println("LocalDateTime格式化前是:" + time);

System.out.println("LocalDateTime格式化后是:" + result);

}

}

1998-3月-18---17:19分28秒

ffee5e3e5b13372f166561412b7a3552.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值