Java8时间日期处理新特性

简介

伴随lambda表达式、streams以及一系列小优化,Java 8 推出了全新的日期时间API。Java处理日期、日历和时间的不足之处:将 java.util.Date 设定为可变类型,以及 SimpleDateFormat 的非线程安全使其应用非常受限。然后就在 java8 上面增加新的特性。全新API的众多好处之一就是,明确了日期时间概念,例如:瞬时(instant)、长短(duration)、日期、时间、时区和周期。同时继承了Joda 库按人类语言和计算机各自解析的时间处理方式。不同于老版本,新API基于ISO标准日历系统,java.time包下的所有类都是不可变类型而且线程安全。

关键类

Instant:瞬时实例。

LocalDate:本地日期,不包含具体时间 例如:2014-01-14 可以用来记录生日、纪念日、加盟日等。

LocalTime:本地时间,不包含日期。

LocalDateTime:组合了日期和时间,但不包含时差和时区信息。

ZonedDateTime:最完整的日期时间,包含时区和相对UTC或格林威治的时差

实际应用

获取当前时间的对象

  1. LocalDateTime localDateTime = LocalDateTime.now();
  2. Date date = new Date();

localDateTime相比Date更像是一个工具类,就是为了时间操作使用。其构造方法是私有的

从字符串中解析

字符串 2019-01-11 解析成时间对象

  1. String str = "2019-01-11";
  2. DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
  3. LocalDate localDate = LocalDate.parse(str, formatter);
  4.  
  5. SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
  6. try {
  7.     Date date = simpleDateFormat.parse(str);
  8. } catch (ParseException e) {
  9.     e.printStackTrace();
  10. }

DateTimeFormatter的包路径是java.time.format和LocalDate一样在java.time下面,而SimpleDateFormat和Date是不同的。所以当判断引入路径的时候更容易判断。
当解析失败的时候,两个异常的抛出不一样,DateTimeFormatter抛出的是DateTimeParseException,继承自RuntimeException,而ParseException明显继承的是Exception。
个人感觉这个思路是,前者如果抛出异常那就是编程上错误,而后者则是的程序代码的不稳定性。更倾向于第一种的异常设计,应该加强对入参的检测判断,而不是通过捕获异常去处理入参的错误。(类似NumberFormatException)

LocalDate比Date更强的初始化时间

Date 设置某个日期,基本上3个方式,时间戳/Calendar/字符串解析。相对的LocalDate就简单很多

  1. LocalDate.of(2019,1,12);

时间戳的转换

LocalDate时间戳的转换不如Date直接。主要因为LocalDate本身是没有时区的。

时间戳传LocalDateTime

  1. long timestamp = System.currentTimeMillis();
  2. Instant instant = Instant.ofEpochMilli(timestamp);
  3. LocalDateTime.ofInstant(instant, ZoneId.systemDefault());

LocalDateTime转时间戳

  1. LocalDateTime dateTime = LocalDateTime.now();
  2. dateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
  3. dateTime.toInstant(ZoneOffset.of("+08:00")).toEpochMilli();
  4. dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();

和Date互转

  1. import java.time.Instant;
  2. import java.util.Date;
  3.  
  4. public class Main {
  5.   public static void main(String[] args) {
  6.     Date  dt =  new Date(); 
  7.     System.out.println("Date: "  + dt);
  8.  
  9.     Instant in = dt.toInstant(); 
  10.     System.out.println("Instant: "  + in);
  11.  
  12.     Date  dt2  = Date.from(in); 
  13.     System.out.println("Date: "  + dt2);
  14.   }
  15. }

更好的理解和操作方式

Date、Calendar的操作,例如设置月份,day of week 的使用都不符合常规,例如1月的定义是0,周一是0。1号是0,相对于的 LocalDate就比较友好。例如DayOfWeek是枚举类型能更直观的使用

另外日期和时间的计算可以直接进行加减和比较,如使用'加'的示例:

而Calendar操作日期则是使用get,set方法很不友好如:

Calendar cal = Calendar.getInstance();

cal.set(Calendar.MONTH, cal.get(Calendar.MONTH) + 1)

线程安全性比较

Java8提供的日期处理API LocalDate 等系列都是线程安全的,每一个字段都用了final关键字了,所以进行操作后都是返回新的copy对象

而Date线程不安全,get,set在多线程的时候容易出现问题,不过set方法已经标注@Deprecated废弃了。当然不是因为线程安全问题废弃的,是因为有了更好的替代

SimpleDateFormat的线程安全性

在一定负载情况下,SimpleDateFormat会出问题的。当然SimpleDateFormat线程不安全应该人尽皆知的,但依然有不安全的使用,但每次使用都new一个实例,当负载大的时候也不好。

