文章目录
简述新的日期时间API
Java 的日期与时间 API 问题由来已久,Java 8 之前的版本中关于时间、日期及其他时间日期格式化类由于线程安全、重量级、序列化成本高等问题而饱受批评。Java 8 吸收了 Joda-Time 的精华,以一个新的开始为 Java 创建优秀的 API。新的 java.time 中包含了所有关于时钟(Clock),本地日期(LocalDate)、本地时间(LocalTime)、本地日期时间(LocalDateTime)、时区(ZonedDateTime)和持续时间(Duration)的类。
历史悠久的 Date 类新增了 toInstant() 方法,用于把 Date 转换成新的表示形式。这些新增的本地化时间日期 API 大大简化了了日期时间和本地化的管理。
目前Java8新增了java.time包定义的类表示日期-时间概念的规则,很方便使用;最重要的一点是值不可变,且线程安全。
- LocalDate:本地日期类,只有年月日
- LocalTime:本地时间类,只有时分秒
- LocalDateTime:本地日期时间类,包含年月日时分秒
- MonthDay:月日
- YearMonth:年月
- ZoneId:时区
下图是java.time包下的一些主要的类的日期时间 值的格式,方便理解使用:
Note: 不过尽管有了新的API,但仍有一个严重的问题——大量的旧代码和库仍然在使用老的API。现在,Java 8解决了这个问题,它给Date类增加了一个新的方法toInstant(),可以将Date转化成新的实例。这样就可以切换到新的API。
获取时区
ZoneId zoneId = ZoneId.systemDefault();
System.out.println(zoneId.toString());
zoneId = ZoneId.of("Asia/Shanghai");
System.out.println(zoneId.toString());
zoneId = TimeZone.getTimeZone("CTT").toZoneId();
System.out.println(zoneId.toString());
结果:
Asia/Shanghai
Asia/Shanghai
Asia/Shanghai
获取日期时间
// 日期
LocalDate date = LocalDate.parse("20191011", DateTimeFormatter.ofPattern("yyyyMMdd"));
LocalDate date = LocalDate.of(2019, 10, 11); // 年 月 日
LocalDate nowDate = LocalDate.now();
// 时间
LocalTime time = LocalTime.parse("151210", DateTimeFormatter.ofPattern("HHmmss"));
LocalTime time = LocalTime.of(22, 12, 18); // 时 分 秒
LocalTime nowTime = LocalTime.now();
System.out.println(date);
System.out.println(time);
// 日期时间
LocalDateTime dateTime = LocalDateTime.of(2014, 3, 16, 13, 20, 22); // 年 月 日 时 分 秒
LocalDateTime dateTime1 = LocalDateTime.of(date, time);
LocalDateTime dateTime2 = LocalDateTime.parse("20191011150012", DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("---黄金分割线---");
System.out.println(dateTime1);
System.out.println(dateTime2);
获取具体的日期时间字段值
LocalDateTime dateTime = LocalDateTime.of(2019, 3, 10, 15, 30, 59);
System.out.println(dateTime);
System.out.println(dateTime.getYear()); // 年
System.out.println(dateTime.getMonthValue()); // 月
System.out.println(dateTime.getDayOfMonth()); // 日
System.out.println(dateTime.getHour()); // 时
System.out.println(dateTime.getMinute()); // 分
System.out.println(dateTime.getSecond()); // 秒
System.out.println(dateTime.getDayOfWeek()); // 星期几
日期时间格式化输出
DateTimeFormatter是不可变的,所以它是线程安全的。
LocalDate today = LocalDate.now();
System.out.println(today.format(DateTimeFormatter.ofPattern("yyyyMMdd")));
LocalTime time = LocalTime.now();
System.out.println("---黄金分割线---");
//24小时制
System.out.println(time.format(DateTimeFormatter.ofPattern("HH:mm:ss")));
//12小时制
System.out.println(time.format(DateTimeFormatter.ofPattern("hh:mm:ss")));
LocalDateTime now = LocalDateTime.of(today,time);
System.out.println("---黄金分割线---");
//yyyyMMdd
System.out.println(now.format(DateTimeFormatter.BASIC_ISO_DATE));
System.out.println(now.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
字符串转日期时间
LocalDate date = LocalDate.parse("20191011", DateTimeFormatter.ofPattern("yyyyMMdd"));
LocalTime time = LocalTime.parse("151210", DateTimeFormatter.ofPattern("HHmmss"));
LocalDateTime dateTime = LocalDateTime.parse("20191011150012", DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
LocalDateTime与Date的转换
Instant
时间点对象可以很容易的转换为老式的 java.util.Date
。
LocalDateTime dateTime = LocalDateTime.of(2019, 3, 10, 15, 30, 59);
Instant instant = dateTime.atZone(ZoneId.systemDefault()).toInstant();
//LocalDateTime 转 Date
Date date = Date.from(instant);
System.out.println(date);
//Date 转 LocalDateTime
instant = date.toInstant();
LocalDateTime localDateTime = instant.atZone(ZoneId.systemDefault()).toLocalDateTime();
System.out.println(localDateTime);
LocalDateTime与时间戳的转换
LocalDateTime localDateTime = LocalDateTime.now();
// LocalDateTime 转秒级时间戳
long timeStamp = localDateTime.toEpochSecond(ZoneOffset.ofHours(8));
System.out.println(timeStamp);
timeStamp = localDateTime.atZone(ZoneId.systemDefault()).toInstant().getEpochSecond();
System.out.println(timeStamp);
// 秒级时间戳转 LocalDateTime
LocalDateTime dateTime = Instant.ofEpochSecond(timeStamp).atZone(ZoneId.systemDefault()).toLocalDateTime();
System.out.println(dateTime);
// LocalDateTime 转毫秒级时间戳
timeStamp = localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
System.out.println("---黄金分割线---");
System.out.println(timeStamp);
// 毫秒级时间戳转 LocalDateTime
dateTime = Instant.ofEpochMilli(timeStamp).atZone(ZoneId.systemDefault()).toLocalDateTime();
System.out.println(dateTime);
时间调整到特定某天
LocalDateTime now = LocalDateTime.now();
System.out.println(now);
//同月的第一天
LocalDateTime firstDayInSameMonthOfNow = now.withDayOfMonth(1);
System.out.println(firstDayInSameMonthOfNow);
//同年的第一天
LocalDateTime firstDayInSameYearOfNow = now.withDayOfYear(1);
System.out.println(firstDayInSameYearOfNow);
//同年的第2月第10天
LocalDateTime time = now.withMonth(2).withDayOfMonth(10);
System.out.println(time);
//当天的6点10分15秒整
time = now.withHour(6).withMinute(10).withSecond(15).withNano(0);
System.out.println(time);
Duration一个时间段
// Duration.between()方法创建 Duration 对象
LocalDateTime from = LocalDateTime.of(2017, Month.JANUARY, 1, 00, 0, 0); // 2017-01-01 00:00:00
LocalDateTime to = LocalDateTime.of(2019, Month.SEPTEMBER, 12, 14, 28, 0); // 2019-09-15 14:28:00
Duration duration = Duration.between(from, to); // 表示从 from 到 to 这段时间
long days = duration.toDays(); // 这段时间的总天数
long hours = duration.toHours(); // 这段时间的小时数
long minutes = duration.toMinutes(); // 这段时间的分钟数
long seconds = duration.getSeconds(); // 这段时间的秒数
long milliSeconds = duration.toMillis(); // 这段时间的毫秒数
long nanoSeconds = duration.toNanos(); // 这段时间的纳秒数
LocalDateTime from = LocalDateTime.of(2019, 3, 10, 15, 30, 59);
LocalDateTime to = LocalDateTime.of(2019, 3, 15, 15, 30, 59);
Duration duration = Duration.between(from, to);
System.out.println(duration.compareTo(Duration.ofDays(2)));
System.out.println(duration.compareTo(Duration.ofDays(10)));
System.out.println("Duration in days: " + duration.toDays());
System.out.println("Duration in hours: " + duration.toHours());
增加、减少年数、月数、天数、小时、分钟、秒
plus
开头的方法都是增加日期时间的。
minus
开头的方法都是增加日期时间的。
with
开头的方法都是直接修改到指定值。
LocalDateTime localDateTime = LocalDateTime.of(2019, Month.SEPTEMBER, 12, 14, 32, 0);
// 增加一年
localDateTime = localDateTime.plusYears(1);
localDateTime = localDateTime.plus(1, ChronoUnit.YEARS);
// 减少一个月
localDateTime = localDateTime.minusMonths(1);
localDateTime = localDateTime.minus(1, ChronoUnit.MONTHS);
// 通过with修改某些值
// 修改年为2020
localDateTime = localDateTime.withYear(2020);
localDateTime = localDateTime.with(ChronoField.YEAR, 2020);
判断今天是否是生日
LocalDate now = LocalDate.now();
LocalDate birthday = LocalDate.of(1991, 10, 12);
MonthDay birthdayMonthDay = MonthDay.of(birthday.getMonth(), birthday.getDayOfMonth());
MonthDay nowMonthDay = MonthDay.from(now);
System.out.println(birthdayMonthDay.equals(nowMonthDay));
判断某个日期在另一个日期的前面还是后面
- isBefore():如果调用方法的那个日期比给定的日期要早的话,方法会返回true。
- isAfter():如果调用方法的那个日期比给定的日期晚的话,方法会返回true。
- isEqual():如果调用方法的那个日期比给定的日期相等的话,方法会返回true。
检查闰年
LocalDate类由一个isLeapYear()方法来返回当前LocalDate对应的那年是否是闰年。
获取今年的天数
// 获取今年的天数
int daysOfThisYear = LocalDate.now().lengthOfYear();
// 获取指定某年的天数
LocalDate.of(2011, 1, 1).lengthOfYear();
获取日期的开始和结束时间
获取当前月的第一天和最后一天
使用TemporalAdjusters方法实现。
LocalDate date = LocalDate.now();
LocalDate firstDay = date.with(TemporalAdjusters.firstDayOfMonth()); // 获取当前月的第一天
LocalDate lastDay = date.with(TemporalAdjusters.lastDayOfMonth()); // 获取当前月的最后一天
System.out.println(date); // 2021-11-11
System.out.println(firstDay); // 2021-11-01
System.out.println(lastDay); // 2021-11-30