前言

Java 8里面添加了许多的新特性,其中一个最常见也是最实用的便是日期处理的类——LocalDate。


新增的日期类主要有三种:

java.time.LocalDate ->只对年月日做出处理

java.time.LocalTime ->只对时分秒纳秒做出处理

java.time.LocalDateTime ->同时可以处理年月日和时分秒

LocalDate:默认返回一个日期格式为yyyy-MM-dd格式的日期


一:创建LocalDate

java8 LocalDate的使用、LocalDate格式化_当前日期

1、now()

从默认时区的系统时钟中获取当前日期。默认输出格式为yyyy-MM-dd

LocalDate localDate = LocalDate.now();
System.out.println(localDate);
2021-11-29

2、now(Clock clock)

从指定时钟获取当前日期。

LocalDate l = LocalDate.now(Clock.systemDefaultZone());
System.out.println(l);

System.out.println(Clock.systemDefaultZone());//方法返回带有系统默认时区的Clock实例。
System.out.println(Clock.systemUTC());//此方法返回带有UTC时区的Clock实例。
2021-11-29

SystemClock[Asia/Shanghai]
SystemClock[Z]

3、now(ZoneId zone)

从指定时区的系统时钟中获取当前日期。

LocalDate l = LocalDate.now(ZoneId.of("UTC+1"));
System.out.println(l);
2021-11-29

时区是用ZoneId类表示的,你可以使用ZoneId.now()或ZoneId.of(“xxx”)来实例化:

ZoneId zoneId = ZoneId.of("UTC+1");

传给of()方法的参数是时区的ID,如“UTC+1”指距离UTC(格林威治时间)有一小时的时差,你可以使用你想要的时差来表示ZoneId(如+1与-5等等)

你也可以使用另一种方式表示zone id,即使用地区名字,也是可以的:

ZoneId zoneId2 = ZoneId.of("Europe/Copenhagen");
ZoneId zoneId3 = ZoneId.of("Europe/Paris");

4、of(int year, int month, int dayOfMonth)

从年、月和日获取LocalDate实例

LocalDate l = LocalDate.of(2021, 11, 29);
System.out.println(l);
2021-11-29

5、ofYearDay(int year,int dayOfYear)

从指定年的指定天获取LocalDate实例

//获取2021年第230天的日期
LocalDate l = LocalDate.ofYearDay(2021, 230);
System.out.println(l);
2021-08-18

6、ofEpochDay(long epochDay)

从1970-01-01开始获取指定天数的LocalDate实例

LocalDate l = LocalDate.ofEpochDay(0);//1970-01-01
LocalDate l1 = LocalDate.ofEpochDay(-10);//1969-12-22
LocalDate l2 = LocalDate.ofEpochDay(10);//1970-01-11

7、parse(CharSequence text)

字符串转换为LocalDate,字符串的格式必须为yyyy-MM-dd 10位长度的日期格式,否则会报错,字符串必须是一个合法的日期,否则会报错

LocalDate l = LocalDate.parse("2021-01-29");
System.out.println(l); //2021-01-29

错误示例:

//日期格式非yyyy-MM-dd
LocalDate l = LocalDate.parse("2021-1-29");
//日期格式非yyyy-MM-dd
LocalDate l = LocalDate.parse("2021/01/29");
//字符串不是一个合法的日期,2月没有30号
LocalDate l = LocalDate.parse("2021-02-30");

若parse(CharSequence text)中传入的格式非yyyy-MM-dd或不合法,会抛出异常,且长度需要是10位

Exception in thread "main" java.time.format.DateTimeParseException: Text '2021/11/29' could not be parsed at index 4
	at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2046)
	at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
	at java.base/java.time.LocalDate.parse(LocalDate.java:428)
	at java.base/java.time.LocalDate.parse(LocalDate.java:413)
	at com.aexpec.mic.merchant.controller.Test.main(Test.java:19)

8、parse(CharSequence text, DateTimeFormatter formatter)

将text字符串转换为formatter格式,text的格式必须与formatter格式一致,如text为yyyyMMdd格式,则formatter也应该为yyyyMMdd格式,否则会报错

