JDK 1.8 新特性之Date-Time API详解个人笔记

虽然java 10已经发布,11 已经在路上,虽然 java EE 已经更名为 jakarta EE,但是大多数人连jdk1.8的新特性都不太了解,本人也是如此,所以在学习Java 8 API 添加的 Data-Time API 的时候 做一些个人笔记,希望帮助自己的同时也能帮到大家。

分析1.8之前的日期类:

1、线程不安全:java.util.Date 这个类线程不安全,而且所有日期类都是可变的。

2、时间处理麻烦:默认的开始日期从1900年,不支持国际化,不提供时区支持,所以经常算出来的时间不是中国时间。

3、设计不好:java初学者接触到导包的时候,总会导错包,比如java.util和java.sql包中都有日期类,类名却是一样的。


那我们一起看看time包下的常用类吧

日期和时间

  • Instant 本质上是一个数字时间戳。可以从a中检索当前的Instant Clock。这对于某个时间点的日志记录和持久性非常有用。
  • LocalDate 没有时间存储日期。存储类似“2010-12-03”的日期,可用于存储生日。
  • LocalTime 没有日期存储时间。存储像'11:30'这样的时间,可用于存储开盘或收盘时间。
  • LocalDateTime 存储日期和时间。这会存储类似'2010-07-23T15:47:25.890'的日期时间。
  • ZonedDateTime 使用时区存储日期和时间。如果您想要考虑到日期和时间的准确计算ZoneId,例如“欧洲/巴黎”,这将非常有用。在可能的情况下,建议使用没有时区的更简单的类。时区的广泛使用往往会给应用程序增加相当大的复杂性

其他类型

  • Month 用来存储一个月。这样可以隔离单个月份,例如“DECEMBER”。
  • DayOfWeek 用来存储一个星期的日子。这样可以隔离存储一个星期几,例如“星期二”。
  • Year 用来存储一年。这样可以隔离一年,例如'2010'。
  • YearMonth 用来存储年加月份的时间。这会存储一年和一个月,例如“2010-12”,并可用于信用卡到期。
  • MonthDay 用来存储月份和日子。它存储月份和日期,例如“12-03”,可用于存储年度活动,如生日,而不存储年份。

写在前面:在连接数据库的时候,使用 Java 8 新特性 TimeDateAPI,字段对应不上,或者存入的不是时间,或者直接抛异常,请更新对应数据库的 pom 依赖,添加以下支持

Spring Data API 



	org.hibernate
	hibernate-java8
	5.0.12.Final

MyBatis


	org.mybatis
	mybatis-typehandlers-jsr310
	1.0.1

 


接下来我们针对每一个类写一点简单的例子,方便快速上手。

Instant

这个类是不可变的,线程安全。

public class InstantDemo {

  public static void main(String[] args) {
    //===============================================================================
    // 1、获取当前时间戳
    //===============================================================================
    System.out.println(Instant.now());  // 2018-07-23T07:57:00.821Z

    //===============================================================================
    // 2、传入CharSequence类型,转换为instant对象
    //===============================================================================
    CharSequence text = "2010-10-31T07:57:00.821Z";
    Instant instant = Instant.parse(text);
    System.out.println(instant);  // 2010-10-31T07:57:00.821Z
    // 注意:格式不正确或者不存在该日期时,会抛出DateTimeParseException异常

    //===============================================================================
    // 3、比较时间(大于小于排序)
    //===============================================================================
    System.out.println(instant.isAfter(Instant.parse("2010-11-30T07:57:00.821Z")));
    // false 返回布尔值
    System.out.println(instant.isBefore(Instant.parse("2010-11-30T07:57:00.821Z")));
    // true 返回布尔值
    System.out.println(instant.compareTo(Instant.parse("2010-11-30T07:57:00.821Z")));
    // -1  compareTo 返回值int类型  等于返回 0 小于返回 -1 大于返回 1
    System.out.println(instant.equals(Instant.parse("2010-10-31T07:57:00.821Z")));
    // true  返回布尔值 比较两个时间是否相等

    //===============================================================================
    // 4、获取从1970-01-01T00:00:00Z到现在的秒数
    //===============================================================================
    System.out.println(instant.getEpochSecond());  // 1288511820  
    // 返回值long,注意返回的是秒!不是毫秒!

    //===============================================================================
    // 5、设置时区偏移
    //===============================================================================
    OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
    System.out.println(offsetDateTime); // 2010-10-31T15:57:00.821+08:00  
    // 返回值类型OffsetDateTime  我们在东八区,所以加上八小时,就是本地时间戳

  }
}

