zoukankan      html  css  js  c++  java
  • java8学习:新的日期使用

    java8学习:新的日期使用

    https://yq.aliyun.com/articles/672967

    摘要: 内容来自《 java8实战 》,本篇文章内容均为非盈利,旨为方便自己查询、总结备份、开源分享。如有侵权请告知,马上删除。书籍购买地址:java8实战 最开始java 1.0时代,开始使用Date时间类,相当难用,他是以1900年起始,月份是从0开始的,如果你要表示2018年11月25日,那么就要这样 Date date = new Date(118,10,25); System.

    内容来自《 java8实战 》,本篇文章内容均为非盈利,旨为方便自己查询、总结备份、开源分享。如有侵权请告知,马上删除。
    书籍购买地址:java8实战

    • 最开始java 1.0时代,开始使用Date时间类,相当难用,他是以1900年起始,月份是从0开始的,如果你要表示2018年11月25日,那么就要这样

      Date date = new Date(118,10,25);
      System.out.println(date.toLocaleString()); //2018-11-25 0:00:00
    • 之后Date大多数方法已经废弃,却而代之的是Calendar类,但是这个类的月份依旧是从0开始的,但是年份不是从1900开始的,但是解析日期的DateFormat方法只在Date中有,并且他不是线程安全的
    • Date和Calendar都是可变的,这将带来很多麻烦,java8中在java.time中整合了很多Joda-Time的特性,Joda-Time之前是第三方类库

    使用LocalDate和LocalTime

    • 从类名就可以看出,LocalDate是表示年月日,而LocalTime是表示时分秒
    • LocalDate使用

      LocalDate date = LocalDate.of(2018,11,25);
      int year = date.getYear();  //2018
      Month month = date.getMonth(); // NOVEMBER
      int dayOfMonth = date.getDayOfMonth(); //25
      DayOfWeek dayOfWeek = date.getDayOfWeek();  //SUNDAY
      int i = date.lengthOfMonth();   //30
      boolean leapYear = date.isLeapYear();  //false
      //获取现在时间
      LocalDate now = LocalDate.now();  //2018-11-25
    • 除了getxxx方法,还可以使用TemporalField参数给get方法获取相同的信息

      LocalDate localDate = LocalDate.of(2018, 11, 25);
      int year = localDate.get(ChronoField.YEAR);
      int month = localDate.get(ChronoField.MONTH_OF_YEAR);
      int dayofweek = localDate.get(ChronoField.DAY_OF_WEEK);
    • 如上的ChronoFieldTemporalField的实现
    • LocalTime的使用

      LocalTime time = LocalTime.of(8,34,00);
      int hour = time.getHour();  //8
      int minute = time.getMinute();  //34
      int second = time.getSecond();  //0
      int nano = time.getNano();  //0
    • LocalDate和LocalTime的解析

      LocalTime time = LocalTime.parse("08:24");
      LocalDate date = LocalDate.parse("2018-11-25");
    • 解析不了会出DateTimeParseException

    合并日期和事件

    • 就是LocalDateTime类,结合了上面两个类,可以同时表示年月日和时分秒

      //LocalDateTime基本使用
      LocalDateTime localDateTime = LocalDateTime.of(2018,11,25,8,37);
      //创建LocalDate对象
      LocalDate localDate = LocalDate.now();
      //调用atTime可以传入具体时分秒,构成LocalDateTime
      LocalDateTime time1 = localDate.atTime(8, 37);
      //创建LocalTime对象
      LocalTime localTime = LocalTime.now();
      //调用atDate,传入具体年月日对象,构成LocalDateTime
      LocalDateTime localDateTime1 = localTime.atDate(localDate);
      //从LocalDateTime中可以获取LocalDate和LocalTime
      LocalDate date = localDateTime.toLocalDate();  
      LocalTime time = localDateTime.toLocalTime();

    Instant

    • 以1970年1月1日0时0分0秒开始计算的

      Instant instant = Instant.ofEpochSecond(20); //1970-01-01T00:00:20Z
      Instant.ofEpochSecond(20, 1000000000);//1970-01-01T00:00:21Z
    • 如上的ofEpochSecond方法,第一个参数是以秒为单位的,然后增强版本,是以纳秒为单位的,其实第二个方法就是在1970-1-1-00:00:00时间上加上了21秒而已
    • 也有now方法获取当前时间戳

    Duration和Period

    • 取两个时间之间的差值

      LocalTime time1 = LocalTime.of(8,00);
      LocalTime time2 = LocalTime.of(9,00);
      Duration between = Duration.between(time1, time2);  //PT1H
    • LocalTime,LocalDateTime,Instant可以用于Duration,Duration适用于以秒和纳秒,所以就不能向其传入LocalDate

      LocalDate date1 = LocalDate.of(2018,7,7);
      LocalDate date2 = LocalDate.of(2018,8,10);
      Period between = Period.between(date1, date2);  //P1M3D
    • 当然他们不仅限于计算差值,还可以创建对象以代表具体的时间值

      Duration duration = Duration.ofMillis(3);
      System.out.println("duration = " + duration);//duration = PT0.003S
      Period period = Period.ofDays(10);
      System.out.println("period = " + period);//period = P10D
    • 对于其他的方法,大家可以查询文档即可:java8 api文档
    • 对于以上的介绍目前为止日期对象都是不可变的,这是考虑函数式编程以及线程安全而做的决定

    操纵解析和格式化日期

    • 创建LocalDate的修改版

      LocalDate date = LocalDate.of(2018, 4, 4); //2018-4-4
      LocalDate date1 = date.withYear(2014);//2014-4-4
      LocalDate date2 = date1.withMonth(6);//2014-6-4
      LocalDate date3 = date2.withDayOfMonth(6);//2014-6-6
    • 也可以这样

      LocalDate date = LocalDate.of(2018, 4, 4); //2018-4-4
      LocalDate date1 = date.minusYears(4); //2014-4-4
      LocalDate date2 = date1.plusMonths(8);//2014-12-4
      LocalDate date3 = date2.plusDays(10);//2014-12-14
    • 需要注意的是,即使对一个时间对象调用方法,但是该对象是不会发生改变的,只是返回一个新对象,如下

      LocalDate date = LocalDate.of(2018, 4, 4); //2018-4-4
      LocalDate date1 = date.plusYears(2).with(ChronoField.MONTH_OF_YEAR, 12).plusDays(10);
      date.plusYears(12);
      System.out.println(date);//2018-4-4
      System.out.println(date1);//2020-12-14

    使用TemporalAdjuster

    • 当我们遇到复杂情况的时候,比如调整时间到下个周日之类的要求,我们就需要自定义一个TemporalAdjuster对象,更加灵活的处理日期
    • java8已经预定义好一些TemporalAdjuster了,可以通过工厂类访问他们

      LocalDate date = LocalDate.of(2018, 11, 26); //2018-11-26   周1
      LocalDate date1 = date.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY)); //下个周日是2018-12-2
      LocalDate date2 = date1.with(TemporalAdjusters.lastDayOfMonth()); //2018-12-31   十二月的最后一天
    • 其他工厂方法请自己查看java api获取
    • TemporalAdjuster是一个函数式接口,定义如下

      @FunctionalInterface
      public interface TemporalAdjuster {
          Temporal adjustInto(Temporal temporal);
      }
    • 如上传入一个Temporal,返回一个Temporal,也就是说,实现的逻辑在于怎样把传入的Temporal转换为另一个需要的Temporal

    定制TemporalAdjuster

    • 创建类实现TemporalAdjuster接口

      
      /**
       * 需求:返回下一个工作日,如果日期在周一到周五之间,就返回下一天就好,如果是周五六日就需要返回下周一的日期
       */
      public class NextWorkingDay implements TemporalAdjuster {
          @Override
          public Temporal adjustInto(Temporal temporal) {
              //得到参数中是这周的第几天
              int day = temporal.get(ChronoField.DAY_OF_WEEK);
              //根据第几天构造出DayOfWeek枚举类,容易观察,当然也可以不用构造
              //如果不够再下面的判断相等直接改成上面的day就行了
              DayOfWeek dayOfWeek = DayOfWeek.of(day);
              //需要在参数的基础上增加几天
              int dayNeedAdd = 1;
              //如果是周五,就需要推后三天才是周一
              if (dayOfWeek == DayOfWeek.FRIDAY){
                  dayNeedAdd = 3;
              }
              //如果是周六,就需要推后两天才是周一
              if (dayOfWeek == DayOfWeek.SATURDAY){
                  dayNeedAdd = 2;
              }
              //如果是周日或者当天就是在周一到周五之间的,直接加一就可以,即返回下一天
              return temporal.plus(dayNeedAdd, ChronoUnit.DAYS);
          }
      }
    • 上面说此接口是函数式接口,当然就可以使用Lmabda传入了,使用如下

      LocalDate date = LocalDate.of(2018, 11, 25);//周日
      LocalDate nextWorkDay = date.with(new NextWorkingDay());  //2018-11-26
    • 使用lambda

      LocalDate date = LocalDate.of(2018, 11, 25);//周日
      LocalDate nextWorkDay = date.with(temporal -> {
          //具体实现是把上面的实现类NextWorkingDay内实现的方法体贴进来就行了
      });
    • 也可以这样

      LocalDate date = LocalDate.of(2018, 11, 25);//周日
      TemporalAdjuster nextWorkDay = TemporalAdjusters.ofDateAdjuster(temporal -> {
          //具体实现是把上面的实现类NextWorkingDay内实现的方法体贴进来就行了
      });
      LocalDate date1 = date.with(nextWorkDay);
    • 如上是一个静态方法,传入一个UnaryOperator函数式接口的实现即可,就能够返回一个TemporalAdjuster对象,然后传入with方法即可

    日期解析

    • java.time.format包就是解析日期格式化日期的,最重要的是DateTimeFormatter类,他有一些预定义常量

      LocalDate date = LocalDate.of(2018, 8, 8);
      String format = date.format(DateTimeFormatter.BASIC_ISO_DATE);//20180808
      String format1 = date.format(DateTimeFormatter.ISO_LOCAL_DATE);//2018-08-08
    • 也可以通过指定解析模式来解析Sring时间字符串

      LocalDate parse = LocalDate.parse("20180808", DateTimeFormatter.BASIC_ISO_DATE); //2018-08-08
      LocalDate parse1 = LocalDate.parse("2018-08-08", DateTimeFormatter.ISO_LOCAL_DATE); //2018-08-08
    • 与之前的DateFormat相比,DateTimeFormatter是线程安全的
    • 按照指定格式创建解析器

      DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM-dd");
      LocalDate date = LocalDate.of(2018, 12, 6);
      //按照指定格式返回时间字符串
      String format = date.format(formatter);
      System.out.println("format = " + format);  //2018/12-06
      //根据指定的解析格式解析指定时间字符串
      LocalDate parse = LocalDate.parse(format, formatter);
      System.out.println("parse = " + parse);  //2018-12-06
    • 创建一个更加复杂的解析器

      DateTimeFormatter builder = new DateTimeFormatterBuilder()
              .appendText(ChronoField.DAY_OF_MONTH)   //首先解析的是一个月的第几天
              .appendLiteral("(")   //分隔符
              .appendText(ChronoField.MONTH_OF_YEAR)  //一年的第几个月
              .appendLiteral("+")   //分隔符
              .appendText(ChronoField.YEAR)  //年份
              .parseCaseInsensitive()  //开始解析,不区分大小写
              .toFormatter(Locale.CHINA);  //按照哪个国家的方言开始解析
      LocalDate date = LocalDate.of(2018, 2, 25);
      String format = date.format(builder);
      System.out.println("format = " + format); //25(二月+2018
    • 到这里,我们介绍了时间类的使用和解析,以及自定义如何实现自己的日期转换逻辑,至于本书剩下的时区和计算时区的偏差,本文不再记录
  • 相关阅读:
    EF4.3 到底能不能用?
    系统架构师(详解+转)
    silverlight MD5加密
    silverlight自定义安装客户端插件
    vs2010中文安装英文版silverlight5,和MVC 3
    如何自定义gridview的表格显示?
    Scott Mitchell的ASP.NET2.0数据指南中文版索引
    成功软件开发者的9种编程习惯(一)
    第8章 商品目录管理
    6/29 项目目录结构有所调整
  • 原文地址:https://www.cnblogs.com/handsome1013/p/10830900.html
Copyright © 2011-2022 走看看