LocalDate l = LocalDate.parse("2021-11-29", DateTimeFormatter.ofPattern("yyyy-MM-dd"));
LocalDate localDate1 = LocalDate.parse("20211129", DateTimeFormatter.ofPattern("yyyyMMdd"));
System.out.println(l);
System.out.println(localDate1);
2021-11-29
2021-11-29
为什么localDate1输出后格式为yyyy-MM-dd?
虽然入参格式为yyyyMMdd,但是转换为LocalDate后,格式默认为yyyy-MM-dd, LocalDate返回的格式默认为yyyy-MM-dd,下面会讲如何转换为其他格式。

错误示例:

//错误示例:text与formatter格式不一致,会抛出异常
LocalDate l = LocalDate.parse("2021-11-29", DateTimeFormatter.ofPattern("yyyyMMdd"));
LocalDate localDate1 = LocalDate.parse("20211129", DateTimeFormatter.ofPattern("yyyy-MM-dd"));

二:LocalDate日期比较

java8 LocalDate的使用、LocalDate格式化_java_02

1、boolean isBefore(ChronoLocalDate other)

用于检查此LocalDate值是否在给定的ChronoLocalDate(other)之前

LocalDate l = LocalDate.parse("2021-11-29");
System.out.println(l.isBefore(LocalDate.parse("2021-11-28"))); //false
System.out.println(l.isBefore(LocalDate.parse("2021-11-30"))); //true

2、boolean isAfter(ChronoLocalDate other)

用于检查此LocalDate值是否在给定的ChronoLocalDate(other)之后

LocalDate l = LocalDate.parse("2021-11-29");
System.out.println(l.isAfter(LocalDate.parse("2021-11-28"))); //true
System.out.println(l.isAfter(LocalDate.parse("2021-11-30"))); //false

3、boolean isEqual(ChronoLocalDate other)

用于检查此LocalDate值是否与给定的ChronoLocalDate(other)相等

LocalDate l = LocalDate.parse("2021-11-29");
System.out.println(l.isEqual(LocalDate.parse("2021-11-28"))); //false
System.out.println(l.isEqual(LocalDate.parse("2021-11-30"))); //false
System.out.println(l.isEqual(l)); //true

4、int compareTo(ChronoLocalDate other)

比较两个日期A.compareTo(B),若日期相同则返回0;

若A>B,则返回1;

若A<B,则返回-1;

LocalDate l = LocalDate.parse("2021-11-29");
System.out.println(l.compareTo(LocalDate.parse("2021-11-28"))); //1
System.out.println(l.compareTo(LocalDate.parse("2021-11-30"))); //-1
System.out.println(l.compareTo(l)); //0


三:获取年、月、日

java8 LocalDate的使用、LocalDate格式化_当前日期_03

LocalDate localDate = LocalDate.now();
System.out.println(localDate); // 2021-11-29

System.out.println("年 : " + localDate.getYear()); // 2021
System.out.println("月(英文) : " + localDate.getMonth()); // NOVEMBER
System.out.println("月(数字英文): " + localDate.getMonth().getValue()); // 11
System.out.println("月(数字英文): " + localDate.getMonthValue()); // 11
System.out.println("本月第几天 : " + localDate.getDayOfMonth()); // 29
System.out.println("星期几(英文) : " + localDate.getDayOfWeek()); // MONDAY
System.out.println("星期几(数字英文) : " + localDate.getDayOfWeek().getValue()); // 1
System.out.println("本年的第几天 : " + localDate.getDayOfYear()); // 333
System.out.println("是否润年 : " + localDate.isLeapYear()); // false
System.out.println("本月天数 : " + localDate.lengthOfMonth()); // 30
System.out.println("本年天数 : " + localDate.lengthOfYear()); // 365


四:日期计算,加/减年、月、周、日

4.1、加/减年、月、周、日

java8 LocalDate的使用、LocalDate格式化_System_04

LocalDate localDate1 = LocalDate.now();
localDate1 = LocalDate.parse("2021-11-29");
System.out.println(localDate1); // 2021-11-29

//通用方法
System.out.println("增加 : " + localDate1.plus(1, ChronoUnit.DAYS));