Java8时间常用计算实例

  1. import java.time.Clock;
  2. import java.time.Instant;
  3. import java.time.LocalDate;
  4. import java.time.LocalDateTime;
  5. import java.time.LocalTime;
  6. import java.time.Month;
  7. import java.time.MonthDay;
  8. import java.time.OffsetDateTime;
  9. import java.time.ZoneOffset;
  10. import java.time.Period;
  11. import java.time.YearMonth;
  12. import java.time.ZoneId;
  13. import java.time.ZonedDateTime;
  14. import java.time.format.DateTimeFormatter;
  15. import java.time.temporal.ChronoUnit;
  16. import java.util.Date;
  17.  
  18. public class DateTest {
  19.     //获取今天的日期
  20.     public void getCurrentDate(){
  21.         LocalDate today = LocalDate.now();
  22.         System.out.println("Today's Local date : " + today);
  23.         
     
  24.         //这个是作为对比
  25.         Date date = new Date();
  26.         System.out.println(date);
  27.     }
  28.     
     
  29.     //获取年、月、日信息
  30.     public void getDetailDate(){
  31.         LocalDate today = LocalDate.now();
  32.         int year = today.getYear();
  33.         int month = today.getMonthValue();
  34.         int day = today.getDayOfMonth();
  35.         System.out.printf("Year : %d  Month : %d  day : %d t %n", year, month, day);
  36.     }
  37.     
     
  38.     //处理特定日期
  39.     public void handleSpecilDate(){
  40.         LocalDate dateOfBirth = LocalDate.of(2018, 01, 21);
  41.         System.out.println("The specil date is : " + dateOfBirth);
  42.     }
  43.     
     
  44.     //判断两个日期是否相等
  45.     public void compareDate(){
  46.         LocalDate today = LocalDate.now();
  47.         LocalDate date1 = LocalDate.of(2018, 01, 21);
  48.         if(date1.equals(today)){
  49.             System.out.printf("TODAY %s and DATE1 %s are same date %n", today, date1);
  50.         }
  51.     }
  52.     
     
  53.     //处理周期性的日期
  54.     public void cycleDate(){
  55.         LocalDate today = LocalDate.now();
  56.         LocalDate dateOfBirth = LocalDate.of(2018, 01, 21);
  57.         MonthDay birthday = MonthDay.of(dateOfBirth.getMonth(), dateOfBirth.getDayOfMonth());
  58.         MonthDay currentMonthDay = MonthDay.from(today);
  59.         if(currentMonthDay.equals(birthday)){
  60.            System.out.println("Many Many happy returns of the day !!");
  61.         }else{
  62.            System.out.println("Sorry, today is not your birthday");
  63.         }
  64.     }
  65.     
     
  66.     //获取当前时间
  67.     public void getCurrentTime(){
  68.         LocalTime time = LocalTime.now();
  69.         System.out.println("local time now : " + time);
  70.     }
  71.     
     
  72.     //增加小时
  73.     public void plusHours(){
  74.         LocalTime time = LocalTime.now();
  75.         LocalTime newTime = time.plusHours(2); // 增加两小时
  76.         System.out.println("Time after 2 hours : " +  newTime);
  77.     }
  78.     
     
  79.     //如何计算一周后的日期
  80.     public void nextWeek(){
  81.         LocalDate today = LocalDate.now();
  82.         LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS);
  83.         System.out.println("Today is : " + today);
  84.         System.out.println("Date after 1 week : " + nextWeek);
  85.     }
  86.     
     
  87.     //计算一年前或一年后的日期
  88.     public void minusDate(){
  89.         LocalDate today = LocalDate.now();
  90.         LocalDate previousYear = today.minus(1, ChronoUnit.YEARS);
  91.         System.out.println("Date before 1 year : " + previousYear);
  92.         LocalDate nextYear = today.plus(1, ChronoUnit.YEARS);
  93.         System.out.println("Date after 1 year : " + nextYear);
  94.     }
  95.     
     
  96.     public void clock(){
  97.         // 根据系统时间返回当前时间并设置为UTC。
  98.         Clock clock = Clock.systemUTC();
  99.         System.out.println("Clock : " + clock);
  100.         // 根据系统时钟区域返回时间
  101.         Clock defaultClock = Clock.systemDefaultZone();
  102.         System.out.println("Clock : " + clock);
  103.     }
  104.     
     
  105.     //如何用Java判断日期是早于还是晚于另一个日期
  106.     public void isBeforeOrIsAfter(){
  107.         LocalDate today = LocalDate.now(); 
  108.  
  109.         LocalDate tomorrow = LocalDate.of(2018, 1, 29);
  110.         if(tomorrow.isAfter(today)){
  111.             System.out.println("Tomorrow comes after today");
  112.         }
  113.         LocalDate yesterday = today.minus(1, ChronoUnit.DAYS);
  114.         if(yesterday.isBefore(today)){
  115.             System.out.println("Yesterday is day before today");
  116.         }
  117.     }
  118.     
     
  119.     //时区处理
  120.     public void getZoneTime(){
  121.         //设置时区
  122.         ZoneId america = ZoneId.of("America/New_York");
  123.         LocalDateTime localtDateAndTime = LocalDateTime.now();
  124.         ZonedDateTime dateAndTimeInNewYork  = ZonedDateTime.of(localtDateAndTime, america );
  125.         System.out.println("现在的日期和时间在特定的时区 : " + dateAndTimeInNewYork);
  126.     }
  127.     
     
  128.     //使用 YearMonth类处理特定的日期
  129.     public void checkCardExpiry(){
  130.         YearMonth currentYearMonth = YearMonth.now();
  131.         System.out.printf("Days in month year %s: %d%n", currentYearMonth, currentYearMonth.lengthOfMonth());
  132.         YearMonth creditCardExpiry = YearMonth.of(2028, Month.FEBRUARY);
  133.         System.out.printf("Your credit card expires on %s %n", creditCardExpiry);
  134.     }
  135.     
     
  136.     //检查闰年
  137.     public void isLeapYear(){
  138.         LocalDate today = LocalDate.now();
  139.         if(today.isLeapYear()){
  140.            System.out.println("This year is Leap year");
  141.         }else {
  142.             System.out.println("2018 is not a Leap year");
  143.         }
  144.     }
  145.     
     
  146.     //计算两个日期之间的天数和月数
  147.     public void calcDateDays(){
  148.         LocalDate today = LocalDate.now();
  149.         LocalDate java8Release = LocalDate.of(2018, Month.MAY, 14);
  150.         Period periodToNextJavaRelease = Period.between(today, java8Release);
  151.         System.out.println("Months left between today and Java 8 release : "  + periodToNextJavaRelease.getMonths() );
  152.     }
  153.     
     
  154.     // 包含时差信息的日期和时间
  155.     public void ZoneOffset(){
  156.         LocalDateTime datetime = LocalDateTime.of(2018, Month.FEBRUARY, 14, 19, 30);
  157.         ZoneOffset offset = ZoneOffset.of("+05:30");
  158.         OffsetDateTime date = OffsetDateTime.of(datetime, offset);  
  159.         System.out.println("Date and Time with timezone offset in Java : " + date);
  160.     }
  161.     
     
  162.     // 获取时间戳
  163.     public void getTimestamp(){
  164.         Instant timestamp = Instant.now();
  165.         System.out.println("What is value of this instant " + timestamp);
  166.     }
  167.  
  168.     // 使用预定义的格式化工具去解析或格式化日期
  169.     public void formateDate(){
  170.         String dayAfterTommorrow = "20180210";
  171.         LocalDate formatted = LocalDate.parse(dayAfterTommorrow, DateTimeFormatter.BASIC_ISO_DATE);
  172.         System.out.printf("Date generated from String %s is %s %n", dayAfterTommorrow, formatted);
  173.     }
  174.     
     
  175.     public static void main(String[] args) {
  176.         DateTest dt = new DateTest();
  177.         dt.formateDate();
  178.     }
  179. }

