java8日期时间API讲解

Posted by 梧桐和风的博客 on May 6, 2018

java日期时间API总结

Date

java中常见的表示时间的类。内部使用long类型的值表示自1970-01-01起的毫秒数。本质上是一个表示瞬时时间的类,表示级别为毫秒。且其为可变对象,即线程不安全的。目前大多数方法已废弃。可用且常见的方法如下:

方法 含义
new Date() 创建一个表示当前时间的对象
new Date(long time) 传入一个表示自1970年1月1日起的毫秒数,基于此时间创建对象
from(Instant instant) 以Instant类的对象构建对象,java8新增
toInstant() 将Date对象转为Instant对象,java8新增

Instant

java8新增类,专门用于表示时间戳。想获取当前时间的时间戳可用Instant.now()获取。

关于Instant比较常用的是与Date的相互转化及比较两时间戳的差值。如下:

        //获取当前时间戳
        Instant now = Instant.now();
        System.out.println(now);

        Thread.sleep(1000);

        // Date转Instant
        Date today = new Date();
        Instant cur = today.toInstant();

        // 计算两Instant示例差值
        long diff = Duration.between(now, cur).toMillis();
        System.out.println(diff);

        // Instant 转Date
        Date date = Date.from(now);
        System.out.println(date);


LocalDate

java8新增的表示日期的类。默认格式为yyyy-MM-dd,表示具体某一天。可由now()获取当前日期,也可传入年月日构造。类中有格式化方法。

常用方法如下:

方法 静态方法 含义
now() 获取当天日期
of(year,month,days) 根据传入的值构造日期
parse(dateStr) 解析日期字符串(需为yyyy-MM-dd格式)为日期格式
format 格式化日期为字符串
isLeapYear() 是否为闰年
lengthOfMonth() 该月长度
getDayOfWeek() 表示是周几,返回枚举类
plusXXX XXX可为年、月或日,表示添加一段时间,返回新日期
minusXXX 同plusXXX类似,在实例基础上减去某个值,返回新日期
equal() 比较两日期是否相等

总的来说,LocalDate表示代表本地时间的日期,API为我们提供了构造、解析、格式化及计算等方法,使得日期表示更简便。


  LocalDate now = LocalDate.now();
  //输出:2018-04-22 ,表示其默认格式为yyyy-MM-dd
  System.out.println(now);

  LocalDate lastDay = LocalDate.of(2018, 4, 21);
  //输出:2018-04-21
  System.out.println(lastDay);

  // 输出:false,不是闰年
  System.out.println(now.isLeapYear());
  
  // 输出 2018-04-21,格式化字符串
  System.out.println(now.format(DateTimeFormatter.ISO_LOCAL_DATE));

  // 注意,会报错,LocalDate类只有日期没有时间信息,不能格式化
  // System.out.println(now.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));

  // 获取某天的年月日信息
  System.out.println(now.getYear());
  System.out.println(now.getMonthValue());
  System.out.println(now.getDayOfMonth());

  // 比较两日期是否相等
  System.out.println(now.equals(lastDay));
  
   // 日期加减
   // 明天
   LocalDate tomorrow = now.plusDays(1);
   System.out.println(tomorrow);
   // 一周前
   LocalDate monthDay = now.minusWeeks(1);
   System.out.println(monthDay);
   // 一年后
   LocalDate afterDay = now.plus(1, ChronoUnit.YEARS);
   System.out.println(afterDay);


LocalTime与LocalDateTime

LocalTime、LocalDateTime与LocalDate类似,LocalTime表示本地时间,LocalDateTime表示本地日期时间。用法也与LocalDate类似。下面简单介绍下。

LocalTime

       //获取当前时间
        LocalTime curTime = LocalTime.now();
        // 输出:10:52:12.108
        System.out.println(curTime);

        // 构造时间
        LocalTime localTime = LocalTime.of(14, 34, 12);
        // 输出:14:34:12
        System.out.println(localTime);

        // 时间加减,1小时后
        LocalTime nextHour = curTime.plus(1, ChronoUnit.HOURS);
        //  11:52:12.108
        System.out.println(nextHour);

        // 两时间差值
        long minuteDiff = Duration.between(curTime, localTime).toMinutes();
        // 输出:221
        System.out.println(minuteDiff);

LocalDateTime

用来表示日期及时间,包含LocalDate与LocalTime的信息,比较常用。方法与前两者类似。

       // 获取当前日期时间
        LocalDateTime now = LocalDateTime.now();
        // 输出:2018-05-05T10:58:17.119
        System.out.println(now);
        // 2018
        System.out.println(now.getYear());
        //5
        System.out.println(now.getMonthValue());
        //5
        System.out.println(now.getDayOfMonth());
        // 10
        System.out.println(now.getHour());
        //58
        System.out.println(now.getMinute());

