Java8新引入了一些日期、时间对象,这些对象与老的日期时间对象的使用上存在很大的不同,刚开始会很不习惯,但经过初步的使用后一定会更习惯使用这些新的API的,它使得对日期时间对象的操作上不会再如老的使用方式那样痛苦。
首先需要明确的一个概念就是,Java8中将日期与时间对象区分开了。如果只需要使用年、月、日而不关注时间信息,可以直接使用LocalDate;如果需要关注时间信息,可以使用LocalDateTime; 如果只关注时间信息,可以使用LocalTime。
本文主要学习LocalDate日期类型的常见用法,时间相关类型用法与日期类型非常相似,因此不再花时间赘述。
先简单说明下几个新的类:
LocalDate: 日期类型对象
Period: 时间间隔,如两个日期对象之间的间隔;
Month: 月份枚举类;
DateTimeFormatter: 日期格式化及从字符串解析的类;
ChronoField: 代表各个字段的枚举类(如年、月、日、一年当中的天等);
IsoFields: 在ChronoField基础上增加的一些额外的字段,如季度相关的DAY_OF_QUARTER等;
接下来主要说明日期的一些常见使用场景:
-
创建日期对象:
// 获取当前时间 LocalDate localDate = LocalDate.now(); // 通过Formatter解析时间 DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyyMMdd"); LocalDate localDate1 = LocalDate.parse("20180101", format); // 根据年月日获取时间 LocalDate localDate2 = LocalDate.of(2018, 9, 1); // 根据年月日获取时间的第二种方式 LocalDate localDate3 = LocalDate.of(2018, Month.FEBRUARY, 1); // 根据从19700101开始的往后指定天数的时间 LocalDate localDate4 = LocalDate.ofEpochDay(108); // 根据年及从年初开始的天数获取时间 LocalDate localDate5 = LocalDate.ofYearDay(2018, 1);
-
获取从1970年以来的天数:toEpochDay
LocalDate localDate = LocalDate.now(); System.out.println(localDate.toEpochDay());
-
计算两个日期之间间隔的天数:
LocalDate localDate = LocalDate.now(); LocalDate startDate = LocalDate.parse("2017-12-01", format); System.out.println(localDate.toEpochDay() - startDate.toEpochDay());
-
日期格式化及字符串转换成日期:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); LocalDate localDate = LocalDate.parse("2018-12-01", formatter); System.out.println(localDate.format(formatter))
其中,与SimpleDateFormat不一样的是,DateTimeFormatter是线程安全的。
-
计算两个日期间单个字段(年、月、日)的差值:
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyyMMdd"); LocalDate localDate = LocalDate.parse("20181101", format); LocalDate startDate = LocalDate.parse("20161201", format); Period period = startDate.until(localDate); // 计算两个日期月字段的减值,注意结果只是两个日期月字段值相关,如以下结果是11 System.out.println("相差月数:" + period.getMonths()); // 计算两个日期间年字段的差值, 如以下结果是1 System.out.println("相差年数:" + period.getYears()); // 计算两个日期间天数字段的差值,只计算天字段相减值,如以下结果是0 System.out.println("相差天数:" + period.getDays());
-
判断日期的先后,isAfter/isBefore
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyyMMdd"); LocalDate localDate = LocalDate.parse("20181101", format); LocalDate startDate = LocalDate.parse("20161201", format); System.out.println(localDate.isAfter(startDate)); System.out.println(localDate.isBefore(startDate));
-
获取年、月、日、周等字段
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyyMMdd"); LocalDate localDate = LocalDate.parse("20180101", format); // 获取年份 System.out.println(localDate.getYear()); // 获取月份,注意是从0开始 System.out.println(localDate.getMonthValue()); // 获取指定日期是所在周的第几天 System.out.println(localDate.getDayOfWeek().getValue()); // 获取指定日期是所在月的第几天, 从1开始 System.out.println(localDate.getDayOfMonth()); // 获取指定日期是所在年的第几天,从1开始 System.out.println(localDate.getDayOfYear()); // 获取其它信息,如所在季度的第几天、当年的第几周等 System.out.println(localDate.get(IsoFields.DAY_OF_QUARTER)); System.out.println(localDate.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR));
-
判断是否是闰年
System.out.println(localDate.isLeapYear());
-
获取指定日期当月的天数
// 获取指定日期当月的天数 System.out.println(localDate.lengthOfMonth());
-
获取指定日期当年的天数
// 获取指定日期当年的天数 System.out.println(localDate.lengthOfYear());
-
日期值调整
-
根据Adjuster进行调整:
// with直接传入LocalDate对象,返回的将是传入的对象 System.out.println(localDate.with(LocalDate.now())); // with传入的不是LocalDate,则返回的是adjuster生成的对象 System.out.println(localDate.with(a -> a));
-
设置日期对象中某个字段(如年、月、日)的值
// 修改日期年、月、日 System.out.println(localDate.with(ChronoField.YEAR, 2010)); System.out.println(localDate.with(ChronoField.MONTH_OF_YEAR, Month.FEBRUARY.getValue())); System.out.println(localDate.with(ChronoField.MONTH_OF_YEAR, 1)); System.out.println(localDate.with(ChronoField.DAY_OF_MONTH, 2)); // 修改日期对象为从1970开始经过指定天数的那一天 System.out.println(localDate.with(ChronoField.EPOCH_DAY, 100)); // 另外的修改年月日的方法 System.out.println(localDate.withYear(2018)); System.out.println(localDate.withMonth(12)); System.out.println(localDate.withDayOfMonth(2)); System.out.println(localDate.withDayOfYear(100));
-
在某个日期上增加指定时间(返回新的对象,原对象不做修改)
// 在某个日期上相加一个间隔,如相加指定天、指定月、指定年等 Period period = Period.ofDays(10); localDate = localDate.plus(period); // 增加2个月 period = Period.ofMonths(2); localDate = localDate.plus(period); // 增加2年 period = Period.ofYears(2); localDate = localDate.plus(period); // 增加两个星期 period = Period.ofWeeks(2); localDate = localDate.plus(period); // 增加指定年、月、日 period = Period.of(1, 2, 3); localDate = localDate.plus(period); // 也可以通过以下方式进行 localDate.plus(1, ChronoUnit.DAYS); // 或者简化的以下方式: localDate = localDate.plusDays(10); localDate = localDate.plusYears(1); localDate = localDate.plusMonths(2);
-
在一个时间上减去指定时间,使用minus,与plus使用方式类似;
-
-
其它
-
定义了一个Month的枚举对象;包含有12个月的枚举值;因此,如果要判断某一日期是不是某一月份,可以这样处理:
LocalDate localDate = LocalDate.parse("20181101", format); System.out.println(localDate.getMonth().equals(Month.JANUARY)); // 也可以直接通过getMonthValue获取月份 System.out.println(localDate.getMonthValue());
-
DayOfWeek枚举值,用于表示星期几的枚举值
-
ChronoField枚举值,用于表示各个字段,如年、月、日或者一年当中天的字段等;主要使用在需要在某个日期中获取某个字段值或者修改某个字段值的场景下,如获取指定日期是当年的第多少天等。
-
atTime函数,用于在LocalDate上增加时间信息,返回的是LocalDateTime字段
-