LocalDate

LocalDate是一个不可变的类,它表示默认格式(yyyy-MM-dd)的日期,线程安全。

public class LocalDateDemo {

  public static void main(String[] args) {
    //===============================================================================
    // 1、获取当前日期
    //===============================================================================
    LocalDate localDate = LocalDate.now();
    System.out.println(localDate); // 2018-07-23
    
    //===============================================================================
    // 2、构造LocalDate
    //===============================================================================
    CharSequence text = "2010-10-10";
    System.out.println(LocalDate.parse(text)); // 2010-10-10
    CharSequence date = "20101010";
    System.out.println(LocalDate.parse(date,DateTimeFormatter.BASIC_ISO_DATE));// 2010-10-10
    // 自定义对应格式的转换,JDK1.8给出了预定义的格式化 DateTimeFormatter.BASIC_ISO_DATE 就是其中之一
    CharSequence myDate = "2010年10月10日";
    System.out.println(LocalDate.parse(myDate,DateTimeFormatter.ofPattern("yyyy年MM月dd日"))); // 2010-10-10
    // 预定义格式没有的情况,也可以自定义
    System.out.println(LocalDate.of(2010, 10, 10));// 2010-10-10
    // 给出int类型对应的 年月日,亦可构造出LocalDate对象
    System.out.println(LocalDate.of(2010, Month.JULY, 10));// 2010-07-10
    // 月份亦可给出对应 Mouth 枚举
    System.out.println(LocalDate.ofEpochDay(123)); // 1970-05-04
    // 给出日子,计算出 从 1970-01-01 对应日子后的日期
    System.out.println(LocalDate.ofYearDay(2010, 163)); //2010-06-12
    // 传入 年,日数,计算出 对应该年份 对应日子后的日期
    
    //===============================================================================
    // 3、获取,年,月,日
    //===============================================================================
    System.out.println(localDate.getMonth()); // JULY  返回英文月份,对应 Mouth 枚举
    System.out.println(localDate.getMonthValue()); // 7  返回数字月份
    System.out.println(localDate.getYear()); // 2018  返回对应年
    System.out.println(localDate.getDayOfMonth()); // 23  返回对应月份中的日子
    System.out.println(localDate.getDayOfWeek()); // MONDAY  返回对应星期,对应 DayOfWeek 枚举
    System.out.println(localDate.getDayOfYear()); // 204 返回对应年份中的日子
    System.out.println(localDate.lengthOfMonth()); // 31 对应该月份有多少天
    System.out.println(LocalDate.parse("2004-02-10").lengthOfMonth());
    // 29 证明可以自动判断是否为闰年!!!
    System.out.println(localDate.lengthOfYear()); // 365 对应年份有多少天
    System.out.println(LocalDate.parse("2004-02-10").lengthOfYear());
    // 366 证明可以自动判断是否为闰年!!!

    //===============================================================================
    // 4、判断大于小于,排序,判断是否闰年
    //===============================================================================
    System.out.println(localDate.compareTo(LocalDate.parse("2000-01-01"))); // 18
    // 这里的 compareTo 方法为什么返回 18 请看下面详解!!!
    System.out.println(localDate.isAfter(LocalDate.parse("2000-01-01"))); // true
    System.out.println(localDate.isBefore(LocalDate.parse("2000-01-01"))); // false
    System.out.println(localDate.isEqual(LocalDate.parse("2000-01-01"))); // false
    System.out.println(localDate.isLeapYear());// false  返回布尔值,该年是否为闰年
    
    //===============================================================================
    // 5、日期的加减
    //===============================================================================
    System.out.println(localDate.plusMonths(1)); // 2018-08-23  加一个月
    System.out.println(localDate.plusMonths(-1)); // 2018-06-23 减去一个月,传入负数即可,下面的也是
    System.out.println(localDate.plusDays(1)); // 2018-07-24 加上一天
    System.out.println(localDate.plusMonths(1)); // 2018-08-23 加上一个月
    System.out.println(localDate.plusWeeks(1)); // 2018-07-30 加上一个星期

    //===============================================================================
    // 6、其他计算
    //===============================================================================
    System.out.println(localDate.withDayOfYear(123)); // 2018-05-03 计算当前年第123天的日期

  }
}

针对上面 compareTo 方法为什么返回 18 ,我们来看一下源码

