时间API

时间API

    • Package java.time
      • Instant
        • 获取Instant实例:
        • 算术运算
    • Duration
    • LocalDate
      • 构建方法
      • 其他方法的应用
    • YearMonth
    • MonthDay
    • Period
    • LocalTime
    • LocalDateTime
    • TemporalAdjusters
    • 时区时间
    • 格式化和解析
  • 与遗留代码互操作

Java之前的时间API如Date等等,弊端和不方便之处还是不小的,所以在Java8推出了新的时间API,今天就来学习一下。

Package java.time

首先看一下time包,里面有几个子包和各种日期时间类。一一开始学习。

Instant

该类是绝对时间,即国际标准时间(UTC时间),世界时间(就类似于整个中国都用的是北京时间一样),UTC时间就是整个世界用的标准时间。此时北京时间2019-09-25T10:37:58.553,而国际时间为2019-09-25T02:37:58.375Z。理解了instant类的含义,开始下一步学习。
Instant具体为时间点,某个时刻。时间点在时间线上。时间线有三个重要时间点(最大值,最小值,原点)。

 		System.out.println(Instant.EPOCH);//时间原点
        System.out.println(Instant.MAX);//最大值
        System.out.println(Instant.MIN);//最小值

运行结果如下:
在这里插入图片描述

获取Instant实例:

Instant可以精确到纳秒,查看Instant源码可知,内部有着两个常量。seconds表示从1970-01-01 00:00:00开始到现在的秒数,用long类型存储,nanos表示纳秒部分(nanos的值不会超过999,999,999),用int类型存储。
Instant实例获取方式有多种:
时间API_第1张图片这里介绍先两个方法

  • now()方法:获得当前的时间(UTC时间)
 //获得当前时间点
        Instant start =  Instant.now();
        System.out.println(start);

打印结果:
在这里插入图片描述
此时北京时间是09-25-11:11。

  • ofEpochSecond(long epochSecond, long nanoAdjustment)方法:根据给定的秒和纳秒(距离时间原点的秒数和纳秒数)获得时间点
 Instant time = Instant.ofEpochSecond(10000000, 10000);
        System.out.println(time);

得到的是距离时间原点10000000秒10000纳秒的时间点
打印结果如下:
在这里插入图片描述

算术运算

时间API_第2张图片
在这里插入图片描述Duration类待会学习。
抽出一个算术方法实践一下:

 //获得当前时间点
        Instant start =  Instant.now();
        System.out.println(start);

        //获得增加两分钟的时间点
        Instant start1 = start.plusSeconds(120);
        System.out.println(start1);

打印结果:
在这里插入图片描述Instant类就简单了解到这步,后面有需要的再从API中学习了解。

Duration

上面在算术运算中提及了Duration类,这里来学习一下。
Duration:时间段。Duration的内部实现与Instant类似,也是包含两部分:seconds表示秒(long类型),nanos表示纳秒(int)。两者的区别是Instant用于表示一个时间戳(或者说是一个时间点),而Duration表示一个时间段,所以Duration类中不包含now()静态方法。
可以通过Duration.between()方法创建Duration对象:

 //获得当前时间点
        Instant start =  Instant.now();
        System.out.println(start);

        //获得增加两分钟的时间点
        Instant start1 = start.plusSeconds(120);
        System.out.println(start1);

        Duration btime = Duration.between(start, start1);// 表示从 start1 到 start 这段时间

        long days = btime.toDays();              // 这段时间的小时数
        long hours = btime.toHours();            // 这段时间的小时数
        long minutes = btime.toMinutes();        // 这段时间的分钟数
        long seconds = btime.getSeconds();       // 这段时间的秒数
        long milliSeconds = btime.toMillis();    // 这段时间的毫秒数
        long nanoSeconds = btime.toNanos();      // 这段时间的纳秒数

也可通过of()方法创建一个时间段。

Duration duration1 = Duration.of(5, ChronoUnit.DAYS);       // 5天
Duration duration2 = Duration.of(1000, ChronoUnit.MILLIS);  // 1000毫秒

