目录
一 java.time背景
用过 java.util.Date 和 java.sql.Date 的或多或少都会觉得这这两个日期 API 包设计的太不友好,太反人类。比如:
- 什么 java.util.Date 是可变类型;
- SimpleDateFormatter 不是线程安全的;
- 甚至 java.util.Date 月份从0开始,一月是0,十二月是11等等。
为了解决这些痛点,Java 8 的 java.time 包出现了,该包下的所有类都是不可变类型,而且都是线程安全的。
你可能会发现该包的很多 API 与 JodaTime 类似,因为 Java 8 的时间包设计参考了 JodaTime 设计。
二 java.time重点类
下面我们简单了解一下java.time包下一些重点类:
Clock:时钟,比如获取当前中国北京的时间。
Instant:时间戳。
Duration:持续时间,用于计算时间差。
LocalDate:只包含日期,比如:2021-01-17 。
LocalTime:只包含时间,比如:14:15:10。
LocalDateTime:同时包含日期和时间,比如:2021-01-170 14:15:10。
Period:时间段,用于计算时间差。
ZoneOffset:时区偏移量,比如:+8:00。
ZonedDateTime:带时区的时间。
java.time包下,
其他都是一些很简单的类,都是比较见名知意的。
三 java.time
基本操作
3.1 创建日期
//当前日期
LocalDate localDate = LocalDate.now();
//指定日期
LocalDate localDate = LocalDate.of(2021, 01, 17);
3.2 创建时间
//当前时间
LocalTime localTime1 = LocalTime.now();
//指定时间
LocalTime localTime2= LocalTime.of(15, 11, 15);
3.3 创建日期和时间
LocalDateTime localDateTime = LocalDateTime.now();
3.4 获取年
//今年
int now = LocalDate.now().getYear()
//明年
int after = LocalDate.now().plusYears(1).getYear();
//去年
int before = LocalDate.now().minusYears(1).getYear();
3.5 获取月
//这个月
int now = LocalDate.now().getMonthValue()
//下个月
int after = LocalDate.now().plusMonths(1).getMonthValue();
//上个月
int before = LocalDate.now().minusMonths(1).getMonthValue();
3.6 获取日
//今天
int now = LocalDate.now().getDayOfMonth();
//明天
int after = LocalDate.now().plusDays(1).getDayOfMonth();
//昨天
int before = LocalDate.now().minusDays(1).getDayOfMonth();
3.7 获取时
//这个时辰
int now = LocalTime.now().getHour();
//下个时辰
int after = LocalTime.now().plusHours(1).getHour();
//上个时辰
int before = LocalTime.now().minusHours(1).getHour();
3.8 获取分
//这一分钟
int now = LocalTime.now().getMinute();
//下一分钟
int after = LocalTime.now().plusMinutes(1).getMinute();
//上一分钟
int before = LocalTime.now().minusMinutes(1).getMinute();
3.9 获取秒
//这一秒
int now = LocalTime.now().getSecond();
//下一秒
int after = LocalTime.now().plusSeconds(1).getSecond();
//上一秒
int before = LocalTime.now().minusSeconds(1).getSecond();
四 java.time
日常应用
4.1 Instant 与 Date 互转
4.1.1 Instant 转 Date
Instant instant = Instant.now();
Date date = Date.from(instant);
4.1.2 Date 转 Instant
Date date = new Date();
Instant instant = date.toInstant();
4.2 LocalDateTime 与 Date 互转
4.2.1 LocalDateTime 转 Date
LocalDateTime localDateTime = LocalDateTime.now();
Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
Date date = Date.from(instant);
4.2.2 Date 转 LocalDateTime
Date date = new Date();
LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
4.3 日期时间格式化输出
4.3.1 LocalDateTime 格式化输出
LocalDateTime localDateTime = LocalDateTime.now();
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String string = dateTimeFormatter.format(localDateTime);
4.3.2 LocalDate 格式化输出
LocalDate data = LocalDate.now();
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy:MM:dd");
String string = dateTimeFormatter.format(data);
4.4 时间进行比较
4.4.1 日期前后对比
LocalDate today = LocalDate.now();
LocalDate speDay = LocalDate.of(2021,01,18);
boolean isAfter = today.isAfter(speDay);
4.4.2 时间前后对比
LocalTime today = LocalTime.now();
LocalTime speDay = LocalTime.of(15,01,18);
boolean isAfter = today.isAfter(speDay);
4.5 加法操作和减法操作
4.5.1 加法操作
//获取当前时间
LocalDateTime localDateTime = LocalDateTime.now();
// 加1年
LocalDateTime plusYears = localDateTime.plusYears(1L);
// 加1个月
LocalDateTime plusMonths = localDateTime.plusMonths(1L);
// 加一天
LocalDateTime plusDays = localDateTime.plusDays(1L);
// 加1个小时
LocalDateTime plusHours = localDateTime.plusHours(1L);
// 加10分
LocalDateTime plusMinutes = localDateTime.plusMinutes(10L);
4.5.2 减法操作
// 减1年
LocalDateTime minusYears = localDateTime.minusYears(1L);
System.out.println("minusYears = " + minusYears);
//输出: minusYears = 2019-07-06T22:53:38.264
// 减1个月
LocalDateTime minusMonths = localDateTime.minusMonths(1L);
System.out.println("minusMonths = " + minusMonths);
//输出: minusMonths = 2020-06-06T22:53:38.264
// 减一天
LocalDateTime minusDays = localDateTime.minusDays(1L);
System.out.println("minusDays = " + minusDays);
//输出: minusDays = 2020-07-05T22:53:38.264
// 减1个小时
LocalDateTime minusHours = localDateTime.minusHours(1L);
System.out.println("minusHours = " + minusHours);
//输出: minusHours = 2020-07-06T21:53:38.264
// 减10分
LocalDateTime minusMinutes = localDateTime.minusMinutes(10L);
System.out.println("minusMinutes = " + minusMinutes);
//输出: minusMinutes = 2020-07-06T22:43:38.264
4.6 计算日期时间差
4.6.1 LocalDateTime 计算时间差
LocalDateTime begin = LocalDateTime.of(2021,01, 17, 15, 13, 14);
LocalDateTime end = LocalDateTime.of(2021,01, 18, 15, 13, 14);
Duration duration = Duration.between(begin, end);
long days = duration.toDays();
long hours = duration.toHours();
long minutes = duration.toMinutes();
4.6.2 LocalDate 计算时间差
LocalDate begin = LocalDate.of(2021,01, 17);
LocalDate end = LocalDate.of(2021,01, 18);
Period period = Period.between(begin, end);
int months = period.getMonths();
五 总结遇到的坑
5.1 Period.getDays() 方法
Period.between() 获取的是两个日期差几年零几月零几天,Period.getDays()获取到的是零几天。如果需要计算两个日期差几天就不能使用 Period.getDays() 方法。
测试代码:
LocalDate begin = LocalDate.of(2021,01, 17);
LocalDate end = LocalDate.of(2021,02, 18);
Period period = Period.between(begin, end);
// 2021.02.18与2021.01.17相差32天
System.out.println(period.getDays());
System.out.println(ChronoUnit.DAYS.between(begin, end));
测试结果:
使用 ChronoUnit.DAYS.between 来计算两个日期之间相差的天数。
5.2 Date.getTime() 方法
比如希望得到当前时间之后 30 天的时间。
测试代码:
Date today = new Date();
Date nextMonth = new Date(today.getTime() + 30 * 1000 * 60 * 60 * 24);
System.out.println(today);
System.out.println(nextMonth);
测试结果:
发现30天后的时间还比当前时间小。出现这个问题,其实是因为 int 发生了溢出。修复方式就是把 30 改为 30L,让其成为一个 long。
测试代码:
Date today = new Date();
Date nextMonth = new Date(today.getTime() + 30L * 1000 * 60 * 60 * 24);
System.out.println(today);
System.out.println(nextMonth);
测试结果:
建议尽量用api来计算时间,别手动计算。