Java8日期/时间使用

一、名词

  • 时间戳(时刻):时间戳是指格林尼治时间1970年01月01日00时00分00秒到现在的总秒数(毫秒数),可以理解成绝对时间,它与时区无关,不同时区对同一时间戳的解读不一样
  • 时区:同一时刻(时间戳),世界上各地区的时间可能是不一样的,具体时间与时区相关,按经度一共分为24个时区,英国格林尼治是0时区,中国北京是东8区

二、Java8时间

  • 2.1 Java8时间

Java1.0版本时,对时间的支持仅有java.util.Date类,它表示从1970-01-01 00:00:00开始精确到毫秒的时间点。到Java1.1时,表示日期的java.util.Calendar类被添加进来,但Calendar类也存在很多问题,比如:Date、Calendar类都是可变的,但像时间、日期这样的类应该是不变的;Date中月份是从0开始的;格式化只对Date生效,对Calendar不生效。2001年左右,Joda-Time项目开始致力于提供一个高质量的时间和日期的类库,因为其易用性很快得到了广泛使用。Java8借鉴了大量Joda-Time特性,推出了新的时间工具包

Java8时间相关类在java.time包路径下,表示时间的主要类如下:

类名 描述
Instant 时间戳(时刻)
LocalDate 与时区无关的日期
LocalTime 与时区无关的时间
LocalDateTime 与时区无关的日期和时间
ZonedDateTime 与时区相关的日期和时间
ZoneId 时区
ZoneOffset 相对于格林尼治时间的时间偏差,比如:+08:00

时间输出格式类型:

输出类型 描述
2019-06-10T03:48:20.847Z 世界标准时间,T:日期和时间分隔,Z:世界标准时间
2019-06-10T11:51:48.872 不含时区信息的时间
2019-06-10T11:55:04.421+08:00[Asia/Shanghai] 包含时区信息的时间,+08:00表示相对于0时区加8小时,[Asia/Shanghai]:时区

2.2 Java8时间使用

  • 构造时间对象

构造Instant:

    public static void main(String ... args) {
        // 获取当前时间戳
        Instant instant = Instant.now();
        System.out.println(instant);
        // 指定系统时间戳
        Instant instant1 = Instant.ofEpochMilli(System.currentTimeMillis());
        System.out.println(instant1);
        // 解析指定时间戳
        Instant instant2 = Instant.parse("2019-06-10T03:42:39Z");
        System.out.println(instant2);
    }
--- 
2019-06-10T03:48:20.847Z
2019-06-10T03:48:20.941Z
2019-06-10T03:42:39Z

