JDK8新特性(五):JDK8时间日期API

本文目录:

前言

1.旧版日期时间API存在的问题

2.新日期时间 API 介绍

3.用法介绍

 1.JDK8 日期和时间类

 2.JDK8 日期时间格式化与解析

 3.JDK8 Instant 类

 4.JDK8 计算日期时间差类

 5.JDK8 日期时间调整器

 6.JDK8 设置日期时间的时区

附:JDK8新特性(目录)


前言

       在 JDK8 之前,我们经常使用到的时间API包括(Date、Calendar),Date 与字符串之间的转换使用 SimpleDateFormat 进行转换(parse()、format() 方法),然而 SimpleDateFormat 不是线程安全的。在设计上也是存在一些缺陷的,比如有两个 Date 类,一个在 java.util 包中,一个在 java.sql 包中。

      在JDK8 中,引入了一套全新的时间日期API,这套 API 在设计上比较合理,使用时间操作也变得更加方便。并且支持多线程安全操作。

1.旧版日期时间API存在的问题

1.设计很差:在 java.util 和 java.sql 的包中都有日期类。java.util.Date 同时包含日期和时间,而java.sql.Date仅包含日期,此外用于格式化和解析的类又在 java.text 包中定义;

2.非线程安全:java.util.Date 是非线程安全的,所有的日期类都是可变的,这是 java 日期类最大的问题之一;

3.时区处理麻烦:日期类并不提供国际化,没有时区支持。因此 java 引入了 java.util.Calendar 和 java.util.TimeZone 类,但他们同样存在上述所有的问题

/**
 * TODO JDK8之前日期存在的问题
 *
 * @author liuzebiao
 * @Date 2020-1-13 11:28
 */
public class DateDemo01 {