日期格式化

java8的日期格式化再也不用SimpleDateFormat类做复杂的日期转化了,格式化的函数都包含在各自的日期时间类中。以LocalDateTime为例:


    @Test
    public void formatDate() {
        LocalDateTime now = LocalDateTime.now();

        // 默认输出:2018-05-05T11:11:59.221
        System.out.println(now);
        // iso日期时间格式,输出:2018-05-05T11:11:59.221
        System.out.println(now.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
        // iso 日期格式,输出:2018-05-05
        System.out.println(now.format(DateTimeFormatter.ISO_LOCAL_DATE));
        // 自定义格式:2018/05/05 11:11:59
        System.out.println(now.format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss")));
        
         // 字符串转日期,默认字符串格式需为ISO_LOCAL_DATE_TIME风格
        LocalDateTime localDateTime = LocalDateTime.parse("2018-05-01T11:00:00");
        System.out.println(localDateTime);

        // 字符串转日期,字符串格式需与模式相匹配
        LocalDateTime localDateTime1 = LocalDateTime.parse("2018/05/05 12:00", DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm"));
        System.out.println(localDateTime1);
        
    }
    

时间差值

java8可以计算时间差值的类有:PeriodDuration以及ChronoUnit。其中ChronoUnit计算时间差值主要也是用到了Duration。而Period主要是针对日期的间隔计算,而Duration主要是针对时间的。看一下示例:

Period

Period表示以日期为单位的时间段,即其最小单位也要是day。常用于计算两LocalDate之间的差值


       // 计算距22年冬奥会还有多久
        LocalDate now = LocalDate.now();
        // 输出:当前日期:2018年05月06日
        System.out.println("当前日期:" + now.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
        LocalDate olympicDay = LocalDate.of(2022, 2, 4);
        Period period = Period.between(now, olympicDay);
        // 输出:距冬奥会还有:3年8月29天
        System.out.println("距冬奥会还有:" + period.getYears() + "年" + period.getMonths() + "月" + period.getDays() + "天");

Duration

相比Period,Duration用于表示两个时间的时间差值,而不仅仅是日期。如可以表示两时间点差值,日期差值。

需注意的是,Duration内部表示时间差是用两个long类型的值:秒(second)及纳秒(nanos)表示的,若用于计算两日期相差天数等问题,通常是将秒换算成天得到的。这样也表明,两时间值至少需要精确到秒,否则不能完成转化,即LocalDate是不能用Duration


        // 计算两个LocalTime相差的毫秒数
        LocalTime start = LocalTime.now();
        TimeUnit.SECONDS.sleep(1);
        Duration duration = Duration.between(start, LocalTime.now());
        // 输出:1004
        System.out.println("1秒后相差毫秒数:" + duration.toMillis());


        // 距冬奥会天数,不能使用LocalDate,因其没有时分秒等单位
        LocalDateTime curTime = LocalDateTime.now();
        LocalDateTime nextTime = LocalDateTime.of(2022, 2, 4, 0, 0);
        System.out.println("距冬奥会相差:" + Duration.between(curTime, nextTime).toDays() + "天");


ChronoUnit

上面说Duration不能用在LocalDate上,而我需要计算两日期相差天数,就不能直接计算得到吗。事实上当然可以了,可以使用ChronoUnit


       //输出: 距冬奥会相差:1370天
       System.out.println("距冬奥会相差:" + Duration.between(curTime, nextTime).toDays() + "天");

不仅如此,ChronoUnit类可用于计算上述所提到的各种时间差。计算模式也很固定

ChronoUnit.计量单位.between(start,end)



       // 1秒钟后
        long diffOneMinute = ChronoUnit.MILLIS.between(start, LocalTime.now());
        System.out.println("1秒钟后" + diffOneMinute);
        
        

新旧时间转化

Date与Instant

Date与Instant都可表示瞬时时间,转化方式上面也有所提及,即:


        // Date转Instant
        Date today = new Date();
        Instant cur = today.toInstant();
        
        // Instant 转Date
        Date date = Date.from(now);
       

Data与LocalDate



        // Date转LocalDateTime、LocalDate
        LocalDateTime now = LocalDateTime.ofInstant(new Date().toInstant(), ZoneId.systemDefault());
        // 输出:2018-05-06T18:29:52.184
        System.out.println(now);
        LocalDate today = now.toLocalDate();
        //输出:2018-05-06
        System.out.println(today);
        
        // LocalDateTime 转Date
        Date date = Date.from(now.atZone(ZoneId.systemDefault()).toInstant());

        // LocalDate 转Date
        Date date1 = Date.from(today.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());