前言
- 在java8之前,我们处理日期会存在不少问题,比如日期转换繁琐,计算困难,线程安全等等各种问题。为了解决这些痛处,在java8中引入了java.time包,全新的日期处理方法从根本上解决了这些痛处。
常见的API说明
-
LocalDateTime 表示没有时区的日期时间,一般表示:年月日时分秒,不可变并且线程安全。
-
LocalDate 表示没有时区的日期时间,一般表示:年月日,不可变并且线程安全。
-
LocalTime 表示没有时区的日期时间,一般表示:时分秒,不可变并且线程安全。
-
ZoneId 时区的Id
-
ZonedDateTime 具有时区的日期时间,存储所有日期和时间字段,精度为纳秒,时区为区域偏移量,用于处理模糊的本地日期时间。
-
Instant 对时间轴上的单一瞬时点建模,表示时间线上的一个点(瞬时),主要用于Date和我们新的日期api之间相互转换
-
Duration 表示一段时间,可用于计算两个时间(时分秒等)间隔
-
Period 表示一段时间,可用于计算两个日期(年月日等)间隔
我们主要围绕LocalDate、LocalTime、LocalDateTime三个基础对象来进行演示
使用示例
- 获取当前时间,使用 now() 来创建对象
LocalDateTime localDateTime = LocalDateTime.now();
LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.now();
ZonedDateTime zonedDateTime = ZonedDateTime.now();
Instant instant = Instant.now();
Year year = Year.now();
YearMonth yearMonth = YearMonth.now();
MonthDay monthDay = MonthDay.now();
System.out.println("localDateTime:" + localDateTime);
System.out.println("localDate:" + localDate);
System.out.println("localTime:" + localTime);
System.out.println("zonedDateTime:" + zonedDateTime);
System.out.println("instant:" + instant);
System.out.println("year:" + year);
System.out.println("yearMonth:" + yearMonth);
System.out.println("monthDay:" + monthDay);
---控制台输出---
localDateTime:2021-09-21T20:49:56.544
localDate:2021-09-21
localTime:20:49:56.544
zonedDateTime:2021-09-21T20:49:56.544+08:00[Asia/Shanghai]
instant:2021-09-21T12:49:56.545Z
year:2021
yearMonth:2021-09
monthDay:--09-21
- 使用 of() 指定时间日期的创建
LocalDateTime localDateTime = LocalDateTime.of(2021, 9, 21, 6, 30, 10);
LocalDate localDate = LocalDate.of(2021, 9, 21);
LocalTime localTime = LocalTime.of(6, 30, 10);
System.out.println("localDateTime:" + localDateTime);
System.out.println("localDate:" + localDate);
System.out.println("localTime:" + localTime);
//其中LocalDateTime可以传入localDate和localTime来创建
LocalDateTime localDateTime2 = LocalDateTime.of(localDate, localTime);
System.out.println("localDateTime2:" + localDateTime2);
---控制台输出---
localDateTime:2021-09-21T06:30:10
localDate:2021-09-21
localTime:06:30:10
localDateTime2:2021-09-21T06:30:10
-
时区
我们可以通过提供的ZoneId类中的方法可以获取一个Set集合,集合中封装了600个时区,大家可以自己输出到控制台查看
Set<String> setZondId = ZoneId.getAvailableZoneIds();
setZondId.stream().forEach(System.out::println);
同时也提供了获取当前系统默认的时区的方式
ZoneId zoneId = ZoneId.systemDefault();
//控制台输出:Asia/Shanghai
System.out.println(zoneId);
我们可以通过给LocalDateTime添加时区查看不同时区的时间。比如我们想获取上海和东京的时间
LocalDateTime now = LocalDateTime.now();
// 使用atZone添加时区
ZonedDateTime zonedDateTime = now.atZone(ZoneId.of("Asia/Shanghai"));
// ZonedDateTime的withZoneSameInstant()方法可以更改时区
ZonedDateTime zonedDateTime2 = zonedDateTime.withZoneSameInstant(ZoneId.of("Asia/Tokyo"));
System.out.println("Asia/Shanghai:" + zonedDateTime);
System.out.println("Asia/Tokyo:" + zonedDateTime2);
---控制台输出---
Asia/Shanghai:2021-09-21T21:18:13.499+08:00[Asia/Shanghai]
Asia/Tokyo:2021-09-21T22:18:13.499+09:00[Asia/Tokyo]
我们可以看出东京比上海多一个小时
-
日期的加减
我们可以使用 plus() 对日期进行添加,使用 minus() 对日期进行减少,以下只示例部分方法,其它请自行测试
LocalDateTime now = LocalDateTime.now();
System.out.println("now:" + now);
LocalDateTime plusYears = now.plusYears(1);
LocalDateTime minusYears = now.minusYears(1);
System.out.println("plusYears:" + plusYears);
System.out.println("minusYears:" + minusYears);
LocalDateTime plusDays = now.plusDays(10);
LocalDateTime minusDays = now.minusDays(10);
System.out.println("plusDays:" + plusDays);
System.out.println("minusDays:" + minusDays);
---控制台输出---
now:2021-09-21T21:31:33.295
plusYears:2022-09-21T21:31:33.295
minusYears:2020-09-21T21:31:33.295
plusDays:2021-10-01T21:31:33.295
minusDays:2021-09-11T21:31:33.295
这里我们可以在plus()方法中传入负数,效果即为减少日期,minus()中传入负数即为添加日期。两个方法底层其实调用的是同一个方法。
日期的加减我们也可以使用另外一种方式,即plus(long amountToAdd, TemporalUnit unit)
LocalDateTime now = LocalDateTime.now();
System.out.println("now:" + now);
LocalDateTime nextYear = now.plus(1, ChronoUnit.YEARS);
LocalDateTime nextMonth = now.plus(1, ChronoUnit.MONTHS);
LocalDateTime nextDay = now.plus(1, ChronoUnit.DAYS);
System.out.println("nextYear:" + nextYear);
System.out.println("nextMonth:" + nextMonth);
System.out.println("nextDay:" + nextDay);
---控制台输出---
now:2021-09-21T21:43:19.384
nextYear:2022-09-21T21:43:19.384
nextMonth:2021-10-21T21:43:19.384
nextDay:2021-09-22T21:43:19.384
-
with()方法直接对日期进行修改
如果不需要对日期进行加减而是要直接修改日期的话,那么可以使用with方法
LocalDateTime now = LocalDateTime.now();
System.out.println("now:" + now);
LocalDateTime withYear = now.withYear(2030);
System.out.println("withYear:" + withYear);
LocalDateTime withMonth = now.withMonth(6);
System.out.println("withMonth:" + withMonth);
---控制台输出---
now:2021-09-21T21:48:55.118
withYear:2030-09-21T21:48:55.118
withMonth:2021-06-21T21:48:55.118
- 获取日期的年月日时分秒
LocalDateTime now = LocalDateTime.now();
int year = now.getYear();
int monthValue = now.getMonthValue();
int dayOfMonth = now.getDayOfMonth();
int hour = now.getHour();
int minute = now.getMinute();
int second = now.getSecond();
System.out.println("year:" + year + "__month:" + monthValue + "__day" + dayOfMonth + "__hour:" + hour
+ "__minute:" + minute + "__second:" + second);
---控制台输出---
year:2021__month:9__day21__hour:21__minute:58__second:6
- 日期前后的比较
LocalDateTime date1 = LocalDateTime.of(2021, 9, 21, 10, 30, 30);
LocalDateTime date2 = LocalDateTime.of(2030, 10, 28, 10, 30, 30);
System.out.println("date1是否比date2日期小:" + date1.isBefore(date2));
System.out.println("date1是否比date2日期大:" + date1.isAfter(date2));
---控制台输出---
date1是否比date2日期小:true
date1是否比date2日期大:false
-
日期的间隔计算
首先是计算两个日期间隔的时间段
LocalDateTime date1 = LocalDateTime.of(2021, 9, 21, 10, 30, 30);
LocalDateTime date2 = LocalDateTime.of(2025, 11, 25, 11, 30, 30);
//注意此处只比较时分秒,不考虑年月日
Duration duration = Duration.between(date1.toLocalTime(), date2.toLocalTime());
System.out.println("date1和date2日期间隔" + duration.toHours() + "小时" + duration.toMinutes() + "分钟"
+ duration.toMillis() / 1000 + "秒");
//注意此处只比较年月日,不考虑时分秒
Period period = Period.between(date1.toLocalDate(), date2.toLocalDate());
System.out.println("date1和date2日期间隔" + period.getYears() + "年" + period.getMonths() + "月"
+ period.getDays() + "天");
---控制台输出---
date1和date2日期间隔1小时60分钟3600秒
date1和date2日期间隔4年2月4天
扩展:既然Period和Duration 表示一段时间间隔,那么我们可以在一个日期上直接添加这个日期间隔
LocalDateTime now = LocalDateTime.now();
System.out.println("now:" + now);
//此处表示时间间隔为一年一个月一天
Period period = Period.of(1, 1, 1);
LocalDateTime plusDate = now.plus(period);
System.out.println("plusDate:" + plusDate);
---控制台输出---
now:2021-09-21T22:24:05.166
plusDate:2022-10-22T22:24:05.166
接下来是直接计算连个日期间隔的特定单位(年月日时分秒)
LocalDate date = LocalDate.of(2021, 9, 20);
LocalDate date2 = LocalDate.of(2022, 10, 21);
System.out.println("间隔年:" + ChronoUnit.YEARS.between(date, date2));
System.out.println("间隔月:" + ChronoUnit.MONTHS.between(date, date2));
System.out.println("间隔天:" + ChronoUnit.DAYS.between(date, date2));
---控制台输出---
间隔年:1
间隔月:13
间隔天:396
- 通过TemporalAdjusters中的一些方法获取一些特定的日期
LocalDateTime date = LocalDateTime.of(2021, 9, 20, 10, 30, 30);
//获取该日期的当月第一天
LocalDateTime with = date.with(TemporalAdjusters.firstDayOfMonth());
//获取该日期的当月最后一天
LocalDateTime with2 = date.with(TemporalAdjusters.lastDayOfMonth());
//在该日期基础上获取上一个周六
LocalDateTime with3 = date.with(TemporalAdjusters.previous(DayOfWeek.SATURDAY));
//在该日期基础上获取下一个周六
LocalDateTime with4 = date.with(TemporalAdjusters.next(DayOfWeek.SATURDAY));
- 日期的格式化
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// LocalDateTime转字符串
LocalDateTime date = LocalDateTime.now();
String format = date.format(dateTimeFormatter);
System.out.println(format);
// 字符串转换LocalDateTime
String formatDate = "2021-09-21 22:46:26";
LocalDateTime parse = LocalDateTime.parse(formatDate, dateTimeFormatter);
System.out.println(parse);
- java.util.date和新日期api之间的转换
//java.util.date转换新日期api
Date now = new Date();
LocalDateTime localDateTime = now.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
LocalDate localDate = now.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
LocalTime localTime = now.toInstant().atZone(ZoneId.systemDefault()).toLocalTime();
// localDateTime转换java.util.date
Date date1 = Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant());
// localDate转换java.util.date
Date date2 = Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant());
// 注意localTime转换java.util.date,必须指定年月日
Date date3 = Date.from(LocalTime.now().atDate(LocalDate.now()).atZone(ZoneId.systemDefault()).toInstant());
最后
用惯了旧的日期api刚接触可能不太习惯,但是,熟能生巧。加油!为了更好地自己