Java8新日期API起始篇

为什么要学习新的日期API

  1. 旧的日期API(Date/Calender)计算困难,毫秒值计算容易出现误差

  2. 旧的日期API(Date/Calender)线程不安全

    SimpleDateFormat类是线程不安全的,在多线程的情况下,全局共享一个

    SimpleDateFormat类中的Calender对象有可能会出现异常

  3. 旧的日期API(Date/Calender)不符合开发规范,使用了魔法数字,初始化月份需-1等操作

​ 最终JavaSE 8中引入了java.time包,这种全新的包从根本上解决了长久以来的存在的诸多弊端,java.time包基于Joda-Time库构件,是一种免费的开源解决方案。

java.time包

常用类的概述和功能介绍

Instant类

​ Instant类对时间轴上的单一瞬时点建模,可以用于记录应用程序中的事件事件戳,之后学习的类型转换中,均可以使用Instant类作为中间类完成转换。

Duration类

​ Duration类表示秒和纳秒时间间隔,适合处理较短的时间,需要更高的精确性。

Period类

​ Period类表示一段时间的年、月、日。

LocalDate类

​ LocalDate是一个不可变的日期时间对象,表示日期,通常被视为年月日。

LocalTime类

​ LocalTime是一个不可变的日期时间对象,代表一个时间,通常被看作是时分秒,时间表示为纳秒精度。

LocalDateTime类

​ LocalDateTime是一个不可变的日期时间对象,代表日期时间,通常被视为年月日 时分秒。

ZonedDateTime类

​ ZonedDateTime是具有时区的日期时间的不可变表示,此类存储所有日期和时间字段,精度为纳秒,时区为区域偏移量,用于处理模糊的本地日期时间。

now()

​ java.time中的API中所有类均生成不可变实例,它们是线程安全的,并且这些类不提供公共构造函数,也就是说没办法通过new的方式直接创建,需要采用工厂方法加以实例化。

​ now():根据当前日期或时间创建实例,还可以通过Year、YearMonth等类获取更精准的某些信息。

public static void  nowDemoMethod(){

        // 使用now()方法创建 Instnat的实例对象
        Instant instantNow = Instant.now();
        System.out.println("Instant:"+instantNow);
        // 使用now()方法创建 LocalDate的实例对象
        LocalDate localDateNow = LocalDate.now();
        System.out.println("LocalDate:"+localDateNow);
        // 使用now()方法创建 LocalTime的实例对象
        LocalTime localTimeNow = LocalTime.now();
        System.out.println("LocalTime:"+localTimeNow);
        // 使用now()方法创建 LocalDateTime的实例对象
        LocalDateTime localDateTimeNow = LocalDateTime.now();
        System.out.println("LocalDateTime:"+localDateTimeNow);
        // 使用now()方法创建 ZonedDateTime的实例对象
        ZonedDateTime zonedDateTimeNow = ZonedDateTime.now();
        System.out.println("ZonedDateTime:"+zonedDateTimeNow);
        System.out.println();
         // 使用now()方法创建 Year的实例对象
         Year yearNow = Year.now();
         System.out.println("Year:"+yearNow);
         // 使用now()方法创建 YearMonth的实例对象
         YearMonth yearMonthNow = YearMonth.now();
         System.out.println("YearMonth:"+yearMonthNow);
         // 使用now()方法创建 MonthDay的实例对象
         MonthDay monthDayNow = MonthDay.now();
         System.out.println("MonthDay:"+monthDayNow);
    }

of()

​ 指定任意时间点。

​ of():可以根据给定的参数生成对应的日期/时间对象,基本上每个基本类都有of()用于生成对应的对象,而且重载形式多变,可以根据不同的参数生成对应格式的数据。

