java8之LocalDate的使用、LocalDate格式化问题

2023-05-17 14:05:04 localdate 格式化 Java8

前言

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

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

  • java.time.LocalDate ->只对年月日做出处理
  • java.time.LocalTime ->只对时分秒纳秒做出处理
  • java.time.LocalDateTime ->同时可以处理年月日和时分秒

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

一:创建LocalDate

方法说明
static LocalDate now()获取默认时区的当前日期,默认返回格式yyyy-MM-dd
static LocalDate now(Clock clock)从指定时钟获取当前日期
static LocalDate now(ZoneId zone)获取指定时区的当前日期
static LocalDate of(int year, int month, int dayOfMonth)根据指定的年、月、日获取LocalDate 实例
static LocalDate of(int year, Month month, int dayOfMonth)根据指定的年、月、日获取LocalDate 实例
static LocalDate ofYearDay(int year,int dayOfYear)根据指定的年,年中的第xx天获取LocalDate实例
static LocalDate ofEpochDay(long epochDay)从1970-01-01开始获取指定天数的LocalDate实例
static LocalDate parse(CharSequence text)字符串转换为LocalDate,字符串的格式必须为yyyy-MM-dd 10位长度的日期格式,否则会报错
static LocalDate parse(CharSequence text, DateTimeFormatter formatter)将text字符串转换为formatter格式,text的格式必须与formatter格式一致,如text为yyyyMMdd格式,则formatter也应该为yyyyMMdd格式,否则会报错

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日期比较

方法说明
boolean isBefore(ChronoLocalDate other)检查日期是否在指定日期之前
boolean isAfter(ChronoLocalDate other)检查日期是否在指定日期之后
boolean isEqual(ChronoLocalDate other)比较日期是否相同
int compareTo(ChronoLocalDate other)日期比较localDateA.compareTo(localDateB),若相等返回0;若A>B,返回1 ;若A<B返回-1

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

三:获取年、月、日

方法说明
int getYear()获取年份
Month getMonth()使用月枚举类型获取月份
int getMonthValue()返回数字月份 1-12月
int getDayOfMonth()获取日期在该月是第几天
DayOfWeek getDayOfWeek()获取日期是星期几
int getDayOfYear()获取日期在该年是第几天
boolean isLeapYear()检查是否闰年
int lengthOfMonth()返回日期所在月份共有几天
int lengthOfYear()返回日期所在年份共有几天
long toEpochDay()返回当前日期距离1970年1月1日的天数
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、加/减年、月、周、日

方法说明
LocalDate plus(long amountToAdd, TemporalUnit unit)通用方法,可以通过unit参数控制增加天、周、月、年
LocalDate plusDays(long daysToAdd)返回增加了*天的LocalDate副本
LocalDate plusWeeks(long weeksToAdd)返回增加了*周的LocalDate副本
LocalDate plusMonths(long monthsToAdd)返回增加了*月的LocalDate副本
LocalDate plusYears(long yearsToAdd)返回增加了*年的LocalDate副本
LocalDate minus(long amountToAdd, TemporalUnit unit)通用方法,可以通过unit参数控制减少天、周、月、年
LocalDate minusDays(long daysToSubtract)返回减少了*天的LocalDate副本
LocalDate minusWeeks(long weeksToSubtract)返回减少了*周的LocalDate副本
LocalDate minusMonths(long monthsToSubtract)返回减少了*月的LocalDate副本
LocalDate minusYears(long yearsToSubtract)返回减少了*年的LocalDate副本
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

以上方法返回的都是LocalDate实例的副本,即源对象localDate1变量的值不变

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

五:日期格式化