System.out.println("增加天数 : " + localDate1.plusDays(1)); // 2021-11-30
System.out.println("增加周数 : " + localDate1.plusWeeks(1)); // 2021-12-06
System.out.println("增加月数 : " + localDate1.plusMonths(1)); // 2021-12-29
System.out.println("增加年数 : " + localDate1.plusYears(1)); // 2022-11-29

//通用方法
System.out.println("减少 : " + localDate1.minus(1, ChronoUnit.DAYS));

System.out.println("减少天数 : " + localDate1.minusDays(1)); // 2021-11-28
System.out.println("减少月数 : " + localDate1.minusMonths(1)); // 2021-10-29
System.out.println("减少周数 : " + localDate1.minusWeeks(1)); // 2021-11-22
System.out.println("减少年数 : " + localDate1.minusYears(1)); // 2020-11-29

4.2、计算两个日期的间隔

方法一:计算两个日期相差的天数

调用LocalDate类的toEpochDay方法,返回距离1970年1月1日的long值

此方法只能计算两个日期相差的天数,不能计算月数,年数

LocalDate start = LocalDate.of(2020,2,28);
LocalDate end = LocalDate.of(2021,12,3);

System.out.println("两个时间之间的相差的天数: "+(end.toEpochDay()-start.toEpochDay())); //644

方法二::计算两个日期相差的天数、月数、年数

ChronoUnit也可以计算两个单元之间的天数、月数或年数。

我们使用ChronoUnit类的between() 方法来执行相同的操作:

LocalDate start = LocalDate.of(2020,2,28);
LocalDate end = LocalDate.of(2021,12,3);
long days= ChronoUnit.DAYS.between(start , end );
结果:644
long month= ChronoUnit.MONTHS.between(start , end );
结果21
long year= ChronoUnit.YEARS.between(start , end );
结果 1

方法三: 计算两个日期相差的年月日

此方法主要是计算两个日期相差的年月日,不能计算出具体相差了多少天

LocalDate start = LocalDate.of(2020,2,28);
LocalDate end = LocalDate.of(2021,12,3);
Period period = Period.between(start,end);
System.out.println("两个时间之间的差值  年:"+period.getYears()+",月:"+period.getMonths()+",日:"+period.getDays());
两个时间之间的差值  年:1,月:9,日:5


五:日期格式化

java8 LocalDate的使用、LocalDate格式化_当前日期_05

LocalDate l = LocalDate.parse("2021-01-29");
System.out.println(l); //2021-01-29

LocalDate l1 = LocalDate.parse("2021-11-29", DateTimeFormatter.ofPattern("yyyy-MM-dd"));
System.out.println(l1); //2021-11-29

LocalDate localDate1 = LocalDate.parse("20211129", DateTimeFormatter.ofPattern("yyyyMMdd"));
System.out.println(localDate1); //2021-11-29

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
System.out.println(l.format(dtf));// 2021-01-29 十位转八位 ==> 20210129

dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
System.out.println(l.format(dtf));// 2021-01-29  ==> 2021年01月29日

dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd");
System.out.println(l.format(dtf));// 2021-01-29  ==> 2021/01/29


六:LocalDate进阶,获取月末、月首、本周一、下周五、每个月的周一

java8 LocalDate的使用、LocalDate格式化_当前日期_06

1、LocalDate with(TemporalAdjuster adjuster)

该方法用于使用传递的TemporalAdjuster作为参数来调整此日期时间,并在调整后返回调整后的日期时间的副本。使用指定的调整器策略对象进行调整。该LocalDate实例是不可变的,不受此方法调用的影响。

参数:该方法接受调节器作为要使用的调节器的参数。

返回值:该方法将基于此方法返回LocalDate并进行调整。

异常:此方法引发以下异常:

DateTimeException–如果无法进行调整。
ArithmeticException–如果发生数字溢出。

TemporalAdjuster:时间调节器

有的时候,你需要进行一些更加灵活复杂的操作,比如,将日期调整到下个周日、下个工作日,或者是本月的最后一天。这时,就需要时间调节器 TemporalAdjuster,可以更加灵活地处理日期。TemporalAdjusters 工具提供了一些通用的功能,并且你还可以新增你自己的功能。