public static void ofDemoMethod(){

        // 初始化2020年10月31日的 LocalDate对象
        LocalDate localDate=LocalDate.of(2020, Month.OCTOBER, 31);
        System.out.println("LocalDate:"+localDate);

        /*
        * 初始化晚上8点0分0秒的 LocalTime对象 -> 如果是晚上时间,需要加12。
        * LocalTime.of方法的重载形式有以下几种,可以根据实际情况自行使用
        * LocalTime.of(int hour, int minute) -> 根据小时/分钟生成对象
        * LocalTime.of(int hour, int minute, int second) -> 根据小时/分钟/秒生成对象
        * LocalTime.of(int hour, int minute, int second, int nanoOfSecond) -> 根据小时/分钟/毫秒/纳秒生成对象
        * */
        LocalTime localTime = LocalTime.of(20, 0);
        // LocalTime:20:00  若末尾秒为0则省略
        System.out.println("LocalTime:" + localTime);

        /*
        * 初始化2020年10月31日下午8点0分的 LocalDateTime对象。
        * LocalDateTime.of方法的重载形式有以下几种,可以根据实际情况自行使用
        * LocalDateTime.of(int year, int month, int dayOfMonth, int hour, int minute, int second,int nanoOfSecond) ->根据年/月/日/时/分/秒/纳秒生成对象
        * LocalDateTime.of(int year, int month, int dayOfMonth, int hour, int minute) -> 根据年/月/日/时/分生成对象
        * */
        LocalDateTime localDateTime = LocalDateTime.of(2020, 10, 31, 20,0);
        // LocalDateTime2020-10-31T20:00
        System.out.println("LocalDateTime:" + localDateTime);

        /*
        * LocalDateTime的 of方法的特殊使用:
        * LocalDateTime.of(LocalDate date, LocalTime time)
        * */
        LocalDateTime localDateTime1 = LocalDateTime.of(localDate, localTime);
        // LocalDateTime1:2020-10-31T20:00
        System.out.println("LocalDateTime1:" + localDateTime1);
        
    }

时区信息的获取(拓展)

​ ZonedDateTime对象不仅有时间日期,并且还有偏移量+时区,在Java中通过java.time.ZoneId类的**getAvailableZoneIds()方法即可获取到一个Set集合,包含有所有的时区信息,大约有590个。也可以通过systemDefault()查看当前系统默认时区,java.time.LocalDateTime类的atZone()获取时区时间信息,java.time.ZonedDateTime类的withZoneSameInstant()**查看不同时区的时间。

public static void zoneIdDemoMethod(){

        // 获取所有时区信息
        Set<String> allZoneList=ZoneId.getAvailableZoneIds();
        for (String zoneId : allZoneList) {
            System.out.println(zoneId);
        }
        System.out.println("时区个数为:"+allZoneList.size()+"个");

        // 获取当前系统默认时区
        ZoneId zoneId=ZoneId.systemDefault();
        System.out.println("当前系统默认时区:"+zoneId);

        // 查看不同时区的时间信息
        LocalDateTime localDateTime=LocalDateTime.of(2020, Month.OCTOBER,30,22,30,50);
        ZonedDateTime zonedDateTime=localDateTime.atZone(zoneId.of("Asia/Shanghai"));
        System.out.println("上海当前时间是:"+zonedDateTime);
        // 更改时区,查看东京当前时间
        ZonedDateTime djzonedDateTime=zonedDateTime.withZoneSameInstant(ZoneId.of("Asia/Tokyo"));
        System.out.println("同时刻东京时间为:"+djzonedDateTime);
    }

Month枚举类

​ Month枚举类中包含标准日历的12个月份常量,也提供了一些方便的方法供我们使用。

JANUARY-1;FEBRUARY-2;MARCH-3; APRIL-4;MAY-5;JUNE-6;JULY-7;AUGUST-8;SEPTEMBER-9;OCTOBER-10;NOVEMBER-11;DECEMBER-12;

public static void monthDemoMethod(){

        // 初始化 LocalDateTime等时间月份推荐使用枚举类Month 简单明了
        LocalDateTime localDateTime=LocalDateTime.of(2020, Month.OCTOBER,30,22,30,50);
        System.out.println(localDateTime);
        // Month枚举类of()可根据传入的数字返回对应的月份枚举
        Month month=Month.of(11);
        System.out.println(month);
        // Month枚举类所有的枚举值
        System.out.println(Arrays.toString(Month.values()));

    }