方法说明
String format(DateTimeFormatter formatter)使用特定格式化形式将LocalDate转为字符串
static LocalDate parse(CharSequence text)从文本字符串获取LocalDate实例,text必须是yyyy-MM-dd格式
static LocalDate parse(CharSequence text, DateTimeFormatter formatter)使用特定格式化形式从文本字符串获取LocalDate实例,text的格式必须与formatter格式一致,如text为yyyyMMdd格式,则formatter也应该为yyyyMMdd格式,否则会报错
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进阶,获取月末、月首、本周一、下周五、每个月的周一

方法说明
LocalDate with(TemporalAdjuster adjuster)使用传递的TemporalAdjuster作为参数来调整此日期时间,并在调整后返回调整后的日期时间的副本
LocalDate with(TemporalField field, long newValue)用于将LocalDate的指定字段设置为新值并返回新的日期时间的副本。此方法可用于更改任何受支持的字段,例如年,月或day-of-month。如果由于不支持该字段或其他原因而无法设置新值,则会引发异常。
LocalDate withMonth(int month)修改LocalDate变量的月份,如LocalDate.parse(“2021-10-30”).withMonth(3)则为2021-03-30
month:从1到12
LocalDate withDayOfMonth(int dayOfMonth)修改LocalDate变量的日,如LocalDate.parse(“2021-10-30”).withDayOfMonth(3)则为2021-10-03 dayOfMonth:从1到28-31
LocalDate withDayOfYear(int dayOfYear)返回当年第几天的日期,如当年第300天是几月几号,dayOfYear从1到365-366
LocalDate withYear(int year)修改LocalDate变量的年份,如LocalDate.parse(“2021-10-30”).withYear(2000)则为2000-10-30 year:从MIN_YEAR到MAX_YEAR

1、LocalDate with(TemporalAdjuster adjuster)

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

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

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

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

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

TemporalAdjuster:时间调节器

有的时候,你需要进行一些更加灵活复杂的操作,比如,将日期调整到下个周日、下个工作日,或者是本月的最后一天。

这时,就需要时间调节器 TemporalAdjuster,可以更加灵活地处理日期。

TemporalAdjusters 工具提供了一些通用的功能,并且你还可以新增你自己的功能。

方法说明
static TemporalAdjuster firstDayOfMonth()当前月的第一天
static TemporalAdjuster firstDayOfNextMonth()下一个月的第一天
static TemporalAdjuster firstDayOfNextYear()下一年的第一天
static TemporalAdjuster firstDayOfYear()当年的第一天
static TemporalAdjuster lastDayOfYear()当年的最后一天
static TemporalAdjuster lastDayOfMonth()当月的最后一天
static TemporalAdjuster firstInMonth(DayOfWeek dayOfWeek)某月的第一个星期几
static TemporalAdjuster lastInMonth(DayOfWeek dayOfWeek)某月的最后一个星期几
static TemporalAdjuster dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek)某月的第几个星期几,例如,三月中第二个星期二
static TemporalAdjuster next(DayOfWeek dayOfWeek)(往后不包括当天)下一个星期几是几月几号。若当前为周三,那么next(DayOfWeek.WEDNESDAY)指下一个周三即下周三;next(DayOfWeek.SUNDAY) 指下一个周日即本周日(此时并不是下周日)
static TemporalAdjuster nextOrSame(DayOfWeek dayOfWeek)(往后包括当天)最近星期几的日期。如最近星期五的日期,如果今天是星期五,则返回今天日期,如果今天不是星期五,则返回下周五的日期
static TemporalAdjuster previous(DayOfWeek dayOfWeek)(往前不包括当天)上一个星期几是几月几号。若当前为周三,那么previous(DayOfWeek.WEDNESDAY)指上一个周三即上周三;previous(DayOfWeek.TUESDAY) 指上一个周二即昨天(此时并不是上周二)
static TemporalAdjuster previousOrSame(DayOfWeek dayOfWeek)(往前包括当天)最近星期几的日期。如最近星期五的日期,如果今天是星期五,则返回今天日期,如果今天不是星期五,则返回上周五的日期
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的互转


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

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

参考:

LocalDate官方apihttps://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

相关文章