LocalDate

现在我们从UTC时间来到当地时间,在中国自然就是北京时间,在其他地区就是其他地区的时间。LocalDate是日期类,只有日期(年月日)不含具体时间

构建方法

now()方法,of()方法

  //获取当天日期
        LocalDate today = LocalDate.now();
        System.out.println("今天日期:"+today);

        //获取当前年月日
        int year = today.getYear();
        int month = today.getMonthValue();
        int day = today.getDayOfMonth();
        System.out.println("年份:"+year+",月份:"+month+",日:"+day);

        //获取特定日期
        LocalDate myBirthday = LocalDate.of(1996, 5, 28);
        LocalDate myBirthday1 = LocalDate.of(1996, Month.APRIL, 10);
        System.out.println("生日:"+myBirthday);
        System.out.println("生日:"+myBirthday1);

运行结果如下:
在这里插入图片描述

其他方法的应用

 //检查两个日期是否想等
        LocalDate date1 = LocalDate.of(2019, 9, 24);
        if(date1.equals(today)){
            System.out.println("是同一天");
        }

 //如何获取一周之后日期(增加日,周,月)
        LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS);//1可以量化为几周
        LocalDate nextWeek1 = today.plusYears(1);
        System.out.println("next week is :"+nextWeek);
        System.out.println("next year is :"+nextWeek1);

 //判断某个日期在另外一个日期前还是后
        LocalDate tomorrow = LocalDate.of(2019, 9, 25);
        if(tomorrow.isAfter(today)){
            System.out.println("明天在今天之后");
        }
        LocalDate yesterday = today.minus(1, ChronoUnit.DAYS);
        if(yesterday.isBefore(today)){
            System.out.println("昨日在今天之前");
        }

 //检查是否是闰年
        if(today.isLeapYear()){
            System.out.println("今年是闰年");
        }else {
            System.out.println("今年不是闰年");
        }

YearMonth

YearMonth类只展示日期的年月,不含日

//如何表示固定日期,
        YearMonth currentYearMonth = YearMonth.now();
        System.out.printf("Days in month year %s: %d%n", currentYearMonth, currentYearMonth.lengthOfMonth());
        YearMonth creditCardExpiry = YearMonth.of(2019, Month.FEBRUARY);
        System.out.printf("Your credit card expires on %s %n", creditCardExpiry);

运行结果:
在这里插入图片描述

MonthDay

前面有只有年月,现在MonthDay类就是只有月日,没有年的

 //如何检查重复事件,比如生日
        //使用MonthDay类。这个类由月日组合,不包含年信息
        LocalDate dateOfBirth = LocalDate.of(1996, 5, 28);
        MonthDay birthday = MonthDay.of(dateOfBirth.getMonth(),dateOfBirth.getDayOfMonth());
        MonthDay currentMonthDay = MonthDay.from(today);
        System.out.println("birthday"+birthday);
        System.out.println("currentMonthDay"+currentMonthDay);
        if(currentMonthDay.equals(birthday)){
            System.out.println("Many Many happy returns of the day !!");
        }else{
            System.out.println("Sorry, today is not your birthday");
        }

运行结果如下:
在这里插入图片描述

Period

这个类以年,月和日为单位建立数量或时间量。 请参阅Duration的等效于此类的时间。

//两个日期之间包含多少个月,多少个日,多少年java.time.Period 
        LocalDate testDate = LocalDate.of(1996, 5, 28);
        Period period = Period.between(testDate,today);
        System.out.println("出生年数:"+period.getYears()+",出生月数:"+period.getMonths()+",出生日数:"+period.getDays());

打印结果如下:
在这里插入图片描述
可以看到在月份和日数上返回的是相对差。此时是2019年9月25日,比较是时间是1996年5月28日。返回的年数没问题,月数是相对差:3月,日子是相对差28(先过完3天5月结束,然后到25号,共28天)。那么我们怎么获得真正的月数和日数?
这时候需要使用LocalDate中的util方法处理。

 System.out.println("年:"+testDate.until(today, ChronoUnit.YEARS)+",月:"+testDate.until(today, ChronoUnit.MONTHS)
                +",周:"+testDate.until(today, ChronoUnit.WEEKS)+",日:"+testDate.until(today, ChronoUnit.DAYS));

打印结果如下:
在这里插入图片描述

LocalTime

前面讨论的是日期,现在讨论一下时间

 //获取当前时间 具有毫秒值
        LocalTime time =LocalTime.now();
        System.out.println("当前时间"+time);
        //获取当前时间 没有毫秒值
        LocalTime time1 =LocalTime.now().withNano(0);
        System.out.println("当前时间"+time1);
        
        //如何增加时间的时分秒数
        LocalTime newTimeHour = time.plusHours(2).withNano(0);
        LocalTime newTimeMin = time.plusMinutes(120).withNano(0);
        LocalTime newTimeSecond = time.plusSeconds(7200).withNano(0);
        System.out.println("增加2小时"+newTimeHour);
        System.out.println("增加120分钟"+newTimeMin);
        System.out.println("增加7200秒"+newTimeSecond);

打印结果如下:
在这里插入图片描述

LocalDateTime

完整的时间:包括年月日+时间

  //当前完整的时间
        LocalDateTime localDateTime1 = LocalDateTime.now();
        System.out.println(localDateTime1);
        //去掉毫秒数
        LocalDateTime localDateTime2 = LocalDateTime.now().withNano(0);
        System.out.println(localDateTime2);

打印结果:
在这里插入图片描述

TemporalAdjusters

日期调整类。在行程安排上,经常会出现这样的案例,“每月的第一个星期二”。TemporalAdjusters类提供了大量用于常见调整的静态方法。
时间API_第3张图片

//TemporalAdjusters
        //获取这个月第二个周末的日期
        System.out.println(today.with(TemporalAdjusters.dayOfWeekInMonth(2,DayOfWeek.SUNDAY)));
        //获取上个月最后一周
        System.out.println(today.with(TemporalAdjusters.dayOfWeekInMonth(0,DayOfWeek.SUNDAY)));
        //获取这个月的倒数第一个周末的时间
        System.out.println(today.with(TemporalAdjusters.dayOfWeekInMonth(-1,DayOfWeek.SUNDAY)));
        //明年的第一天
        System.out.println(today.with(TemporalAdjusters.firstDayOfNextYear()));
        //获取接下来的一个周5的时间
        System.out.println(today.with(TemporalAdjusters.next(DayOfWeek.FRIDAY)));
        // 获取本月最后一天
        System.out.println(today.with(TemporalAdjusters.lastDayOfMonth()));

还可以通过实现TemporalAdjusters类实现自己的调整器

 //  参数默认localdate
        TemporalAdjuster next = TemporalAdjusters.ofDateAdjuster(
                tdate->{
                    DayOfWeek work = tdate.getDayOfWeek();
                    int addDays=0;
                    if (work.equals(DayOfWeek.FRIDAY)) {
                        addDays=3;
                    }else if(work.equals(DayOfWeek.SATURDAY)){
                        addDays=2;
                    }else {
                        addDays=1;
                    }
                    return today.plusDays(addDays);
                }
        );
        System.out.println("下个工作日为:"+today.with(next));

时区时间

互联网编码分配管理机构(IANA)保存着一个数据库,里面保存着世界上所有已知时区。Java使用的是IANA数据库。
每个时区都有一个ID,例如America/New_York,Europe/Berlin。要想找到所有的时区ID,可以调用ZoneId.getAvailableZoneIds()方法。
给定一个时区ID,静态方法 ZoneId.of(String zoneId)可以产生一个ZoneId对象。可以通过调用local.atZone(zoneId)用这个对象将LocalDateTime对象转为ZonedDateTime对象,或者调用静态方法ZonedDateTime.of()来构造一个ZonedDateTime对象。

 //处理不同时区
        ZoneId america = ZoneId.of("America/New_York");
        LocalDateTime localDateTime = LocalDateTime.of(2019, 9, 24, 16, 14);
        ZonedDateTime dateAndTimeInNewYork = ZonedDateTime.of(localDateTime, america );
        System.out.println("不同时区"+dateAndTimeInNewYork);