plus()/minus()

修改某个日期/时间对象的现有实例时,可以使用plus和minus相关方法来完成操作。

​ Java8中日期时间相关API中的所有实例都是不可改变的,一旦创建LocalDate、LocalTime、LocalDateTime就无法修改它们(类似String),这对于线程安全是非常有利的。

plusXXX()/minusXXX()

​ plusXXX()与minusXXX是一组对应方法,前者是增加具体值,后者是减少具体值,实际上minus()调用的也是plus(),只不过传入的参数是负数。

plus()与minus()方法在LocalDate与LocalTime中的使用

  • LocalDate

    LocalDate plusDays(long days) 增加天数

    LocalDate minusDays(long days) 减少天数

    LocalDate plusWeeks(long weeks) 增加周数

    LocalDate minusWeeks(long weeks) 减少周数

    LocalDate plusMonths(long months) 增加月数

    LocalDate minusMonths(long months) 减少月数

    LocalDate plusYears(long years) 增加年数

    LocalDate minusYears(long years) 减少年数

  • LocalTime

    LocalTime plusNanos(long nanos) 增加纳秒

    LocalTime minusNanos(long nanos) 减少纳秒

    LocalTime plusSeconds(long seconds) 增加秒

    LocalTime minusSeconds(long seconds) 减少秒

    LocalTime plusMinutes(long minutes) 增加分钟

    LocalTime minusMinutes(long minutes) 减少分钟

    LocalTime plusHours(long hours) 增加小时

    LocalTime minusHours(long hours) 减少小时

public static void plusXXXAndminusXXXDemoMethod(){
        /**
         * LocalDate
         */
        // 初始化日期为2020年11月1日
        LocalDate localDate=LocalDate.of(2020, Month.NOVEMBER, 1);
        System.out.println("当前日期为:"+localDate);
        System.out.println();
        // 四天后的日期是 2020-11-05
        LocalDate localDate1=localDate.plusDays(4);
        System.out.println("四天后的日期为:"+localDate1);
        System.out.println("原日期为:"+localDate1.minusDays(4));
        // 三周后的日期是 2020-11-22
        LocalDate localDate2=localDate.plusWeeks(3);
        System.out.println("三周后的日期为:"+localDate2);
        System.out.println("原日期为:"+localDate2.minusWeeks(3));
        // 二月后的日期是 2021-01-01
        LocalDate localDate3=localDate.plusMonths(2);
        System.out.println("二月后的日期为:"+localDate3);
        System.out.println("原日期为:"+localDate3.minusMonths(2));
        // 一年后的日期是 2021-11-01
        LocalDate localDate4=localDate.plusYears(1);
        System.out.println("一年后的日期为:"+localDate4);
        System.out.println("原日期为:"+localDate4.minusYears(1));

        /**
         * LocalTime
         */
        System.out.println("******LocalTime******");
        // 初始化时间为22点43分56秒216纳秒
        LocalTime localTime=LocalTime.of(22,43,56,216);
        System.out.println("当前时间为:"+localTime);
        System.out.println();
        // 200纳秒后的时间是 22:43:56.000000416
        LocalTime localTime1=localTime.plusNanos(200);
        System.out.println("200纳秒后的时间为:"+localTime1);
        System.out.println("原时间为:"+localTime1.minusNanos(200));
        // 30秒后的时间是 22:44:26.000000216
        LocalTime localTime2=localTime.plusSeconds(30);
        System.out.println("30秒后的时间为:"+localTime2);
        System.err.println("原时间为:"+localTime2.minusSeconds(30));
        // 20分钟后的时间是 23:03:56.000000216
        LocalTime localTime3=localTime.plusMinutes(20);
        System.out.println("20分钟后的时间为:"+localTime3);
        System.out.println("原时间为:"+localTime3.minusMinutes(20));
        // 10小时后的时间是 08:43:56.000000216
        LocalTime localTime4=localTime.plusHours(10);
        System.out.println("10小时后的时间为:"+localTime4);
        System.out.println("原时间为:"+localTime4.minusHours(10));

    }

plus()/minus()