JDK 1.8 新特性之Date-Time API详解个人笔记_第1张图片

源码

所以也就不难理解为什么返回18了,2018年到2000年差的不就是18年,所以这里返回的是相差的年数,如果年数一样,返回的则是相差的月数,同理相同的月份,则返回相差的天数。


LocalTime

LocalTime是一个不可变的日期时间对象,代表一个时间,通常被看作是小时 - 秒,这个类不可变,线程安全。

public class LocalTimeDemo {

  public static void main(String[] args) {
    //===============================================================================
    // 1、获取当前时间
    //===============================================================================
    LocalTime time1 = LocalTime.now();
    System.out.println(time1); // 09:39:47.275

    //===============================================================================
    // 2、构造LocalTime
    //===============================================================================
    // 根据传入文本构造LocalTIme时间对象,格式不正确会抛出 java.time.format.DateTimeParseException 异常
    CharSequence text1 = "22:22:22";
    LocalTime localTime1 = LocalTime.parse(text1);
    System.out.println(localTime1); // 22:22:22
    // 传入自定义文本,自定义格式化 构造 LocalTime 对象
    CharSequence text2 = "11-11-11";
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("HH-mm-ss");
    LocalTime localTime2 = LocalTime.parse(text2, dateTimeFormatter);
    System.out.println(localTime2); // 11:11:11
    // 根据入参 时,分,秒,纳秒构造出LocalTime对象,24小时制
    // 如果入参不符合时间要求,例如传入25小时,61分钟,会抛出 java.time.DateTimeException 异常
    LocalTime time2 = LocalTime.of(13, 22);
    System.out.println(time2); // 13:22
    LocalTime time3 = LocalTime.of(14, 22, 31);
    System.out.println(time3); // 14:22:31
    LocalTime time4 = LocalTime.of(22, 43, 33, 422);
    System.out.println(time4); // 22:43:33.000000422
    // 根据分钟 构造 LocalTime 时间对象 超过最大分钟,会抛出 java.time.DateTimeException 异常
    LocalTime time5 = LocalTime.ofSecondOfDay(22324);
    System.out.println(time5); // 06:12:04
    // 根据纳秒构造LocalTime对象
    LocalTime time6 = LocalTime.ofNanoOfDay(1231);
    System.out.println(time6); // 00:00:00.000001231

    //===============================================================================
    // 3、获时,分,秒等
    //===============================================================================
    int hour = time1.getHour();
    int minute = time1.getMinute();
    int second = time1.getSecond();
    System.out.println("小时:" + hour + ",分钟:"
        + minute + ",秒数:" + second); // 小时:10,分钟:5,秒数:53

    //===============================================================================
    // 4、判断大于小于,排序,相差多少
    //===============================================================================
    // 判断时间1是否在时间2后
    boolean after = time1.isAfter(time2);
    System.out.println(after); // false
    // 判断时间1是否在时间2前
    boolean before = time1.isBefore(time2);
    System.out.println(before); // true
    // 排序比较,前者大于后者返回 1,否则 -1,相等 0
    int i = time1.compareTo(time2);
    System.out.println(i); // -1
    // 时间1和时间2相差多少小时,分钟,秒,大于为正数,小于为负数(坏处就是分跟分加减,秒跟秒加减)
    long betweenHours = ChronoUnit.HOURS.between(time1, time2);
    long betweenSeconds = ChronoUnit.SECONDS.between(time1, time2);
    long betweenMinutes = ChronoUnit.MINUTES.between(time1, time2);
    System.out.println("相差小时:" + betweenHours + " 分钟: " +
        betweenMinutes + " 秒数:" + betweenSeconds); // 相差小时:2 分钟: 178 秒数:10707

    //===============================================================================
    // 5、时间的加减,修改
    //===============================================================================
    // 加两小时,减去传入负数即可
    LocalTime time7 = time3.plusHours(2);
    System.out.println(time7); // 16:22:31
    // 减去10分钟
    LocalTime time8 = time3.plusMinutes(-10);
    System.out.println(time8); // 14:12:31
    // 加上30秒
    LocalTime time9 = time3.plusSeconds(30);
    System.out.println(time9); // 14:23:01
    // 修改小时
    LocalTime time10 = time3.withHour(23);
    System.out.println(time10); // 23:22:31
    // 修改分钟
    LocalTime time11 = time3.withMinute(11);
    System.out.println(time11); // 14:11:31
    // 修改秒数
    LocalTime time12 = time3.withSecond(50);
    System.out.println(time12); // 14:22:50


  //===============================================================================
    // 6、两个时间之间的相差秒数,小时
    
 //===============================================================================
    Duration duration = Duration.between(time3, time12);
    long days = duration.toDays();
    long hours = duration.toHours();
    long millis = duration.toMillis()/1000;

  }
}