java8 LocalDate的使用、LocalDate格式化_当前日期_07

LocalDate now = LocalDate.now();
System.out.println("当前时间:"+now); //2021-11-30

//获取当月第一天
System.out.println("当月第一天:"+now.with(TemporalAdjusters.firstDayOfMonth()));// 2021-11-01
//获取本月第2天:
System.out.println("本月第2天:"+now.withDayOfMonth(2)); //2021-11-02
//获取下月第一天
System.out.println("下月第一天:"+now.with(TemporalAdjusters.firstDayOfNextMonth())); //2021-12-01
//获取明年第一天
System.out.println("明年第一天:"+now.with(TemporalAdjusters.firstDayOfNextYear())); //2022-01-01
//获取本年第一天
System.out.println("本年第一天:"+now.with(TemporalAdjusters.firstDayOfYear()));//2021-01-01
//获取当月最后一天,再也不用计算是28,29,30还是31:
System.out.println("当月最后一天:"+now.with(TemporalAdjusters.lastDayOfMonth())); //2021-11-30
//获取本年最后一天
System.out.println("本年最后一天:"+now.with(TemporalAdjusters.lastDayOfYear())); //2021-12-31
//获取当月的第一个星期一
System.out.println("当月的第一个星期一:"+now.with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY))); //2021-11-01
//获取当月的最后一个星期一
System.out.println("当月的最后一个星期一:"+now.with(TemporalAdjusters.lastInMonth(DayOfWeek.MONDAY))); //2021-11-29

//获取当月第三周星期五
System.out.println("当月第三周星期五:"+now.with(TemporalAdjusters.dayOfWeekInMonth(3, DayOfWeek.FRIDAY))); //2021-11-19
//获取本周一
System.out.println("本周一:"+now.with(DayOfWeek.MONDAY)); //2021-11-29
//获取上周二
System.out.println("上周二:"+now.minusWeeks(1).with(ChronoField.DAY_OF_WEEK, 2)); //2021-11-23
//(往前不包括当天)获取当前日期的上一个周一  如果今天是周一,则返回上周一
System.out.println("上一个周一(不包括当天):"+now.with(TemporalAdjusters.previous(DayOfWeek.MONDAY))); //2021-11-29
//(往前包括当天)最近星期五的日期  如果今天是星期五,则返回今天日期
System.out.println("上一个周一(包括当天):"+now.with(TemporalAdjusters.previousOrSame(DayOfWeek.FRIDAY))); //2021-11-26
//获取下周二
System.out.println("下周二:"+now.plusWeeks(1).with(ChronoField.DAY_OF_WEEK, 2)); //2021-12-07
//(往后不包括当天)获取当前日期的下一个周日 如果今天是周日,则返回下周日的时间  如果今天是星期一,则返回本周日的时间
System.out.println("下一个周日(不包括当天):"+now.with(TemporalAdjusters.next(DayOfWeek.SUNDAY))); //2021-12-05
//(往后包括当天)最近星期五的日期  如果今天是星期五,则返回今天日期
System.out.println("下一个周日(包括当天):"+now.with(TemporalAdjusters.nextOrSame(DayOfWeek.FRIDAY))); //2021-12-03


七.LocalDateTime与Date的互转

/**
  * Date转LocalDateTime
  * @param date Date
  * @return LocalDateTime
  */
 public static LocalDateTime dateToLocalDateTime(Date date) {
     Instant instant = date.toInstant();
     ZoneId zoneId = ZoneId.systemDefault();
     return instant.atZone(zoneId).toLocalDateTime();
 }

 /**
  * LocalDateTime转Date
  * @param localDateTime LocalDateTime
  * @return Date
  */
 public static Date localDateTimeToDate(LocalDateTime localDateTime) {
     ZoneId zoneId = ZoneId.systemDefault();
     ZonedDateTime zdt = localDateTime.atZone(zoneId);
     return Date.from(zdt.toInstant());
 }

参考:

LocalDate官方api

https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html


转自: