
在JDK1.0中,Date类是唯一的一个代表时间的类,但是由于Date类不便于实现国际化,所以从JDK1.1版本开始,使用Calendar类进行时间和日期处理。实际应用中,使用joda-time比较多(Java7以前),所以从Java8开始有了从joda改进的java.time包。
Date-Time API由主包 java.time 和四个子包组成:
| 包名 | 描述 |
| java.time | 表示日期和时间的 API 的核心。它包括日期、时间、日期&时间相结合的类别, 时区/zones,瞬间/instants,持续时间/duration 和 时钟/clocks。这些类基于 ISO-8601 中定义的日历系统, 并且不可变且线程安全。 |
| java.time.chrono | 用于表示除默认 ISO-8601 以外的日历系统的 API。您也可以定义自己的日历系统。本教程不包含任何细节。 |
| java.time.format | 用于格式化和分析日期和时间的类。 |
| java.time.temporal | 扩展 API 主要用于框架和库编写器,允许日期和时间类之间的互操作,查询和调整。字段(TemporalField 和 ChronoField) 和单位(TemporalUnit 和 ChronoUnit)在此包中定义。 |
| java.time.zone | 支持时区的类,时区的偏移和时区规则。如果使用时区,大多数开发人员只需使用 ZonedDateTime 和 ZoneId 或 ZoneOffse |
常用类| 类名 | 描述 |
| Instant | 本质上是一个时间戳 |
| LocalDate | 存储了日期,如:2010-12-03。可以用来存储生日 |
| LocalTime | 存储了时间,如:11:30 |
| LocalDateTime | 存储了日期和时间,如:2010-12-03T11:30 |
| ZonedDateTime | 存储一个带时区的日期和时间 |
java.time包的API提供了大量相关的方法,这些方法一般有一致的方法前缀
| 前缀名称 | 功能 | 例子 |
| of | 静态工厂方法 | DateTimeFormatter.ofPattern("yyyy年MM月d日")) |
| parse | 静态工厂方法,关注于解析 | |
| get | 获取值 | |
| is | 用于比较 | |
| with | 不可变的setter等价物 | |
| plus | 加一些量到某个对象 | plusMonths(1) |
| minus | 从某个对象减去一些量 | minusMonths(1) |
| to | 转换到另一个类型 | |
| at | 把这个对象与另一个对象组合起来,例如 | date.atTime(time) |
//获取当前日期时间
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("localDateTime :" + localDateTime);
//格式化输出时间,线程安全的格式化类
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月d日 hh:mm:ss");
System.out.println("format :" + dateTimeFormatter.format(localDateTime));
// 获取当前年份
Year year = Year.of(2019);
System.out.println("year :" + year);
// 从Year获取LocalDate
LocalDate localDate = year.atDay(41);
System.out.println("localDate :" + localDate);
// 把LocalTime关联到一个LocalDate得到一个LocalDateTime
LocalTime localTime = LocalTime.of(12,0);
LocalDateTime localDateTime1 = localTime.atDate(localDate);
System.out.println("localDateTime1 :" + dateTimeFormatter.format(localDateTime1));
// 判断是否是闰年
System.out.println("isLeapYear :" + localDate.isLeapYear());
localDateTime :2019-02-10T22:30:05.581042500 format :2019年02月10日 10:30:05 year :2019 localDate :2019-02-10 localDateTime1 :2019年02月10日 12:00:00 isLeapYear :false格式化与时间计算
| 类名 | 描述 |
| DateTimeFormatter | 在日期对象与字符串之间进行转换 |
| ChronoUnit | 计算出两个时间点之间的时间距离,可按多种时间单位计算 |
| TemporalAdjuster | 各种日期计算功能 |
DayOfWeek dayOfWeek = DayOfWeek.of(1);
System.out.println("dayOfWeek :" + dayOfWeek);
//计算两个日期之间时间,还可以按其他时间单位计算两个时间点之间的间隔。
long between = ChronoUnit.HOURS.between(LocalDateTime.of(2019,2,10,22,0), LocalDateTime.of(2019,2,9,22,0));
System.out.println("between :" + between);
// 解析字符串形式的日期时间
DateTimeFormatter dateTimeFormatter2 = DateTimeFormatter.ofPattern("yyyy MM d");
TemporalAccessor temporalAccessor = dateTimeFormatter2.parse("2019 01 31");
System.out.println("temporalAccessor :" + LocalDate.from(temporalAccessor));
//计算某月的第一天的日期
LocalDate with = localDate.with(TemporalAdjusters.firstDayOfMonth());
System.out.println("with :" + with);
// 计算某月的第一个星期一的日期
TemporalAdjuster temporalAdjuster = TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY);
LocalDate with1 = localDate.with(temporalAdjuster);
System.out.println("with1 :" + with1);
// 计算localDate的下一个星期一的日期
LocalDate with2 = localDate.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
System.out.println("with2 :" + with2);
输出:
dayOfWeek :MONDAY between :-24 temporalAccessor :2019-01-31 with :2019-02-01 with1 :2019-02-04 with2 :2019-02-11新旧之间的转换
Date.toInstant()
Date.from(Instant)
Calendar.toInstant()
注意:输出instant时可能会出现与实际时间差8个小时的情况,这是因为Date和Calender输出时是按照中国所在的时区(UTCGMT+8)输出的,而instant输出是按照相对于GMT的时间输出的,所以会相差8个小时。
应用1:LocalDateTime与String日期互相转换//LocalDateTime转换成String
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime ldt = LocalDateTime.now();
String ldtStr = df.format(ldt);
System.out.println("LocalDateTime转成String类型的时间:"+ldtStr);
//String转换成LocalDateTime
String ldtStr2 = "2017-09-28 17:07:05";
LocalDateTime ldt2 = LocalDateTime.parse(ldtStr2,df);
System.out.println("String类型的时间转成LocalDateTime:"+ldt2);
控制台结果:
LocalDateTime转成String类型的时间:2017-09-30 10:40:06 String类型的时间转成LocalDateTime:2017-09-28T17:07:05应用2:获得两个日期之间的所有月份
public void getBetweenMonth() {
String start = "2020-03-01";
String end = "2021-02-01";
List list = new ArrayList<>();
LocalDate startDate = LocalDate.parse(start);
LocalDate endDate = LocalDate.parse(end);
long distance = ChronoUnit.MONTHS.between(startDate, endDate);
if (distance < 1) {
list.forEach(li -> System.out.println(li));
}
Stream.iterate(startDate, d -> d.plusMonths(1)).limit(distance + 1).forEach(f -> {
list.add(f.toString());
});
list.forEach(li -> System.out.println(li));
}
应用3:每个月的第一天和最后一天
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String month = "2022-05-15"
LocalDate date = LocalDate.parse(month, dtf);
// 获取当前月的第一天
LocalDate firstDay = date.with(TemporalAdjusters.firstDayOfMonth());
// 获取当前月的最后一天
LocalDate lastDay = date.with(TemporalAdjusters.lastDayOfMonth());