Java8 引入全新的日期和时间API,主要包括LocalDate、LocalTime、LocalDateTime、Instant、Duration 以及Period
日期
LocalDate 表示日期
创建日期
// 创建指定日期LocalDate date=LocalDate.of(2020,4,1);// 创建当前日期LocalDate date=LocalDate.now();
获取日期属性
LocalDate date=LocalDate.of(2020,4,1);// 年int year= date.getYear();// 月int month= date.getMonthValue();// 日期int day= date.getDayOfMonth();// 星期几DayOfWeek weekDay= date.getDayOfWeek();// 是否润年boolean leapYear= date.isLeapYear();
时间
LocalTime 表示时间
创建时间
// 创建指定时间LocalTime time=LocalTime.of(13,40,50);// 创建当前时间LocalTime time=LocalTime.now();
获取时间属性
LocalTime time=LocalTime.of(13,40,50);// 小时int hour= time.getHour();// 分钟int minute= time.getMinute();// 秒int second= time.getSecond();
合并日期和时间
LocalDateTime 表示日期 + 时间,即有日期也有时间
创建日期时间
// 创建指定日期时间LocalDateTime time=LocalDateTime.of(2020,4,1,13,40,50);// 使用日期+时间进行创建LocalDateTime time=LocalDateTime.of(date, time);// 创建当前日期时间LocalDateTime time=LocalDateTime.now();
获取属性
LocalDateTime 也可以通过日期或者时间的get 方法,获取年、月、日、时、分、秒属性
LocalDateTime dt=LocalDateTime.of(2020,4,1,13,40,50);// 日期LocalDate date= dt.toLocalDate();// 时间LocalTime time= dt.toLocalTime();
时间戳
Instant 表示时间戳,记录从1970-01-01 00:00:00 时间以来的毫秒数。
创建时间戳
// 使用毫秒数进行构建Instant ins=Instant.ofEpochMilli(100);// 使用秒数进行构建Instant ins=Instant.ofEpochSecond(600);// 创建当前时间戳Instant ins=Instant.now();
时间段
Duration 及Period 都可以表示时间段。
Duration
创建Duration 时间段
Duration 以秒和纳秒衡量时间的长短,Duration 的between 方法不支持LocalDate
// 使用两个日期或者时间创建时间段Duration duration=Duration.between(time1, time2);Duration duration=Duration.between(dateTime1, dateTime2);Duration duration=Duration.between(instant1, instant2);// 创建单纯的时间段Duration threeMinutes=Duration.ofMinutes(3);Duration threeMinutes=Duration.of(3,ChronoUnit.MINUTES);
获取Duration 属性
// 获取时间段的总天数long diffDays= duration.toDays()// 获取时间段的总小时数long diffHours= duration.toHours()// 获取时间段的总分钟数long diffMinutes= duration.toMinutes()// 获取时间段的总秒数long diffSeconds= duration.toSeconds()// 获取时间段的总毫秒数long diffMillis= duration.toMillis()
Period
Period 以年-月-日 多个时间单位表示时间段。
创建Period 时间段
// 使用两个日期创建时间段Period period=Period.between(date1, date2);// 使用单纯的时间段Period oneYear=Period.ofYears(1);Period oneYear=Period.of(1,0,0);
获取Period 属性
// 年long diffYears= period.getYears()// 月long diffMonth= duration.getMonths()// 日long diffDays= duration.getDays()
示例
Period period=Period.between(LocalDate.of(2020,10,8),LocalDate.of(2021,10,6));System.out.println(period.getYears());// 1System.out.println(period.getMonths());// 0System.out.println(period.getDays());// -2
操作日期
Java8 为日期提供了非常方便地操作API
设置属性
可以通过with 方法设置某个属性的值。但如果日期对象不支持设置的属性,则会抛出UnsupportedTemporalTypeException,比如设置LocalDate 对象的ChronoField.NANO_OF_SECOND 属性。
LocalDate date1=LocalDate.of(2021,4,1);// 2021-04-01LocalDate date2= date1.withYear(2011);// 2011-04-01LocalDate date3= date2.withDayOfMonth(25);// 2011-04-25LocalDate date4= date3.with(ChronoField.MONTH_OF_YEAR,9);// 2011-09-25
日期增减
通过plus 及minus 方法进行日期的增减操作
LocalDate date1=LocalDate.of(2021,4,1);// 增加一个星期LocalDate date2= date1.plusWeeks(1);// 减三年LocalDate date3= date2.minusYears(3);// 增加六个月LocalDate date4= date3.plus(6,ChronoUnit.MONTHS);
使用TemporalAdjuster
目前使用的日期操作方法都是比较直接的,但有时需要一些更复杂的操作,比较:将日期调整为下个周日,调整为当月最后一天,这时可以使用with 方法的重载版本,传入一个TemporalAdjuster 对象,可以更加灵活地处理日期。
LocalDate date1=LocalDate.of(2021,4,1);// 当月最后一天LocalDate date2= date1.with(TemporalAdjusters.lastDayOfMonth());// 当前日期最近的一个星期天LocalDate date3= date1.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
| 方法名 | 描述 | 
|---|---|
| dayOfWeekInMonth | 同一个月中每一周的第几天 | 
| firstDayOfMonth | 当月的第一天 | 
| firstDayOfNextMonth | 下月的第一天 | 
| firstDayOfNextYear | 明年的第一天 | 
| firstDayOfYear | 当年的第一天 | 
| firstInMonth | 同一个月中,第一个符合星期几要求的值 | 
| lastDayOfMonth | 当月的最后一天 | 
| lastDayOfNextMonth | 下月的最后一天 | 
| lastDayOfNextYear | 明年的最后一天 | 
| lastDayOfYear | 今年的最后一天 | 
| lastInMonth | 同一个月中,最后一个符合星期几要求的值 | 
| next/previous | 日期调整后或者调整前,第一个符合指定星期几要求的日期 | 
| nextOrSame/previousOrSame | 日期调整后或者调整前,第一个符合指定星期几要求的日期,如果该日期已经符合要求,直接返回该对象 | 
日期格式化
日期解析以及日期格式化也是日期的一个非常重要的功能。Java8 提供了DateTimeFormatter 类用来辅助格式化。DateTimeFormatter 提供了几个国际化格式,但通常我们更多地使用ofPattern 创建自定义格式。
格式化输出
LocalDate date=LocalDate.of(2021,4,1);String s1= date.format(DateTimeFormatter.BASIC_ISO_DATE);// 20210401String s2= date.format(DateTimeFormatter..ofPattern("yyyy-MM-dd"));// 2021-04-01
解析字符串
LocalDate date1=LocalDate.parse("20210401",DateTimeFormatter.BASIC_ISO_DATE);LocalDate date2=LocalDate.parse("2021-04-01",DateTimeFormatter..ofPattern("yyyy-MM-dd"));
时区
前文中出现的所有日期、时间类型都不包含时区信息,Java8 提供了java.time.ZoneId 类来进行时区处理,用于代替老版的java.util.TimeZone。时区是按照一定的规则将区域划分成的标准时间相同的区间,每个特定的ZoneId 对象都由一个地区ID 标识
ZoneId romeZone=ZoneId.of("Europe/Rome");
原来的TimeZone 也可以转换为ZoneId
ZoneId zoneId=TimeZone.getDefault().toZoneId();
一旦得到一个ZoneId 对象,你就可以将它与LocalDate、LocalDateTime 或者Instant 对象整合起来,构造为一个ZonedDateTime 实例,它代表了相对于指定时区的时间点。
LocalDate date=LocalDate.of(2020,Month.MARCH,1);ZonedDateTime zdt1= date.atStartOfDay(romeZone);LocalDateTime dateTime=LocalDateTime.of(2020,Month.MARCH,1,12,30);ZonedDateTime zdt2= dateTime.atZone(romeZone);Instant instant=Instant.now();ZonedDateTime zdt3= instant.atZone(romeZone);

通过ZoneId 也可以实现LocalDateTime 与Instant 间的转换
Instant instant=LocalDateTime.now().toInstant(romeZone);LocalDateTime ldt=LocalDateTime.ofInstant(Instant.now(), romeZone);
日历
日期系统默认使用ISO-8601 日历系统,即世界文明日历系统(阳历),Java8 也提供了 4 种其它的日历系统,每个日历系统都有一个对应的日期类:ThaiBuddhistDate、MinguoDate、JapaneseDate 及HijrahDate。
LocalDate date=LocalDate.of(2020,Month.MARCH,18);JapaneseDate japaneseDate=JapaneseDate.from(date);