​ 下面为大家介绍单独使用plus()与minus()

  • plus/minus()

    plus/minus(TemporalAmount amountToAdd) 为当前日期/时间添加一段时间

    ​ TemporalAmount是一个接口,当接口作为方法的参数时,实际传入的是接口的实现类对象。该接口体系中比较常用的实现类为Period,该类表示一段时间。Period类的of(int year,int month,int day)可用于表示一段时间,例如Period.of(1,2,3)返回的对象即为一年二个月三天这么一个时间段。

    plus/minus(long amountToAdd, TemporalUnit unit) 为当前日期/时间添加一些特殊事件,如世纪、年、半天…

    ​ 在实际开发过程中,可能还会更精准的去操作日期或者说增加一些特殊的时间,比如说1个世纪、1个半天、1千年、10年等,Java8提供了这些日期的表示方式而不需要去单独进行计算了。

    ​ TemporalUnit是一个接口,该接口体系中常用的实现类是ChronoUnit,该类封装了很多时间段供我们使用:NANOS-纳秒、MICROS-微秒、MILLIS-毫秒、SECONDS-秒、MINUTES-分钟、HOURS-小时、HALF_DAYS-半天、DAYS-天、WEEKS-星期、MONTHS-月、YEARS-年、DECADES-十年、CENTURIES-世纪、MILLENNIA-千年、ERAS-十亿年、FOREVER-永远。

public static void plusAndminusDemoMethod(){

        LocalDateTime now=LocalDateTime.of(2020, Month.NOVEMBER,1,22,30,30);
        // 在当前日期基础上增加2年1个月4天  
        LocalDateTime endTime=now.plusYears(2).plusMonths(1).plusDays(4);
        System.out.println("当前时间:"+now+",增加后的时间:"+endTime);
        
        // plus(TemporalAmount amountToAdd)
        Period period=Period.of(2, 1, 4);
        LocalDateTime endTime1=now.plus(period);
        LocalDateTime startTime1=endTime1.minus(period);
        System.out.println("当前时间:"+startTime1+",增加后的时间:"+endTime1);
        
        // plus(long amountToAdd,  TemporalUnit unit)
        // 在当前日期基础上增加10年
        LocalDateTime endTime2=now.plus(1, ChronoUnit.DECADES);
        LocalDateTime startTime2=endTime2.minus(1, ChronoUnit.DECADES);
        System.out.println("当前时间:"+startTime2+",十年后的时间:"+endTime2);
        // 在当前日期基础上增加半天
        LocalDateTime endTime3=now.plus(1, ChronoUnit.HALF_DAYS);
        LocalDateTime startTime3=endTime3.minus(1, ChronoUnit.HALF_DAYS);
        System.out.println("当前时间:"+startTime3+",半天后的时间:"+endTime3);

    }

with()

​ 当想要直接修改日期时,可以使用with(),该方法提供了很多种修改时间的方式

  1. 直接使用对应方法修改日期时间中的某个值

    LocalDateTime withNano(int i) 修改纳秒

    LocalDateTime withSecond(int i) 修改秒

    LocalDateTime withMinute(int i) 修改分钟

    LocalDateTime withHour(int i) 修改小时

    LocalDateTime withDayOfMonth(int i) 修改日

    LocalDateTime withMonth(int i) 修改月

    LocalDateTime withYear(int i) 修改年

  2. with(TemporalField field, long newValue) 指定修改日期时间中的某个值

    ​ TemporalField是一个接口,该接口体系中常用的实现类是ChronoField,该类封装了一些日期时间中的组成成分,可以直接选择后传入第二个参数进行修改。

    ​ 比如:with(ChronoField.MONTH_OF_YEAR,10) 将日期时间中的月份修改为10月

    ​ 比如:with(ChronoField.YEAR,2021) 将日期时间中的年修改为2021年

    ​ TemporalField类中的常用日期时间的表示字段有:YEAR-年、MONTH_OF_YEAR-月、DAY_OF_MONTH-日、HOUR_OF_DAY-时、MINUTE_OF_HOUR-分、SECOND_OF_MINUTE-秒。

