最近在项目中需要频繁对日期和时间进行处理,综合考虑后,在处理过程中选择了使用Java8的新日期和时间api,为了在以后的开发中可以快速使用,更为了能够为广大掘友提供方便,现在做了一个整理,
本文总共分为两个部分,第一部分介绍Java8日期和时间的主要api,第二部分为各主要api的使用场景示例;
Java8主要日期和时间api介绍
1,LocalDate
LocalDate抽象了本地日期的表示,因为是不可变对象所以是线程安全的,其覆写了toString() 方法,返回日期格式为 yyyy-MM-dd;
2,LocalDateTime
LocalDateTime抽象了本地日期和时间的表示, 实际上是 LocalDate 和 LocalTime的组合,线程安全,返回时间包含毫秒值,格式示例:2020-05-24T13:04:30.197;
3,LocalTime
LocalTime抽象了本地时间(不包含日期)的表示,线程安全,格式示例:13:07:32.659;
4,Instant
Instant抽象了时间戳的表示,表示当前时间戳时,包含日期和时间(基于utc时间),格式示例:2020-05-24T05:14:44.899Z;
5,ZonedDateTime
一个包含时区的完整的日期时间,偏移量是以UTC为基准;格式示例:2020-05-25T17:16:18.475+08:00[Asia/Shanghai];
6,ZoneOffset
表示与UTC时区偏移的固定区域,不跟踪由夏令时导致的区域偏移的更改;
使用场景示例
例1,获取当天的日期
LocalDate now = LocalDate.now();
// 执行结果:2020-05-25
例2,根据具体年/月/日的值获取 LocalDate
// 根据年/月/日的值获取 LocalDate
LocalDate.of(2018, 11, 30);
// 根据某年的第n天获取 LocalDate
LocalDate.ofYearDay(2018, 300);
例3,根据今天的日期获取对应于本年度的日期信息
LocalDate now = LocalDate.now();
now.getYear(); // 今天对应的年份
now.getMonthValue(); // 月份(数值表示, 从1开始)
now.getMonth(); // 月份(英文[enum]表示)
now.getDayOfMonth(); // 日期(从1开始)
now.getDayOfYear(); // 当天所在这一年的第几天(从1开始)
now.getDayOfWeek(); // 星期几
now.lengthOfYear(); // 当年的天数
now.lengthOfMonth(); //当月的天数
now.toEpochDay(); // 与时间纪元(1970年1月1日)相差的天数,负数表示在时间纪元之前多少天
now.isLeapYear();// 今年是否是闰年
例4,基于今天的日期进行的日期/周别/月份/年份计算
System.out.println("加法运算");
System.out.println("当前:" + LocalDate.now());
System.out.println("加1天:" + LocalDate.now().plusDays(1));
System.out.println("加1周:" + LocalDate.now().plusWeeks(1));
System.out.println("加1月:" + LocalDate.now().plusMonths(1));
System.out.println("加1年:" + LocalDate.now().plusYears(1));
System.out.println("减法运算");
System.out.println("当前:" + LocalDate.now());
System.out.println("减1天:" + LocalDate.now().minusDays(1));
System.out.println("减1周:" + LocalDate.now().minusWeeks(1));
System.out.println("减1月:" + LocalDate.now().minusMonths(1));
System.out.println("减1年:" + LocalDate.now().minusYears(1));
例5,基于LocalDate的两个日期比较
System.out.println("当天:" + LocalDate.now());
System.out.println("是否在当天之前:" + LocalDate.now().minusDays(1).isBefore(LocalDate.now()));
System.out.println("是否在当天之后:" + LocalDate.now().plusDays(1).isAfter(LocalDate.now()));
System.out.println("是否在当天:" + LocalDate.now().isEqual(LocalDate.now()));
例6,LocalDate转换为LocalDateTime
// 传入时间,h(小时)必须在0~23之内,m(分钟)必须在0~59之内,s(秒)必须在0~59内
LocalDate now = LocalDate.now();
System.out.println(now.atTime(10,11));// 2020-05-25T10:11
System.out.println(now.atTime(10,11,11)); // 2020-05-25T10:11:11
System.out.println(now.atTime(10,11,12,100000000));// 2020-05-25T10:11:12.100
例7,如何检查重复事件,比如生日/每月还款日
LocalDate dateOfBirth = LocalDate.of(2021, 01, 14);
MonthDay birthday = MonthDay.of(dateOfBirth.getMonth(), dateOfBirth.getDayOfMonth());
MonthDay currentMonthDay = MonthDay.from(LocalDate.now());
if(currentMonthDay.equals(birthday)){
System.out.println("Many Many happy returns of the day !!");
}else{
System.out.println("Sorry, today is not your birthday");
}
例8,如何获取当前时间
System.out.println(LocalDateTime.now()); // 带日期
System.out.println(LocalTime.now()); // 不带日期
例9,基于当前时间的计算(如获取昨天/明天/一周后对应现在的时间)
LocalDateTime now = LocalDateTime.now();
System.out.println(now.plusSeconds(1));// 1s后
System.out.println(now.plusMinutes(1));// 1min后
System.out.println(now.plusHours(1));// 1h后
System.out.println(now.plusDays(1));// 1天后
System.out.println(now.plusWeeks(1));// 1周后
System.out.println(now.plusMonths(1));// 1月后
System.out.println(now.plusYears(1));// 1年后
// 过去时间的计算(减法)
System.out.println(now.minusSeconds(1));// 1s前
// ... 参照类似的加法运算
例10,根据当前时间(LocalDateTime)计算的零点时间和最后时间
// 当天零点
System.out.println(LocalDateTime.of(LocalDate.now(), LocalTime.MIN));
// 当天的最后时间
System.out.println(LocalDateTime.of(LocalDate.now(), LocalTime.MAX));
// 获取本周一零点时间
System.out.println(LocalDateTime.of(LocalDate.now().with(DayOfWeek.MONDAY), LocalTime.MIN));
// 获取上周一的零点时间
System.out.println(LocalDateTime.of(LocalDate.now().with(DayOfWeek.MONDAY).minusWeeks(1),LocalTime.MIN));
// 获取本月的第一天零点时间
System.out.println(LocalDate.of(LocalDate.now().getYear(), LocalDate.now().getMonth(), 1));
// 获取上月的最后一天的最后时间
System.out.println(LocalDateTime.of(LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()).minusMonths(1), LocalTime.MAX));
例11,使用Clock进行操作
Clock clock = Clock.systemUTC();
System.out.println(clock.instant());// 获取一个基于utc时间的Instant时刻值
System.out.println(clock.millis());// 获取当前基于utc时间的毫秒值
Clock c1 = Clock.tick(clockDuration.ofSeconds(5));//获得一个嘀嗒间隔5秒的tick Clock时钟
例12,处理不同的时区的时间转换
将本地时间转换成另一个时区中的对应时间
ZoneId america = ZoneId.of("America/New_York");// 纽约时间
LocalDateTime localDateTime = LocalDateTime.now();
ZonedDateTime dateAndTimeInNewYork = ZonedDateTime.of(localDateTime, america );
System.out.println("date and time in a particular timezone : " + dateAndTimeInNewYork);
例13,表示固定的日期,如信用卡过期时间
YearMonth可以非常方便的获取对指定年月的日期操作,如获取某年的2月的天数,可以非常快速的判断是否是闰月,具体示例如下:
YearMonth currentYearMonth = YearMonth.now();
// 获取当前YearMonth示例以及当前月的天数
System.out.printf("Days in month year %s: %d%n", currentYearMonth, currentYearMonth.lengthOfMonth());
// 获取2108年2月的YearMonth
YearMonth creditCardExpiry = YearMonth.of(2018, Month.FEBRUARY);
// 获取2108年2月的最后一天
System.out.println(creditCardExpiry.atEndOfMonth());
// 获取2108年2月的的第2天
System.out.println(creditCardExpiry.atDay(2));
例14,检查闰年
LocalDate today = LocalDate.now();
if(today.isLeapYear()){
System.out.println("This year is Leap year");
}else {
System.out.println("2018 is not a Leap year");
}
例15,两个日期之间包含多少月/多少天
可通过java.time.Period类来完成这个功能,如下示例:
LocalDate today = LocalDate.now();
LocalDate everDay = LocalDate.of(2016, Month.MARCH, 14);
Period period = Period.between(everDay, today);
// 现在的日期对应之前的日期相差的年数/月数/天数
System.out.printf("year span is:%s; month span is:%s;date span is:%s",period.getYears(),period.getMonths(),period.getDays());
注意:Period其实只能计算同月的天数、同年的月数,不能计算跨月的天数以及跨年的月数。可使用下面demo验证:
DateTimeFormatter formatter=DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate date1 = LocalDate.parse("2020-05-12", formatter);
LocalDate date2 = LocalDate.parse("2021-05-13",formatter);
// 计算日期间隔
int period = Period.between(date1,date2).getDays();
System.out.println(period); // 结果是1!
例16,获取当前时间戳
Instant timeStamp = Instant.now();
System.out.printf("current timeStamp is:%s",timeStamp);
例17,时间戳(Instant) 与java.util.Date间转换
Date date = Date.from(Instant.now());
Instant instant = date.toInstant();
例18,使用格式化器来对日期进行解析/格式化
java8之前,对日期进行格式化需要使用SimpleDateFormat类,然而此类是线程非安全的,在使用时需要进行线程安全控制,使用起来比较麻烦,java8中通过DateTimeFormatter格式化器可以方便的对日期和时间进行格式化和解析而又无需担心线程安全问题,它可以使用预定义的格式也可以自定义格式进行格式化 ,见如下使用示例
// 基本iso日期
String date = "20140116";
DateTimeFormatter dateFormatter = DateTimeFormatter.BASIC_ISO_DATE;
System.out.println(LocalDate.parse(date,dateFormatter));
// 带时区的iso日期和时间
String dateTime = "2011-12-03T10:15:30";
DateTimeFormatter isoDateTime = DateTimeFormatter.ISO_DATE_TIME;
System.out.println(LocalDateTime.parse(dateTime, isoDateTime));
String dateTime = "2018-12-03 10:15:30";
// 使用自定义格式化器解析日期字符串
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dHH:mm:ss");
System.out.println(LocalDateTime.parse(dateTime, timeFormatter));
// 使用自定义格式化器格式化日期时间
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dHH:mm:ss");
String dateTime = now.format(timeFormatter);