纽约时刻:
在这里插入图片描述
时区涉及到夏令时(不太懂什么意思)
当夏令时开始时候,时钟要向前拨快一个小时,当你构建的时间正好落入这跳过去的一个小时内时:

 ZonedDateTime skipTime =ZonedDateTime.of(LocalDate.of(2013, 3, 31),LocalTime.of(2, 30),ZoneId.of("Europe/Berlin"));
        System.out.println(skipTime);

打印结果:
在这里插入图片描述
我希望构造的是2:30,但是我得到的却是3:30
反过来,当夏令时结束时候,时钟要往回拨慢一个小时,这样同一个本地时间就会出现两次。当你构建位于这个时间段的时间时,就会得到这两个时刻中较早的一个。

 ZonedDateTime skipTime1 =ZonedDateTime.of(LocalDate.of(2013, 10, 27),LocalTime.of(2, 30),ZoneId.of("Europe/Berlin"));
        System.out.println("skipTime1:"+skipTime1);
        ZonedDateTime anHourLater = skipTime1.plusHours(1);
        System.out.println("anHourLater:"+anHourLater);

打印结果:
在这里插入图片描述两个打印值都是2:30。即一个小时后时间会具有相同的小时和分钟,但是时区偏移量发生变化。
你还需要在调整跨越夏令时边界日期时特别注意。例如你需要把会议放在下一周,不要加上7天的Duration,而应该用Period类。
看的迷迷糊糊的…

格式化和解析

DateTimeFormatter类提供了三种用于打印日期/时间值的格式器:

  • 预定义的格式器
  • Locale相关的格式器
  • 带有定制模式的格式器

时间API_第4张图片要使用标准的格式器,直接调用format方法:

 String formatter1 = DateTimeFormatter.ISO_OFFSET_DATE.format(skipTime);
        System.out.println(formatter1);

打印一下:
在这里插入图片描述
标准格式器是为了机器刻度的时间戳而设计的。我们常用的日期时间形式的使用Locale相关的格式器。
时间API_第5张图片
静态方法ofLocalizedDate() ofLocalizedDateTime() ofLocalizedDateTime()可以创建上述格式器

  DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);
        String formatter2 = dateTimeFormatter.format(localDateTime);
        System.out.println(formatter2);

打印结果:
在这里插入图片描述
上述方法使用了默认的Locale,为了切换不同的Locale,可以使用withLocale方法

String formatter3 = dateTimeFormatter.withLocale(Locale.CHINA).format(localDateTime);
        System.out.println(formatter3);

也可以通过制定模式来指定自己的日期格式


        dateTimeFormatter = DateTimeFormatter.ofPattern("E yyyy-MM-dd HH:mm");
        String formatter2 = dateTimeFormatter.format(localDateTime);
        System.out.println(formatter2);

打印如下:
在这里插入图片描述

LocalDateTime dateTime = LocalDateTime.now();
String strDate1 = dateTime.format(DateTimeFormatter.BASIC_ISO_DATE);    // 20190925
String strDate2 = dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE);    // 2019-09-25
String strDate3 = dateTime.format(DateTimeFormatter.ISO_LOCAL_TIME);    // 17:11:12.145
String strDate4 = dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));   // 2019-09-25
String strDate5 = dateTime.format(DateTimeFormatter.ofPattern("今天是:YYYY年 MMMM DD日 E", Locale.CHINESE)); // 今天是:2019年 九月 25日 星期三

String strDate6 = "2019-09-25";
String strDate7 = "2019-09-25 17:33:24";

LocalDate date = LocalDate.parse(strDate6, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
LocalDateTime dateTime1 = LocalDateTime.parse(strDate7, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

与遗留代码互操作

时间API_第6张图片

时间API_第7张图片
看的头晕晕的,还需要在之后的工作学习中多多使用。
如有错误之处,还请指正!

你可能感兴趣的:(读Java核心技术第十版)