public static void withDemoMethod(){

        // 初始化日期时间
        LocalDateTime localDateTime=LocalDateTime.of(2020, Month.SEPTEMBER,27,21,15,55);
        // 修改时间日为28日
        LocalDateTime changeTime=localDateTime.withDayOfMonth(28);
        System.out.println("原时间:"+localDateTime+",修改后的时间:"+changeTime);
        // with(TemporalField field,long newValue) 
        // 修改时间月为10月
        LocalDateTime changeTime2=changeTime.with(ChronoField.MONTH_OF_YEAR,10);
        System.out.println("原时间:"+localDateTime+",两次修改后的时间:"+changeTime2);
        
    }

TemporalAdjuster调节器

​ with(TemporalAdjuster adjuster) 该方法可用于更复杂的日期时间操作,比如将时间调整到本月第一天、下月第一天、本年第一天等,这时可以使用调节器TemporalAdjuster来更方便的处理。该方法需要传入一个TemporalAdjuster对象,TemporalAdjuster是一个接口,实际传入的是TemporalAdjuster接口的实现类对象。

TemporalAdjusters类的一些静态方法可以返回TemporalAdjuster对象。TemporalAdjusters常用的静态方法有:

​ static TemporalAdjuster firstDayOfMonth() 本月的第一天

​ static TemporalAdjuster lastDayOfMonth() 本月最后一天

​ static TemporalAdjuster firstDayOfYear() 本年的第一天

​ static TemporalAdjuster lastDayOfYear() 本年最后一天

​ static TemporalAdjuster firstDayOfNextMonth() 下个月的第一天

​ static TemporalAdjuster firstDayOfNextYear() 下一年第一天

public static void temporalAdjusterDemo(){
        // 初始化当前日期对象
        LocalDate localDate=LocalDate.of(2020, 11, 8);
        // with(TemporalAdjuster adjuster)
        LocalDate firstDayOfMonth=localDate.with(TemporalAdjusters.firstDayOfMonth());
        System.out.println("当月第一天:"+firstDayOfMonth);

        LocalDate lastDayOfMonth=localDate.with(TemporalAdjusters.lastDayOfMonth());
        System.out.println("当月最后一天:"+lastDayOfMonth);

        LocalDate firstDayOfYear=localDate.with(TemporalAdjusters.firstDayOfYear());
        System.out.println("本年第一天:"+firstDayOfYear);

        LocalDate lastDayOfYear=localDate.with(TemporalAdjusters.lastDayOfYear());
        System.out.println("本年最后一天"+lastDayOfYear);

        LocalDate firstDayOfNextMonth=localDate.with(TemporalAdjusters.firstDayOfNextMonth());
        System.out.println("下个月第一天:"+firstDayOfNextMonth);

        LocalDate firstDayOfNextYear=localDate.with(TemporalAdjusters.firstDayOfNextYear());
        System.out.println("下一年第一天:"+firstDayOfNextYear);
    }

注意:TemporalAdjuster是一个接口,with(TemporalAdjuster adjuster) 实际上传入的是TemporalAdjuster接口的实现类对象。TemporalAdjusters并不是TemporalAdjuster的实现类,只不过TemporalAdjusters的静态方法返回了TemporalAdjuster对象。

DayOfWeek

DayOfWeek是一周中星期几的枚举类,封装了从周一到周日的值。

​ MONDAY-1、TUESDAY-2、WEDNESDAY-3、THURSDAY-4、FRIDAY-5、SATURDAY-6、SUNDAY-7

public static void dayOfWeekDemo(){

        // 初始化当前日期对象
        LocalDate localDate=LocalDate.of(2020, 11, 10);
        // 将当前日期修改为下周日
        LocalDate s=localDate.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
        System.out.println("下周日是:"+s);
        // 将当前日期修改为上周三
        LocalDate w=localDate.with(TemporalAdjusters.previous(DayOfWeek.WEDNESDAY));
        System.out.println("上周三是:"+w);

    }

本片博客只是大致介绍最基本新日期API的用法,进阶详细教程
Java8新日期API精华篇

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值