构造LocalDateTime:

    public static void main(String ... args) {
        // 获取当前时间
        LocalDateTime localDateTime = LocalDateTime.now();
        System.out.println(localDateTime);
		// 指定时间
        LocalDateTime localDateTime1 = LocalDateTime.of(2019, 06, 10, 10, 30,30);
        System.out.println(localDateTime1);
		// 解析时间
        LocalDateTime localDateTime2 = LocalDateTime.parse("2019-06-10 11:55:04", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        System.out.println(localDateTime2);
    }
---
2019-06-10T11:59:58.765
2019-06-10T10:30:30
2019-06-10T11:55:04

构造ZonedDateTime:

    public static void main(String ... args) {
		// 获取当前时区当前时间
        ZonedDateTime zonedDateTime = ZonedDateTime.now();
        System.out.println(zonedDateTime);
		// 指定时间及时区
        ZonedDateTime zonedDateTime1 = ZonedDateTime.of(2019, 06, 10, 10, 30,30, 00,  ZoneId.of("UTC"));
        System.out.println(zonedDateTime1);
		// 解析指定时间
        ZonedDateTime zonedDateTime2 = ZonedDateTime.parse("2019-06-10T12:03:19.367+08:00[Asia/Shanghai]", DateTimeFormatter.ISO_ZONED_DATE_TIME);
        System.out.println(zonedDateTime2);
    }
---
2019-06-10T12:08:44.405+08:00[Asia/Shanghai]
2019-06-10T10:30:30Z[UTC]
2019-06-10T12:03:19.367+08:00[Asia/Shanghai]
  • 时间对象转换
    public static void main(String ... args) {
        Instant instant = Instant.now();
        // 时间戳转LocalDateTime
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        System.out.println(localDateTime);
        // 时间戳转时区时间
        ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(instant, ZoneId.of("Asia/Shanghai"));
        System.out.println(zonedDateTime);
        // LocalDateTime转时间戳,因为LocalDateTime不带时区信息,因此需要指定当前时区到UTC的offset
        Instant instant1 = localDateTime.toInstant(ZoneOffset.ofHours(8));  // ZoneOffset.of("+08:00"), ZoneOffset.UTC
        System.out.println(instant1);
        // 时区时间转时间戳,ZonedDateTime自带时区信息
        Instant instant2 = zonedDateTime.toInstant();
        System.out.println(instant2);
        // LocalDateTime转时区时间(为时间加上时区信息)
        ZonedDateTime zonedDateTime1 = ZonedDateTime.of(localDateTime, ZoneId.of("Asia/Tokyo"));
        System.out.println(zonedDateTime1);
        // 时区时间转换为LocalDateTime,将时区时间的时区信息去除
        LocalDateTime localDateTime1 = zonedDateTime.toLocalDateTime();
        System.out.println(localDateTime1);
    }
---
2019-06-10T14:02:50.483
2019-06-10T14:02:50.483+08:00[Asia/Shanghai]
2019-06-10T06:02:50.483Z
2019-06-10T06:02:50.483Z
2019-06-10T14:02:50.483+09:00[Asia/Tokyo]
2019-06-10T14:02:50.483
  • LocalDateTime与Date转换

Instant和Date是新老时间转换的桥梁,二者都是时间戳的表现形式,但Date在打印时会转换成当前时区时间(可通过设置TimeZone调整),Instant打印时默认是0时区时间

    public static void main(String ... args) {
        Date date = Date.from(Instant.now());
        System.out.println(date);
        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
        System.out.println(date);
        Instant instant = date.toInstant();
        System.out.println(instant);
    }
---
Mon Jun 10 14:09:27 CST 2019
Mon Jun 10 06:09:27 UTC 2019
2019-06-10T06:09:27.307Z
  • 时区转换
    public static void main(String ... args) {
        // 初始化北京时间
        ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(Instant.now(), ZoneId.of("Asia/Shanghai"));
        System.out.println(zonedDateTime);
        // 北京时间转换为UTC时间
        ZonedDateTime utcZonedDateTime = zonedDateTime.toInstant().atZone(ZoneId.of("UTC"));
        System.out.println(utcZonedDateTime);
        // 初始化东京时间
        ZonedDateTime tokyoDateTime = ZonedDateTime.of(2019, 06, 10, 11, 20, 20, 00, ZoneId.of("Asia/Tokyo"));
        System.out.println(tokyoDateTime);
        // 东京时间转换为芝加哥时间
        ZonedDateTime chicagoDateTime = tokyoDateTime.toInstant().atZone(ZoneId.of("America/Chicago"));
        System.out.println(chicagoDateTime);
    }
---
2019-06-10T14:19:19.053+08:00[Asia/Shanghai]
2019-06-10T06:19:19.053Z[UTC]
2019-06-10T11:20:20+09:00[Asia/Tokyo]
2019-06-09T21:20:20-05:00[America/Chicago]
  • 时间调整(TemporalAdjuster)
    public static void main(String ... args) {
        LocalDateTime localDateTime = LocalDateTime.now();
        // 本年本月最后一天
        System.out.println(localDateTime.with(TemporalAdjusters.lastDayOfMonth()));
        // 本年本月第一天
        System.out.println(localDateTime.with(TemporalAdjusters.firstDayOfMonth()));
        // 本年下一月第一天
        System.out.println(localDateTime.with(TemporalAdjusters.firstDayOfNextMonth()));
        // 下一年第一天
        System.out.println(localDateTime.with(TemporalAdjusters.firstDayOfNextYear()));
        // 本年最后一天
        System.out.println(localDateTime.with(TemporalAdjusters.lastDayOfYear()));
        // 下一个周五
        System.out.println(localDateTime.with(TemporalAdjusters.next(DayOfWeek.FRIDAY)));
        // 本月第一个周五
        System.out.println(localDateTime.with(TemporalAdjusters.firstInMonth(DayOfWeek.FRIDAY)));
        // 本月最后一个周五
        System.out.println(localDateTime.with(TemporalAdjusters.lastInMonth(DayOfWeek.FRIDAY)));
        // 下一个周五,如果当前是周五则返回当前时间
        System.out.println(localDateTime.with(TemporalAdjusters.nextOrSame(DayOfWeek.FRIDAY)));
        // 前一个周五
        System.out.println(localDateTime.with(TemporalAdjusters.previous(DayOfWeek.FRIDAY)));
        // 前一个周五,如果当前是周五则返回当前时间
        System.out.println(localDateTime.with(TemporalAdjusters.previousOrSame(DayOfWeek.FRIDAY)));
    }
---
2019-06-30T14:29:50.960
2019-06-01T14:29:50.960
2019-07-01T14:29:50.960
2020-01-01T14:29:50.960
2019-12-31T14:29:50.960
2019-06-14T14:29:50.960
2019-06-07T14:29:50.960
2019-06-28T14:29:50.960
2019-06-14T14:29:50.960
2019-06-07T14:29:50.960
2019-06-07T14:29:50.960
  • 计算日期时间差异
    public static void main(String ... args) {
       // 通过Period计算年龄
       LocalDate birthDay = LocalDate.of(1992, 02, 25);
       LocalDate localDate = LocalDate.now();
       Period period = Period.between(birthDay, localDate);
       System.out.printf("%d 岁 %d 月 %d 天 %n", period.getYears(), period.getMonths(), period.getDays());
       // 计算时间差值
       Instant instant = Instant.now();
       Instant instant1 = instant.plus(Duration.ofMinutes(2));
       Duration duration = Duration.between(instant, instant1);
       System.out.println(duration.getSeconds());
       System.out.println(duration.toMillis());
       // 按某一单位维度计算差值
       LocalDateTime localDateTime = LocalDateTime.of(2019, 05, 20, 10, 10, 10);
       LocalDateTime localDateTime1 = LocalDateTime.now();
       Long dayDiff = ChronoUnit.DAYS.between(birthDay, localDate);
       System.out.println(dayDiff);
       Long miniteDiff = ChronoUnit.MINUTES.between(localDateTime, localDateTime1);
       System.out.println(miniteDiff);
   }
---
27 岁 3 月 16 天 
120
120000
9967
30553
  • 时间打印
    public static void main(String ... args) {
        LocalDateTime localDateTime = LocalDateTime.of(2019, 06,10, 10, 10, 10);
        System.out.println(localDateTime.format(DateTimeFormatter.BASIC_ISO_DATE));
        System.out.println(localDateTime.format(DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss")));
        LocalDateTime localDateTime1 = LocalDateTime.parse("20190610 00:00:00", DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss"));
        System.out.println(localDateTime1);
    }
---
20190610
20190610 10:10:10
2019-06-10T00:00
  • 判断是否闰年
    public static void main(String ... args) {
        LocalDate localDate = LocalDate.now();
        System.out.println(localDate.isLeapYear());
    }
---
false
  • 判断前后
    public static void main(String ... args) {
        LocalDateTime localDateTime = LocalDateTime.now();
        LocalDateTime localDateTime1 = LocalDateTime.of(2019, 05, 20, 10, 10, 10);
        System.out.println(localDateTime.isAfter(localDateTime1));
        System.out.println(localDateTime.isBefore(localDateTime1));
    }
---
true
false

参考

上一篇:Spring Boot中使用@RequestBody对json解析时,LocalDateTime反序列化失败


下一篇:JDK1.8 LocalDate 使用方式;LocalDate 封装Util,LocalDate工具类