总结

Java 8日期时间API的重点

1)提供了javax.time.ZoneId 获取时区。

2)提供了LocalDate和LocalTime类。

3)Java 8 的所有日期和时间API都是不可变类并且线程安全,而现有的Date和Calendar API中的java.util.Date和SimpleDateFormat是非线程安全的。

4)主包是 java.time,包含了表示日期、时间、时间间隔的一些类。里面有两个子包java.time.format用于格式化, java.time.temporal用于更底层的操作。

5)时区代表了地球上某个区域内普遍使用的标准时间。每个时区都有一个代号,格式通常由区域/城市构成(Asia/Tokyo),在加上与格林威治或 UTC的时差。例如:东京的时差是+09:00。

参考链接:

https://www.136.la/jingpin/show-15179.html

https://www.jianshu.com/p/4508d6976bb1

Java8时间日期处理新特性的更多相关文章

  1. 【java】JDK1.8时间日期库 新特性 所有java中时间Date的使用

    除了lambda表达式,stream以及几个小的改进之外,Java 8还引入了一套全新的时间日期API,在本篇教程中我们将通过几个简单的任务示例来学习如何使用java 8的这套API.Java对日期, ...

  2. Java8 时间日期类操作

    Java8 时间日期类操作 Java8的时间类有两个重要的特性 线程安全 不可变类,返回的都是新的对象 显然,该特性解决了原来java.util.Date类与SimpleDateFormat线程不安全 ...

  3. Java9都快发布了,Java8的十大新特性你了解多少呢?

    Java 9预计将于今年9月份发布,这是否会是一次里程碑式的版本,我们拭目以待.今天,我们先来复习一下2014年发布的Java 8的十大新特性. Java 8可谓是自Java 5以来最具革命性的版本了 ...

  4. java8的十大新特性

    推荐学习的博客: http://blog.csdn.net/renfufei/article/details/24600507/-------讲解的非常通俗易懂 http://blog.csdn.ne ...

  5. java8 时间日期操作包总结

  6. java8新特性学习1

    java8增加了不少新特性,下面就一些常见的新特性进行学习... 1.接口中的方法 2.函数式接口 3.Lambda表达式 4.java8内置的四大核心函数式接口 5.方法引用和构造器引用 6.Str ...

  7. 2020你还不会Java8新特性?

    Java8(1)新特性介绍及Lambda表达式 前言: 跟大娃一块看,把原来的电脑拿出来放中间看视频用 --- 以后会有的课程 难度 深入Java 8 难度1 并发与netty 难度3 JVM 难度4 ...

  8. 简单了解JAVA8的新特性

    JAVA8新特性会颠覆整个JAVA程序员的编程习惯 甚至如果您坚守JAVA7之前的编程习惯,今后你看比较年轻的程序员写的JAVA代码都会无法理解 所以为了保证不脱钩,我觉得有必要学习JAVA8的新特性 ...

  9. Java 8 新特性:日期处理

    1.  Java 8 日期处理新特性 Java 8基于ISO标准日期系统,提供了java.time包来处理时间日期,且该包下的所有类都是不可变类型而且线程安全. 2.  关键类 Instant:瞬时实 ...

  10. Java8新特性之Stream

    原文链接:http://ifeve.com/stream/ Java8初体验(二)Stream语法详解 感谢同事[天锦]的投稿.投稿请联系 tengfei@ifeve.com上篇文章Java8初体验( ...

