概述
??Java 8中新增了新的日期处理包java.time,解决了jdk 1.7之前日期类Calendar,DateFormat线程不安全的问题,为了熟悉API特地学习了一下,写此博客作为记录,并分享给大家。
??详细使用方法请参考下面的代码:
package top.jacktgq.demo2;import java.sql.Timestamp;
import java.time.DayOfWeek;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.MonthDay;
import java.time.Period;
import java.time.Year;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.TemporalQuery;
import java.util.Calendar;
import java.util.Date;
import java.util.Set;
import java.util.TimeZone;import org.junit.Test;/*** * @Title: Java8TimeClassesMethodTest.java * @Package top.jacktgq.demo2 * @Description: Date-Time API中的所有类均生成不可变实例,他们是线程安全的,并且这些类不提供公共构造函数,* 也就是说没办法通过new的方式直接创建,需要采用工厂方法加以实例化。* @author CandyWall * @date 2020年5月13日 下午3:08:37 * @version V1.0*/
public class Java8TimeClassesMethodTest {
@Test/*** now()方法入门*/public void demo1() {
//使用now方法创建Instant类的实例对象Instant instantNow = Instant.now();//使用now方法创建LocalDate类的实例对象LocalDate localDateNow = LocalDate.now();//使用now方法创建LocalTime类的实例对象LocalTime localTimeNow = LocalTime.now();//使用now方法创建LocalDateTime类的实例对象LocalDateTime localDateTime = LocalDateTime.now();//将实例对象都打印到控制台查看内容System.out.println("Instant" + "\t:" + instantNow);System.out.println("LocalDate" + "\t:" + localDateNow);System.out.println("LocalTime" + "\t:" + localTimeNow);System.out.println("LocalDateTime" + "\t:" + localDateTime);}@Test/*** 使用now()方法创建Year、YearMonth、MonthDay类的实例*/public void demo2() {
//使用now()方法创建Year类的实例Year year = Year.now();//使用now()YearMonth类的实例YearMonth yearMonth = YearMonth.now();//使用now()MonthDay类的实例MonthDay monthDay = MonthDay.now();System.out.println("Year:" + "\t:" + year);System.out.println("YearMonth:" + "\t:" + yearMonth);System.out.println("MonthDay:" + "\t:" + monthDay);}@Test/*** of()方法*/public void demo3() {
//初始化2020年5月13日的LocalDate对象LocalDate localDate = LocalDate.of(2020, 5, 13);System.out.println("LocalDate:" + "\t:" + localDate);//初始化下午3:30分30秒的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) -> 根据小时/分钟/秒/毫秒/纳生成对象//注意:如果秒和纳秒都是0的话,那么默认不会封装这些数据,只显示小时和分钟LocalTime localTime = LocalTime.of(15, 30, 30, 90);System.out.println("LocalTime:" + "\t:" + localTime);//初始化2020年5月13日 下午3:30分30秒的LocalDateTime对象//LocalDateTime.of()方法的重载形式有以下几种,可以根据实际情况自行使用//LocalDateTime.of(int year, int month, int dayofMonth, int hour, int minute) -> 根据 年/月/日/时/分 生成对象//LocalDateTime.of(int year, int month, int dayofMonth, int hour, int minute, int second, int nanoOfSecond) -> 根据 年/月/日/时/分/秒/纳秒 生成对象LocalDateTime localDateTime = LocalDateTime.of(2020, 5, 13, 15, 30, 30, 90);System.out.println("LocalDateTime:" + "\t:" + localDateTime);//LocalDateTime的of()方法的特殊用法://LocalDateTime.of(LocalDate localDate, LocalTime localTime)System.out.println("LocalDateTime的of()方法的特殊用法:" + LocalDateTime.of(localDate, localTime));}@Test/*** 时区相关*/public void demo4() {
//获取所有的时区信息Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();for(String zoneId : availableZoneIds) {
System.out.println(zoneId);}//获取当前系统默认的时区信息 -> 中国System.out.println("系统默认时区:" + ZoneId.systemDefault());}@Test/*** 为LocalDateTime添加时区信息*/public void demo5() {
//1、封装LocalDateTime对象,参数自定义 -> 2020年5月14日 15点00分38秒LocalDateTime localDateTime = LocalDateTime.of(2020, 5, 14, 15, 0, 38);//2、LocalDateTime对象现在只是封装了一个时间,并没有时区相关的数据,所以需要添加时区信息到对象中,使用atZone()方法ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("Asia/Shanghai"));System.out.println("Asia/Shanghai对应的当前时间是:" + zonedDateTime);//3、更改时区查看其它时区的当前时间,通过withZoneSameInstant()方法即可更改ZonedDateTime tokyoZonedDateTime = zonedDateTime.withZoneSameInstant(ZoneId.of("Asia/Tokyo"));System.out.println("Asia/Tokyo对应的当前时间是:" + tokyoZonedDateTime);}@Testpublic void demo6() {
//在初始化LocalDate和LocalDateTime的时候,月份的参数建议传入枚举类//2020年5月14日15点12分36秒LocalDateTime localDateTime = LocalDateTime.of(2020, Month.MAY, 15, 12, 36);System.out.println(localDateTime);//Month枚举类 -> of()方法可以根据传入的数字返回对应的枚举Month month = Month.of(12);System.out.println(month);}@Test/*** 创建当前时间(不带时区)* 创建当前时间(只包含年月日)* 创建当前时间(包含年月日时分秒并且带有时区)* 创建2012年12月31日7时38分46秒的日期对象 月份使用枚举表示* 创建7时38分46秒的时间对象*/public void test01() {
//1、创建当前时间(不带时区)LocalTime localTime1 = LocalTime.now();System.out.println("LocalTime:\t" + localTime1);//2、创建当前时间(只包含年月日)LocalDate localDate = LocalDate.now();System.out.println("LocalDate:\t" + localDate);//3、创建当前时间(包含年月日时分秒并且带有时区)ZonedDateTime zonedDateTime = ZonedDateTime.now();System.out.println("ZonedDateTime:\t" + zonedDateTime);//4、创建2012年12月31日7时38分46秒的日期对象 月份使用枚举表示LocalDateTime localDateTime = LocalDateTime.of(2012, Month.DECEMBER, 31, 7, 38, 46);System.out.println("LocalDateTime:\t" + localDateTime);//5、创建7时38分46秒的时间对象LocalTime localTime2 = LocalTime.of(7, 38, 46);System.out.println("localTime2:\t" + localTime2);}@Test/*** 日期的计算*/public void demo7() {
//封装LocalDate对象LocalDate localDate = LocalDate.now();System.out.println("当前日期是:" + localDate);//计算当前日期的4天后的日期System.out.println("当前日期的4天后的日期是:" + localDate.plusDays(4));//计算当前日期3周后的日期System.out.println("计算当前日期3周后的日期是:" + localDate.plusWeeks(3));//计算当前日期5个月后的日期System.out.println("计算当前日期5个月后的日期是:" + localDate.plusMonths(5));//计算当前日期2年后的日期System.out.println("计算当前日期2年后的日期是:" + localDate.plusYears(2));//如果需要计算当前日期之前的日期只需要调用LocalDate.minus()方法即可}@Testpublic void demo8() {
//封装LocalTime对象LocalTime localTime = LocalTime.now();System.out.println("当前时间是:" + localTime);//计算当前时间的500纳秒后的时间System.out.println("当前时间的500纳秒后的时间是:" + localTime.plusNanos(500));//计算当前时间的45秒后的时间System.out.println("当前时间的45秒后的时间是:" + localTime.plusSeconds(45));//计算当前时间的19分钟后的时间System.out.println("当前时间的19分钟后的时间是:" + localTime.plusMinutes(19));//计算当前时间的3小时后的时间System.out.println("当前时间的3小时后的时间是:" + localTime.plusHours(3));//如果需要计算当前时间之前的时间只需要调用LocalDate.minus()方法即可}@Testpublic void demo9() {
//需求:今天程序员小张查看自己的车辆保险记录的时候看到了还有2年3月8天就到期了,计算到期的日期是什么时候LocalDate localDate = LocalDate.now();//写法一:System.out.println("当前日期是:" + localDate + ",保险到期的日期是:" + localDate.plusYears(2).plusMonths(3).plusDays(8));//写法二:System.out.println("当前日期是:" + localDate + ",保险到期的日期是:" + localDate.plus(Period.of(2, 3, 8)));}@Testpublic void demo10() {
//结婚10年称为锡婚,2020年2月2日11时11分11秒称为对称日,//很多情侣准备在那天结婚,如果在那天结婚了,那么锡婚会发生在什么时候?LocalDateTime marryTime = LocalDateTime.of(2020, Month.FEBRUARY, 2, 11, 11, 11);LocalDateTime tin_marriageTime = marryTime.plus(1, ChronoUnit.DECADES);System.out.println("如果在 " + marryTime + " 的时候结婚,那么锡婚发生的时间点在:" + tin_marriageTime);System.out.println("如果锡婚后的半天需要请所有的亲戚朋友们吃饭,那么吃饭的时间节点是:" + tin_marriageTime.plus(1, ChronoUnit.HALF_DAYS));}@Testpublic void demo11() {
//修改日期或者时间中的某个值LocalDateTime localDateTime = LocalDateTime.now();System.out.println("当前时间是:" + localDateTime);//将日期修改成1号//写法一:System.out.println("将当前日期修改成2019年1月1日14时08分26秒:" + localDateTime.withYear(2019).withMonth(1).withDayOfMonth(1).withHour(14).withMinute(8).withSecond(26));//写法二:System.out.println("将当前日期修改成2019年1月1日14时08分26秒:" + localDateTime.with(ChronoField.YEAR, 2019).with(ChronoField.MONTH_OF_YEAR, 1).with(ChronoField.DAY_OF_MONTH, 1).with(ChronoField.HOUR_OF_DAY, 14).with(ChronoField.MINUTE_OF_HOUR, 8).with(ChronoField.SECOND_OF_MINUTE, 26));}@Testpublic void test02() {
//使用三种方式计算2019年7月19日14时38分34秒后的3年7个月18天后是什么时候LocalDateTime localDateTime = LocalDateTime.of(2019, 7, 19, 14, 38, 34);//方式一:System.out.println("2019年7月19日14时38分34秒后的3年7个月18天后是:" + localDateTime.plusYears(3).plusMonths(7).plusDays(18));//方式二:System.out.println("2019年7月19日14时38分34秒后的3年7个月18天后是:" + localDateTime.plus(Period.of(3, 7, 18)));//方式三:System.out.println("2019年7月19日14时38分34秒后的3年7个月18天后是:" + localDateTime.plus(3, ChronoUnit.YEARS).plus(7, ChronoUnit.MONTHS).plus(18, ChronoUnit.DAYS));}@Testpublic void demo12() {
//封装日期为当前时间LocalDateTime now = LocalDateTime.now();System.out.println("当前时间为:" + now);//通过with()方法传入TemporalAdjuster类的实现类对象,就可以进行更改,//实现类对象室友TemporalAdjuster类的静态方法来提供的//修改时间为当月第一天System.out.println("将时间修改为当月的第一天,具体时间为:" + now.with(TemporalAdjusters.firstDayOfMonth()));//修改时间为下个月的第一天System.out.println("将时间修改为下个月的第一天,具体时间为:" + now.with(TemporalAdjusters.firstDayOfNextMonth()));//修改时间为下一年的第一天System.out.println("将时间修改为下一年的第一天,具体时间为:" + now.with(TemporalAdjusters.firstDayOfNextYear()));//修改时间为本年的第一天System.out.println("将时间修改为本年的第一天,具体时间为:" + now.with(TemporalAdjusters.firstDayOfYear()));//修改时间为本月的最后一天System.out.println("将时间修改为本月的最后一天,具体时间为:" + now.with(TemporalAdjusters.lastDayOfMonth()));//修改时间为本年的最后一天System.out.println("将时间修改为本年的最后一天,具体时间为:" + now.with(TemporalAdjusters.lastDayOfYear()));//总结:TemporalAdjuster是一个接口,with方法实际上传入的是这个接口的实现类对象,//TemporalAdjusters并不是TemporalAdjuster的实现类,//只不过TemporalAdjusters的静态方法实现了TempopralAdjuster,并且将实现类对象返回了。}@Testpublic void demo13() {
//封装日期对象为当前日期LocalDate now = LocalDate.now();//将当前日期修改为下个周日System.out.println("下一个周日是:" + now.with(TemporalAdjusters.next(DayOfWeek.SUNDAY)));//将当前日期修改为上一个周日System.out.println("上一个周日是:" + now.with(TemporalAdjusters.previous(DayOfWeek.SUNDAY)));}@Testpublic void demo14() {
//假如员工一个月中领取工资,发薪日是每个月的15号,如果发薪日是周末,则调整为周五LocalDate payDate = LocalDate.of(2018, 12, 15);LocalDate realPayDate = LocalDate.from(new TemporalAdjuster() {
@Overridepublic Temporal adjustInto(Temporal temporal) {
//1、Temporal是日期时间对象的父接口,实际上可以理解为传入的就是LocalDate或者LocalTime对象LocalDate payDate = LocalDate.from(temporal);//2、判断当前封装的日期中的日期是不是当月15号,如果不是则修改为15号if(payDate.getDayOfMonth() != 15) {
payDate = payDate.withDayOfMonth(15);}//3、判断payDate对象中封装的星期是不是周六或者周日,如果是周末的话则改为上一个周五if(payDate.getDayOfWeek() == DayOfWeek.SATURDAY || payDate.getDayOfWeek() == DayOfWeek.SUNDAY) {
payDate = payDate.with(TemporalAdjusters.previous(DayOfWeek.FRIDAY));}return payDate;}}.adjustInto(payDate));System.out.println("这个月的实际发薪日是:" + realPayDate);}@Testpublic void demo15() {
//计算当前时间距离劳动节还有多少天LocalDate now = LocalDate.now();//调用now的query()方法,然后将我们自己实现的UtilDayQueryImpl作为参数传入即可Long dayCount = now.query(new TemporalQuery<Long>() {
@Overridepublic Long queryFrom(TemporalAccessor temporal) {
//1、TemporalAccessor是LocalDateTime的顶级父接口,//LocalDate就是接口的实现类,将temporal转换为为LocalDate进行使用LocalDate now = LocalDate.from(temporal);//2、封装当年的劳动节日期,年份从now中获取,月份:Month.MAY,日期:1 -> 2020年5月1日LocalDate laborDay = LocalDate.of(now.getYear(), Month.MAY, 1);//3、判断当前时间是否已经超过了当年的劳动节,如果超过了当年的劳动节,则laborDay加1年if(now.isAfter(laborDay)) {
laborDay = laborDay.plusYears(1);}//4、通过ChronoUnit的between()方法来计算两个时间点的差值return ChronoUnit.DAYS.between(now, laborDay);}});System.out.println("当前的日期是:" + now + ",距离下一个五一劳动节还有 " + dayCount + " 天");//计算当前时间距离下一个圣诞节/儿童节/劳动节各相差多少天Long[] daysArray = now.query(new TemporalQuery<Long[]>() {
@Overridepublic Long[] queryFrom(TemporalAccessor temporal) {
LocalDate now = LocalDate.from(temporal);return new Long[] {
getDate(now, 12, 25), getDate(now, 6, 1), getDate(now, 5, 1)};}//根据当前日期和下一个节日的日期,获取距离下一个日期的差值private Long getDate(LocalDate now, int month, int day) {
LocalDate festivalDay = LocalDate.of(now.getYear(), month, day);if(now.isAfter(festivalDay)) {
festivalDay = festivalDay.plusYears(1);}return ChronoUnit.DAYS.between(now, festivalDay);}});for(Long days : daysArray) {
System.out.println(days);}}@Test/*** java.util.Date转换为java.time.LocalDate*/public void demo16() {
//初始化一个Date对象Date d = new Date();//方法一:使用Instant类完成转换//1、将Date对象转换成Instant对象Instant instant = d.toInstant();//2、Date类中包含日期信息和时间信息,但是不提供时区信息,和Instant类一样,//通过Instant类的atZone方法添加时区信息进行转换ZonedDateTime zonedDateTime = instant.atZone(ZoneId.systemDefault());//3、将ZonedDateTime通过toLocalDate()方法转换为LocalDate对象LocalDate localDate1 = zonedDateTime.toLocalDate();System.out.println("转换之前的java.util.Date对象是:" + d);System.out.println("转换之后的java.time.LocalDate对象是:" + localDate1);//方法二:将Java.util.Date先转换成java.sql.Date//再将java.sql.Date转换成java.time.LocalDate//java.sql.Date类构造的时候需要毫秒值 -> java.util.Date类中提供了一个获取毫秒值的方法getTime()java.sql.Date date = new java.sql.Date(d.getTime());LocalDate localDate2 = date.toLocalDate();System.out.println("转换之前的java.util.Date对象是:" + d);System.out.println("转换之后的java.time.LocalDate对象是:" + localDate2);}@Test/*** java.sql.Date转换为java.time.LocalDate* java.sql.TimeStamp转换为java.time.LocalDateTime*/public void demo17() {
//初始化java.sql.Date对象java.sql.Date d = new java.sql.Date(System.currentTimeMillis());//java.sql.Date类中自带了转换为LocalDate的方法toLocalDate()LocalDate localDate = d.toLocalDate();System.out.println("转换之前的java.sql.Date对象是:" + d);System.out.println("转换之后的java.time.LocalDate对象是:" + localDate);//初始化java.sql.TimeStamp对象Timestamp t = new Timestamp(System.currentTimeMillis());LocalDateTime localDateTime = t.toLocalDateTime();System.out.println("转换之前的java.sql.TimeStamp对象是:" + t);System.out.println("转换之后的java.time.LocalDateTime对象是:" + localDateTime);}@Test/*** java.util.Calendar转换为java.time.ZonedDateTime*/public void demo18() {
//1、初始化一个Calendar对象Calendar calendar = Calendar.getInstance();//2、Calendar对象自java 1.1版本开始提供了一个方法getTimeZone()用于获取时区对象//要将Calendar转换为ZonedDateTime对象,需要先获取时区对象。TimeZone timeZone = calendar.getTimeZone();//3、从java 1.8版本开始TimeZone类提供了一个方法可以获取到ZoneId -> //拿ZoneId对象来构建ZonedDateTime对象ZoneId zoneId = timeZone.toZoneId();//4、ZonedDateTime类有一个ofInstant()方法,//可以将一个Instant对象和ZoneId独享封装为一个ZonedDateTime对象ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(calendar.toInstant(), zoneId);System.out.println("转换之前的java.util.Calendar对象是:" + calendar);System.out.println("转换之后的java.time.ZonedDateTime对象是:" + zonedDateTime);}@Test/*** java.util.calendar类转换成java.time.LocalDateTime*/public void demo19() {
//1、初始化一个Calendar对象Calendar calendar = Calendar.getInstance();//2、通过get方法获取到Calendar对象中封装的数据int year = calendar.get(Calendar.YEAR);int month = calendar.get(Calendar.MONTH) + 1;int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);int hourOfDay = calendar.get(Calendar.HOUR_OF_DAY);int minute = calendar.get(Calendar.MINUTE);int second = calendar.get(Calendar.SECOND);LocalDateTime localDateTime = LocalDateTime.of(year, month, dayOfMonth, hourOfDay, minute, second);System.out.println("转换之前的java.util.Calendar对象是:" + calendar);System.out.println("转换之后的java.time.LocalDateTime对象是:" + localDateTime);}@Test/*** 日期格式化和字符串转日期*/public void demo20() {
//对LocalDateTime进行格式化和解析,初始化LocalDateTime对象LocalDateTime now = LocalDateTime.now();System.out.println("没有格式化的String是:" + now);//now对象可以直接调用format方法进行格式化String s1 = now.format(DateTimeFormatter.ISO_DATE_TIME);System.out.println("按照ISO_DATE_TIME格式化之后String是:" + s1);String s2 = now.format(DateTimeFormatter.ISO_DATE);System.out.println("按照ISO_DATE格式化之后String是:" + s2);//解析字符串的方式通过LocalDateTime类的静态方法parse方法传入需要解析的字符串即可LocalDateTime localDateTime = LocalDateTime.parse(s1);System.out.println("将ISO_DATE_TIME格式的字符串转成LocalDateTime的结果是:" + localDateTime);LocalDate localDate = LocalDate.parse(s2);System.out.println("将ISO_DATE格式的字符串转成LocalDateTime的结果是:" + localDate);}@Test/*** 本地日期格式化(将根据当前系统所处环境-中国)*/public void demo21() {
LocalDateTime now = LocalDateTime.now();//通过DateTimeFormatter的ofLocalizedDate指定解析格式System.out.println("FormatStyle.FULL:" + now.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL)));System.out.println("FormatStyle.LONG:" + now.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG)));System.out.println("FormatStyle.MEDIUM:" + now.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)));System.out.println("FormatStyle.SHORT:" + now.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT)));}@Test/*** 自定义日期格式化*/public void demo22() {
LocalDateTime now = LocalDateTime.now();//通过DateTimeFormatter提供的ofPattern方法自定义格式化方式System.out.println("将LocalDateTime按照yyyy/MM/dd HH:mm:ss:SSS格式进行格式化:" + now.format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss:SSS")));System.out.println("将LocalDateTime按照yyyy年MM月dd日 HH:mm:ss:SSS格式进行格式化:" + now.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss:SSS")));}@Test/*** 练习:将2020年5月20日22时22分22秒格式化为以下格式:2020-05月-18---22:22分22秒*/public void test03() {
LocalDateTime now = LocalDateTime.of(2020, 5, 20, 22, 22, 22);System.out.println("将LocalDateTime按照yyyy-MM月-dd---HH:mm分ss秒格式进行格式化:" + now.format(DateTimeFormatter.ofPattern("yyy-MM月-dd---HH:mm分ss秒")));}}