    public static void main(String[] args) {
        //旧版日期时间 API 存在的问题
        //1.设计不合理(JDK8 Date类已经 @Deprecated 注释,不推荐使用)
        Date now =new Date(1985,9,23);
        System.out.println(now);

        //2.时间格式化和解析是线程不安全的
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        for (int i = 0; i < 50; i++) {
            new Thread(()->{
                try {
                    Date date = sdf.parse("2019-09-09");
                    System.out.println("date:"+date);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

 多线程测试结果:(会有日期格式化错误的,还有直接报错的,说明线程是不安全)

date:Tue Jun 09 00:00:00 CST 2026
date:Tue Sep 09 00:00:00 CST 990
date:Tue Sep 09 00:00:00 CST 990
date:Tue Sep 09 00:00:00 CST 990
date:Sun Dec 01 00:00:00 CST 2019
date:Mon Sep 09 00:00:00 CST 2019(这个才是正确的)
date:Mon Sep 09 00:00:00 CST 2019
date:Mon Sep 09 00:00:00 CST 2019
Exception in thread "Thread-35" Exception in thread "Thread-37" java.lang.NumberFormatException: For input string: "1909E.21909"
	at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
	at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
	at java.lang.Double.parseDouble(Double.java:538)

2.新日期时间 API 介绍

      JDK8 中增加了一套全新的日期时间 API,这套 API 设计合理,是线程安全的。新的日期及时间 API 位于 java.time 包下,如下是一些该包下的关键类:

  • LocalDate:表示日期,包含:年月日。格式为:2020-01-13
  • LocalTime:表示时间,包含:时分秒。格式为:16:39:09.307
  • LocalDateTime:表示日期时间,包含:年月日 时分秒。格式为:2020-01-13T16:40:59.138
  • DateTimeFormatter:日期时间格式化类
  • Instant:时间戳类
  • Duration:用于计算 2 个时间(LocalTime,时分秒)之间的差距
  • Period:用于计算 2 个日期(LocalDate,年月日)之间的差距
  • ZonedDateTime:包含时区的时间

       Java 中使用的历法是 ISO-8601 日历系统,他是世界民用历法,也就是我们所说的公里。平年有365天,闰年是366天。此外 Java8 还提供了 4 套其他历法,分别是:

  • ThaiBuddhistDate:泰国佛教历
  • MinguoDate:中华民国历
  • JapaneseDate:日本历
  • HijrahDate:伊斯兰历

3.用法介绍

 1.JDK8 日期和时间类

        LocalDate、LocalTime、LocalDateTime类的实例是不可变的对象,分别表示使用 ISO-8601 日历系统的日期、时间、日期和时间。他们提供了简单的日期或时间,并不包含当前的时间信息,也不包含与时区相关的信息。

        对日期时间的修改,就是对已经存在的 LocalDate对象,根据需求创建它的修改版,最简单的方式是使用 withAttribute() 方法。withAttribute()方法会创建对象的一个副本,并按照需要修改它的属性。

       以下所有方法都返回了一个修改属性的对象,它们并不会影响原来的日期对象。(即:修改后的日期与原来的日期不是一个对象,原日期不受影响

/**
 * TODO 时间日期类
 *      LocalDate、LocalTime、LocalDateTime
 *
 * @author liuzebiao
 * @Date 2020-1-13 13:42
 */
public class DateDemo02 {

    /**
     * LocalDate 日期类(年月日)
     */
    @Test
    public void testLocalDate() {
        //获取当前日期
        LocalDate now = LocalDate.now();
        System.out.println(now);
        //指定日期 LocalDate.of(year,month,day)
        LocalDate date = LocalDate.of(2008, 8, 8);
        System.out.println(date);
        //获取年
        System.out.println("年:" + date.getYear());
        //获取月(英文)
        System.out.println("月(英文):" + date.getMonth());
        //获取月(阿拉伯数字)
        System.out.println("月(数字):" + date.getMonthValue());
        //获取日
        System.out.println("日:" + date.getDayOfMonth());
        //是否是闰年
        System.out.println("是否是闰年:" + date.isLeapYear());
        //...其他方法,自行研究
    }

    /**
     * LocalDate 时间类(时分秒)
     */
    @Test
    public void testLocalTime() {
        //获取当前时间
        LocalTime now = LocalTime.now();
        System.out.println(now);
        //指定日期 LocalTime.of(hour,minute,second)
        LocalTime date = LocalTime.of(13, 26, 39);
        System.out.println(date);
        //获取时
        System.out.println(date.getHour());
        //获取分
        System.out.println(date.getMinute());
        //获取秒
        System.out.println(date.getSecond());
        //获取纳秒
        System.out.println(now.getNano());
        //...其他方法,自行研究

    }

    /**
     * LocalDateTime 日期时间类(年月日 时分秒)
     */
    @Test
    public void testLocalDateTime() {
        //LocalDateTime: LocalDate + LocalTime,有年月日 时分秒
        LocalDateTime now = LocalDateTime.now();
        System.out.println("当前日期时间:"+now);
        //指定日期时间 LocalDateTime.of(year,month,day,hour,minute,second)
        LocalDateTime date = LocalDateTime.of(2018, 7, 23, 18, 59, 31);
        System.out.println(date);
        //获取年
        System.out.println(date.getYear());
        //获取月
        System.out.println(date.getMonth());
        //获取日
        System.out.println(date.getDayOfMonth());
        //获取时
        System.out.println(date.getHour());
        //获取分
        System.out.println(date.getMinute());
        //获取秒
        System.out.println(date.getSecond());
        //...其他方法,自行研究
    }

    /**
     * 修改时间
     */
    @Test
    public void modifyTime() {
        //以LocalDateTime为例(LocalDate、LocalTime与此类似)
        LocalDateTime now = LocalDateTime.now();
        //修改年[修改时间(不是JDK8之前的setXXX(),而是使用withXXX())]
        System.out.println("修改年后:" + now.withYear(9102));
        //增加年(减使用 minusYear()方法)
        System.out.println("+2年后:" + now.plusYears(2));
        //增加日(减使用 minusDays()方法)
        System.out.println("47天后:" + now.plusDays(47));
        //...其他方法,自行研究
    }

    /**
     * 时间比较
     */
    @Test
    public void compareTime() {
        //以LocalDateTime为例(LocalDate、LocalTime与此类似)
        //时间1
        LocalDateTime now = LocalDateTime.now();
        //时间2
        LocalDateTime dateTime = LocalDateTime.of(2018, 7, 12, 13, 28, 51);
        //判断前面日期是否在后面日期后
        System.out.println("A时间是否晚于B时间:" + now.isAfter(dateTime));
        //判断前面日期是否在后面日期前
        System.out.println("A时间是否早于B时间:" + now.isBefore(dateTime));
        //判断两个日期时间是否相等
        System.out.println("两个时间是否相等:" + now.isEqual(dateTime));
        //...其他方法,自行研究
    }
}

 2.JDK8 日期时间格式化与解析

/**
 * TODO 日期时间格式化 + 解析 + 多线程执行(安全)
 *
 * @author liuzebiao
 * @Date 2020-1-13 14:12
 */
public class DateDemo03 {

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

        //格式化
        //使用JDK自带的时间格式:ISO_DATE_TIME(默认提供了很多格式,请自行查看)
        DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE_TIME;
        String format = now.format(dtf);
        System.out.println("format="+format);

        //指定时间格式(ofPattern()方法)
        DateTimeFormatter dtf1 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒");
        String format1 = now.format(dtf1);
        System.out.println(format1);

        //解析(parse()方法)
        LocalDateTime parse = LocalDateTime.parse(format1, dtf1);
        System.out.println("parse="+parse);

        /**
         * 多线程执行(验证线程安全性)
         * 1.返回结果正确   2.不抛异常
         */
        for (int i = 0; i < 50; i++) {
            new Thread(()->{
                LocalDateTime parse1 = LocalDateTime.parse(format1, dtf1);
                System.out.println("parse="+parse1);
            }).start();
        }
    }
}

 3.JDK8 Instant 类

      Instant 类,就是时间戳,内部保存了从1970年1月1日 00:00:00以来的秒和纳秒。

/**
 * TODO JDK8的 Instant类(时间戳)
 * (主要不是面向用户使用)
 *
 * @author liuzebiao
 * @Date 2020-1-13 14:31
 */
public class DateDemo04 {

    @Test
    public void Instant(){
        //Instant 
        // 内部保存了秒和纳秒,一般不是给用户使用的,而是方便程序做一些统计的(比如:统计方法耗时)
        Instant now = Instant.now();
        System.out.println("当前时间戳:"+now);//2020-01-13T06:48:46.267Z
        //Instant类 并没有修改年月日等操作.因为 Instant 本来就不是给用户使用的
        //Instant类:对 秒、纳秒等操作方便
        Instant plus = now.plusSeconds(20);
        System.out.println("+20秒后:"+plus);

        Instant minus = now.minusSeconds(20);
        System.out.println("-20秒后:"+minus);

        //获取秒、毫秒、纳秒
        long second = now.getEpochSecond();
        System.out.println("秒:"+second);
        int nano = now.getNano();
        System.out.println("纳秒:"+nano);
        //...其他方法,自行研究
    }
}

 4.JDK8 计算日期时间差类

     Duration/Period 类:主要用来计算日期时间差

  1. Duration:用于计算 2 个时间(LocalTime,时分秒)的差值
  2. Period:用于计算 2 个 日期(LocalDate,年月日)的差值
/**
 * TODO JDK8 计算日期时间差值
 *
 * @author liuzebiao
 * @Date 2020-1-13 14:55
 */
public class DateDemo05 {

    /**
     * Duration类:计算时间的差值
     */
    @Test
    public void testTimeDiff(){
        //时间1
        LocalTime now = LocalTime.now();
        //时间2
        LocalTime dateTime = LocalTime.of(8, 15, 46);
        //计算两个时间的差值
        //计算规则:让第二个参数 减去 第一个参数(位置错误可能出现负数)
        Duration duration = Duration.between(dateTime,now);
        System.out.println("相差的天数:"+duration.toDays());
        System.out.println("相差的小时数:"+duration.toHours());
        System.out.println("相差的分钟数:"+duration.toMinutes());
        System.out.println("相差的秒数:"+duration.toSeconds());//JDK 9+ 出现(JDK8会报错误)
        System.out.println("相差的纳秒数:"+duration.toNanos());
        //...其他方法,自行研究
    }

    /**
     * Period类:计算日期的差值
     */
    @Test
    public void testDateDiff(){
        //日期1
        LocalDate now = LocalDate.now();
        //日期2
        LocalDate date = LocalDate.of(1999,5,29);
        //计算两个日期的差值
        //计算规则:让第二个参数 减去 第一个参数(位置错误可能出现负数)
        Period period = Period.between(date,now);
        System.out.println("相差的年:"+period.getYears());
        System.out.println("相差的月:"+period.getMonths());
        System.out.println("相差的日:"+period.getDays());
        //...其他方法,自行研究
    }
}

 5.JDK8 日期时间调整器

   有时我们可能需要获取,例如:"将日期调整到下一个月的第一天"等操作,此时我们可以通过时间调整器来进行操作。

  • TemporalAdjuster:时间调整器
  • TemporalAdjusters:工具类。该类通过静态方法提供了大量的常用 TemporalAdjuster 的实现
/**
 * TODO JDK8 时间调整器
 *
 * @author liuzebiao
 * @Date 2020-1-13 15:10
 */
public class DateDemo06 {

    /**
     * TemporalAdjuster类:自定义调整时间
     */
    @Test
    public void timeCorrector(){
        //将日期调整到"下一个月的第一天"操作
        LocalDateTime now = LocalDateTime.now();
        //参数:TemporalAdjuster adjuster。TemporalAdjuster是一个接口,里面只有 Temporal adjustInto(Temporal temporal); 这一个方法,支持接入 lambda 表达式
        //此处 Temporal 就是指时间(包括 LocalDate、LocalTime、LocalDateTime 都是继承自该类。继承关系:如下图所示)
        TemporalAdjuster adjuster = ( Temporal temporal)->{
            LocalDateTime dateTime = (LocalDateTime)temporal;
            return dateTime.plusMonths(1).withDayOfMonth(1);//下一个月第一天
        };
        LocalDateTime newDateTime = now.with(adjuster);
        System.out.println("下个月第一天:"+newDateTime);
    }

    /**
     * TemporalAdjusters工具类:使用JDK提供的时间调整器
     */
    @Test
    public void JDKTimeCorrector(){
        //JDK中自带了很多时间调整器,其他调整器请自行查看
        //使用 TemporalAdjusters 工具类
        //TemporalAdjusters.firstDayOfNextYear()--->根据内容可知:下一年第一天
        TemporalAdjuster temporalAdjuster = TemporalAdjusters.firstDayOfNextYear();

        LocalDateTime now = LocalDateTime.now();
        LocalDateTime newDateTime = now.with(temporalAdjuster);
        System.out.println("下个月第一天:"+newDateTime);
    }
}

 附:继承关系(LocalDate、LocalTime、LocalDateTime、Temporal类)

 6.JDK8 设置日期时间的时区

       JDK8 中加入了对时区的支持。LocalDate、LocalTime、LocalDateTime 是不带时区的,带时区的日期时间类分别为:ZonedDate、ZonedTime、ZonedDateTime类。

       其中每个时区都有对应着的 ID,ID的格式为"区域/城市",例如:Asia/Shanghai 等。

       ZoneId类:该类中包含了所有的时区信息。

/**
 * TODO JDK8设置时区(设置日期时间的时区)
 *
 * @author liuzebiao
 * @Date 2020-1-13 15:43
 */
public class DateDemo07 {

    /**
     * 获取时区ID
     */
    @Test
    public void getZoneIds(){
        //1.获取所有的时区ID
        Set<String> zoneIds = ZoneId.getAvailableZoneIds();
        zoneIds.forEach(System.out::println);//返回600来个时区
    }

    /**
     * 不带时区 Vs 带时区的日期时间
     */
    @Test
    public void ZonedDemo(){
        //2.操作带时区的类
        //不带时间,获取计算机的当前时间
        LocalDateTime now = LocalDateTime.now();
        System.out.println("now:"+now);

        //中国使用的是东八区的时间,比标准时间早8个小时
        //操作带时间的类
        ZonedDateTime zdt = ZonedDateTime.now(Clock.systemUTC());//创建出来的时间是世界标准时间
        System.out.println("世界标准时间:"+zdt);
    }

    /**
     * 本地时间
     */
    @Test
    public void localTime(){
        //now():使用计算机的默认的时区,创建日期时间
        ZonedDateTime now = ZonedDateTime.now();
        System.out.println("本地时间:"+now);//本地时间:2020-01-13T15:52:43.633+08:00[Asia/Shanghai]
    }

    /**
     * 使用指定的时区来创建时间
     */
    @Test
    public void ZoneTime(){

        ZonedDateTime now = ZonedDateTime.now(ZoneId.of("America/New_York"));
        System.out.println("设置指定时间:"+now);//设置指定时间:2020-01-13T02:56:24.776-05:00[America/New_York]
    }

    /**
     * 修改时区
     */
    @Test
    public void modifyZone(){
        ZonedDateTime now = ZonedDateTime.now(ZoneId.of("America/New_York"));

        //withZoneSameInstant():既更改时区,也更改时间
        ZonedDateTime modifyTime = now.withZoneSameInstant(ZoneId.of("Asia/Shanghai"));
        System.out.println("修改时区后的时间:"+modifyTime);

        //withZoneSameLocal():只更改时区,不更改时间
        ZonedDateTime modifyTime2 = now.withZoneSameLocal(ZoneId.of("Asia/Shanghai"));
        System.out.println("修改时区后的时间:"+modifyTime2);
    }
    //...其他方法,自行研究
}

附:JDK8新特性(目录)

       本目录为 JDK8新特性 学习目录,包含JDK8 新增全部特性的介绍。

       如需了解,请跳转链接查看:我是跳转链接


博主写作不易,来个关注呗

求关注、求点赞,加个关注不迷路 ヾ(◍°∇°◍)ノ゙

博主不能保证写的所有知识点都正确,但是能保证纯手敲,错误也请指出,望轻喷 Thanks♪(・ω・)ノ

  • 10
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
JDK 8,也就是 Java Development Kit 8,有许多新的特性。以下是其中一些主要的新特性: 1. **Lambda 表达式和函数式接口**:这是 JDK 8 中最重要的新特性之一。Lambda 表达式允许开发者以更简洁的方式编写代码,通过使用匿名函数来实现。此外,JDK 8 还引入了函数式接口(如 `Supplier`, `Function`, `Consumer`, `BiFunction` 等),它们允许开发者创建更复杂的功能块。 2. **Stream API**:Java Stream APIJDK 8 中另一个重要的新特性。它提供了一种对数据进行操作和处理的方式,这种处理方式更接近于其他编程语言的数据处理库。 3. **新的集合类**:JDK 8 引入了一些新的集合类,如 `NavigableSet`, `ConcurrentHashMap` 等,这些类提供了更高效的数据结构和性能。 4. **G1垃圾收集器**:JDK 8 中的 G1垃圾收集器是一个可预测的、并行化的垃圾收集器,提供了更好的性能和响应时间。 5. **日期时间 API**:JDK 8 引入了一个新的日期时间 API,它提供了更简单、更一致的方式来处理日期时间。 6. **模块系统**:Java 模块系统是 JDK 8 中的另一个新特性,它允许开发者创建独立的、可移植的软件包。 7. **流处理框架**:JDK 8 中的流处理框架 Stream API 支持用户自定义的流处理操作符,这使得开发者可以创建更复杂的流处理程序。 8. **新的异常处理机制**:JDK 8 中的新异常处理机制允许开发者使用 lambda 表达式来声明和处理异常。 9. **改进的 JDBC API**:JDK 8 中的 JDBC API 提供了一个更简单、更直观的方式来访问数据库。 以上就是 JDK 8 中一些主要的新特性,这些特性都为开发者提供了更高效、更简洁的开发体验。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

扛麻袋的少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值