随机推荐

  1. 【软件学习】如何将Typora中的本地图片上传到博客

    1. 配置方法 下载软件: 点击程序输入博客信息进行配置: 进行偏好设置: 2. 配置中出现的一些问题 解决方法:

  2. 前端ajax发送post 请求 json格式 springMVC报错415

    如标题所示 后端填坑日记 在使用springMVC的时候发现 后端使用@RequestBody注解会报错415 不支持的媒体类型 相信很多小伙伴都遇到过或者正在面临这个报错 提示错误:The serv ...

  3. 通过netty把百度地图API获取的地理位置从Android端发送到Java服务器端

    本篇记录我在实现时的思考过程,写给之后可能遇到困难的我自己也给到需要帮助的人. 写的比较浅显,见谅. 在写项目代码的时候,需要把Android端的位置信息传输到服务器端,通过Netty达到连续传输的效 ...

  4. 应用DriverManager类创建sqlserver数据库连接实例 JSP中使用数据库

    JSP中使用数据库 1.JDBC介绍 java数据库连接(java Database Connectivity ,JDBC)是一种用于执行SQL语句的JavaAPI ,由一组使用java编程语言编写的 ...

  5. JUC(3)

    文章目录 1.集合类不安全 2.在高并发情况下arraylist()并不安全 3.高并发下set并不安全 3.测试map(高并发情况下出现问题) 1.集合类不安全 2.在高并发情况下arraylist ...

  6. 第三方库openPyxl读取excel文件

    import openpyxl from openpyxl.worksheet.worksheet import Worksheet def openpyxl_read(): #1.打开文件 work ...

  7. 1.python基础使用

    1.git简介 git是一个免费的开源的分布式版本控制系统,可以快速高效的处理从小型到大型项目的所有事务 在实际工作中可以保留项目的所有版本,可以快速的实现版本的回滚和修改 git整体可以分为4个区域 ...

  8. Git配置和使用?Git你真的会用么?Git与SVN的主要区别

    1.Git环境配置    在学习Git之前,首先要知道什么是版本控制 1.1 版本控制:版本迭代.新的版本!版本管理器 版本控制是开发过程中用于管理我们的文件.目录或工程内容的修改内容,查看修改历史记 ...

  9. Vue 基础学习总结

    介绍 Vue.js 中文文档地址:https://cn.vuejs.org/guide/introduction.html#what-is-vue Vue.js 是什么 Vue (读音 /vjuː/, ...

  10. 2022春每日一题:Day 35

    题目:[NOI Online #1 提高组] 冒泡排序 看到范围这么大,求逆序对,有修改,估计也只能树状数组了,考查冒泡排序性质,排第i次冒泡排序,总逆序对个数会减少i的逆序对个数,然后交换两个数,他 ...