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()); // 1
System.out.println(period.getMonths()); // 0
System.out.println(period.getDays()); // -2
操作日期
Java8
为日期提供了非常方便地操作 API
设置属性
可以通过 with
方法设置某个属性的值。但如果日期对象不支持设置的属性,则会抛出 UnsupportedTemporalTypeException
,比如设置 LocalDate
对象的 ChronoField.NANO_OF_SECOND
属性。
LocalDate date1 = LocalDate.of(2021, 4, 1); // 2021-04-01
LocalDate date2 = date1.withYear(2011); // 2011-04-01
LocalDate date3 = date2.withDayOfMonth(25); // 2011-04-25
LocalDate 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); // 20210401
String 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);