LocalDateTime

是一个不可变的日期时间对象,代表日期时间,年-月-日-时-分-秒,线程安全。

public class LocalDateTimeDemo {

  public static void main(String[] args) {
    //===============================================================================
    // 1、获取当前日期时间
    //===============================================================================
    LocalDateTime localDateTime = LocalDateTime.now();
    System.out.println(localDateTime); // 2018-07-26T14:47:44.144

    //===============================================================================
    // 2、构造日期时间
    //===============================================================================
    CharSequence text = "2007-12-03T10:15:30";
    // 从一个文本字符串 获得 LocalDateTime实例
    LocalDateTime dateTime1 = LocalDateTime.parse(text);
    System.out.println(dateTime1); // 2007-12-03T10:15:30

    //===============================================================================
    // 3、获取,年,月,日,时等等
    //===============================================================================
    int dayOfMonth = localDateTime.getDayOfMonth();
    DayOfWeek dayOfWeek = localDateTime.getDayOfWeek();
    int dayOfYear = localDateTime.getDayOfYear();
    int hour = localDateTime.getHour();
    Month month = localDateTime.getMonth();
    int year = localDateTime.getYear();
    System.out.println(year + "年" + month.toString() + "月" + dayOfMonth + "日" +
        hour + "时" + "|||" + dayOfWeek + "|||" + dayOfYear);
    // 2018年JULY月31日9时|||TUESDAY|||212
  }
}

YearMonth

是一个不变的日期时间对象,表示一年和一个月的组合。 可以获得可以从年和月派生的任何字段,例如四分之一年份。类线程安全

public class YearMonthDemo {

  public static void main(String[] args) {
    //===============================================================================
    // 1、获取当前年月
    //===============================================================================
    YearMonth yearMonth = YearMonth.now();
    System.out.println(yearMonth); // 2018-07

    //===============================================================================
    // 2、构造年月
    //===============================================================================
    CharSequence text = "2018-01";
    YearMonth yearMonth1 = YearMonth.parse(text);
    System.out.println(yearMonth1); // 2018-01
    CharSequence text2 = "2018年02月";
    YearMonth yearMonth2 = YearMonth.parse(text2, DateTimeFormatter.ofPattern("yyyy年MM月"));
    System.out.println(yearMonth2); // 2018-02

    //===============================================================================
    // 3、获取,年,月
    //===============================================================================
    int year = yearMonth.getYear();
    Month month = yearMonth.getMonth();
    int monthValue = yearMonth.getMonthValue();
    System.out.println(year + "年" + monthValue + "月" + "mouth对象-》" + month);
    // 2018年7月mouth对象-》JULY

    //===============================================================================
    // 4、判断大于小于,排序,判断是否闰年
    //===============================================================================
    System.out.println(yearMonth.isAfter(yearMonth1));  // true
    System.out.println(yearMonth.isBefore(yearMonth1)); // false
    System.out.println(yearMonth.isLeapYear()); // 是否闰年 false
    System.out.println(yearMonth.compareTo(yearMonth1)); // 6 (这里为什么是6 上面有详解)

    //===============================================================================
    // 5、年月的加减,设置年月
    //===============================================================================
    YearMonth yearMonth3 = yearMonth.plusMonths(1);
    System.out.println(yearMonth3); // 2018-08
    YearMonth yearMonth4 = yearMonth.plusYears(-1);
    System.out.println(yearMonth4); // 2017-07
    YearMonth yearMonth5 = yearMonth.withMonth(5);
    System.out.println(yearMonth5); // 2018-05
    YearMonth yearMonth6 = yearMonth.withYear(2000);
    System.out.println(yearMonth6); // 2000-07
  }

}

MonthDay

是一个不变的日期时间对象,代表一年和一个月的组合。 可以获得可以从月和日派生的任何字段,线程安全。

public class MonthDayDemo {

  public static void main(String[] args) {
    //===============================================================================
    // 1、获取当前月日
    //===============================================================================
    MonthDay monthDay = MonthDay.now();
    System.out.println(monthDay); // --07-31

    //===============================================================================
    // 2、构造月日
    //===============================================================================
    CharSequence text1 = "--03-01";
    MonthDay monthDay1 = MonthDay.parse(text1);
    System.out.println(monthDay1); // --03-01
    CharSequence text2 = "11月23日";
    MonthDay monthDay2 = MonthDay.parse(text2, DateTimeFormatter.ofPattern("MM月dd日"));
    System.out.println(monthDay2); // --11-23
    MonthDay monthDay3 = MonthDay.of(2, 3);
    System.out.println(monthDay3); // --02-03
    MonthDay monthDay4 = MonthDay.of(Month.AUGUST, 22);
    System.out.println(monthDay4); // --08-22

    //===============================================================================
    // 3、获取 月,日
    //===============================================================================
    int monthValue = monthDay.getMonthValue();
    Month month = monthDay.getMonth();
    int dayOfMonth = monthDay.getDayOfMonth();
    System.out.println(monthValue + "月" + dayOfMonth + "日" + "月份-》" + month);
    // 7月31日月份-》JULY

    //===============================================================================
    // 4、判断大于小于,排序
    //===============================================================================
    System.out.println(monthDay.isAfter(monthDay1)); // true
    System.out.println(monthDay.isBefore(monthDay1)); // false
    System.out.println(monthDay.compareTo(monthDay1)); // 4 (这里为什么是4,上面有详解)

  }

}

常见需求

针对业务上常见的需求,日期处理,这里给出了示范,根据示范举一反三,我想可以解决99%以上的日期操作。

public class NewTimeDemo {

  public static void main(String args[]) {
    // 输入 20180101
    CharSequence str = "20040201";
    // BASIC_ISO_DATE -》ISO日期格式化,格式或解析无偏移的日期,如“20111203”。
    LocalDate localDate = LocalDate.parse(str, BASIC_ISO_DATE);

    //===============================================================================
    // 1、 这个月月末
    //===============================================================================
    System.out.println("本月月末是:" + localDate.with(TemporalAdjusters.lastDayOfMonth()));
    // 本月月末是:2004-02-29

    //===============================================================================
    // 2、 下个月月初
    //===============================================================================
    System.out.println("下月月初是:" + localDate.with(TemporalAdjusters.firstDayOfNextMonth()));
    //下月月初是:2004-03-01

    //===============================================================================
    // 3、 下个月月末
    //===============================================================================
    System.out.println("下月月末是:" + localDate.with(TemporalAdjusters.firstDayOfNextMonth())
        .with(TemporalAdjusters.lastDayOfMonth()));
    // 下月月末是:2004-03-31

    //===============================================================================
    // 4、 给年月,计算当月天数
    //===============================================================================
    CharSequence str2 = "200102";
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMM");
    YearMonth ym = YearMonth.parse(str2, dateTimeFormatter);
    System.out.println(ym.lengthOfMonth()); // 28

    //===============================================================================
    // 5、 日期加减天数
    //===============================================================================
    System.out.println(localDate.plusDays(-1)); // 2004-01-31

    //===============================================================================
    // 6、 日期加减月份
    //===============================================================================
    System.out.println(localDate.plusMonths(-1)); // 2004-01-01
    System.out.println(localDate.plusMonths(1)); // 2004-03-01

    //===============================================================================
    //  7、 传参月份,日子,输出修改后的
    //===============================================================================
    try {
      System.out.println(localDate.withMonth(2).withDayOfMonth(2));
      // 2004-02-02
    } catch (DateTimeException exception) {
      System.out.println("输入日期异常!");
    }
    System.out.println(localDate.withDayOfMonth(1));
    // 2004-02-01

    //===============================================================================
    //  8、 小于15日,输出该月15日,否则输出下月1日
    //===============================================================================
    System.out.println("--------------------");
    if (localDate.getDayOfMonth() < 15) {
      System.out.println(localDate.withDayOfMonth(15));
    } else {
      System.out.println(localDate.with(TemporalAdjusters.firstDayOfNextMonth()));
    }
    // 2004-02-15

  }

}

总结

1、构造对应时间对象,使用 .now()  .parse() ;

2、获取相关时间单位,使用 .get()  .lengthOf..() ;

3、判断、比较,使用 .is...()    .compareTo() ;

4、日期加减,使用 .plus() ; 

5、其他计算,使用 .with()    .with(TemporalAdjusters.......()) ;

 

你可能感兴趣的:(java)