1、前言

Java8之前处理日期一直是Java程序员比较头疼的问题,从Java 8之后,Java里面添加了许多的新特性,其中一个最常见也是最实用的便是日期处理的类——LocalDate。LocalDate是一种更为高效的日期类,比起Date的复杂具有相当高的简洁性,吸取了企业级别的joda.time时间处理的优点,避免了传统的Date和Calendar复合起来计算的难处。

新增的日期常用的用这三个:

  • java.time.LocalDate:只对年月日做出处理
  • java.time.LocalTime:只对时分秒纳秒做出处理
  • java.time.LocalDateTime :同时可以处理年月日和时分秒

2、LocalDate、LocalTime、LocalDateTime

LocalDate:代表IOS格式(yyyy-MM-hh)的日期,不包含具体时间的日期,比如2014-01-14。它可以用来存储生日,周年纪念日,入职日期等。

LocalTime:它代表的是不含日期的时间;

LocalDateTime:它包含了日期及时间,不过还是没有偏移信息或者说时区,比较常用;

它们三者共同特点:

  • 相比于前面的Date和Calendar,他们是线程安全的;
  • 它们是不可变的日期时间对象;

常用方法:

  • now() 、 now(Zoneld zone):静态方法,根据当前时间创建对象 、 指定时区的对象
  • of() :静态方法,根据指定日期,时间创建对象
  • getDayOfMonth():获得月份天数(1-31)
  • getDayOfYear():获取年份天数(1-366)
  • getDayOfWeek():获得星期几
  • getYear():获得年份
  • getMonth() 、 getMonthValue(): 获得月份(返回枚举值如:January) 、 返回数字(1-12)
  • getHour()、getMinute()、getSecond():获得当前对象的时、分、秒
  • withDayOfMonth()、withDayOfYear()、withMonth()、withYear():将月份天数、年份天数、月份、年份修改为指定的值并且返回新的对象,因为LocalDate等是不变性的
  • plusDays()、plusWeeks()、plusMonths()、plusYears()、plusHours():向当前对象添加几天、几周、几个月、几年,几小时
  • minusDays()、minusWeeks()、minusMonths()、minusYears()、minusHours():从当前对象减去几月、几周、几个月、几年、几小时
  • isLeapYear():判断是否为闰年
  • isBefore、isEqual、isAfter:检查日期是否在指定日期前面,相等,后面

由于LocalDate的API与LocalTime、LocalDateTime大都是通用的,所有后面两个的就不展示了。

方法使用举例:

 //now():获取当前日期
 LocalDate localDate=LocalDate.now();
 LocalTime localTime=LocalTime.now();
 LocalTime localTime1= LocalTime.now().withNano(0); // 这个是不带毫秒的
 LocalDateTime localDateTime=LocalDateTime.now();
 System.out.println("日期:"+localDate);
 System.out.println("时间:"+localTime);
 System.out.println("时间不带毫秒:"+localTime1);
 System.out.println("日期时间:"+localDateTime);

 //of():设置指定的年月日时分秒,没有偏移量
 System.out.println("-----------");
 LocalDateTime localDateTime2=LocalDateTime.of(2020, 04, 04, 18, 48, 56);
 System.out.println("设置的时间为:"+localDateTime2);

 //getXXX:获取相关的属性
 System.out.println("-----------");
 System.out.println("这年的第几天:"+localDateTime.getDayOfYear());
 System.out.println("这月的第几天:"+localDateTime.getDayOfMonth());
 System.out.println("这月的第几天:"+localDateTime.getDayOfWeek());
 System.out.println("月份为:"+localDateTime.getMonth());
 System.out.println("月份为:"+localDateTime.getMonthValue());
 System.out.println("小时为:"+localDateTime.getHour());

 //withXXX:设置相关的属性,体现了不可变性,修改后返回了新的对象
 LocalDateTime localDateTime3=localDateTime.withDayOfMonth(22);
 System.out.println("当前的时间:"+localDateTime);
 System.out.println("修改月份后:"+localDateTime3);

 LocalDateTime localDateTime4=localDateTime.withHour(14);
 System.out.println("当前的时间:"+localDateTime);
 System.out.println("修改小时后:"+localDateTime4);

 //plusXXX:增加相关属性
 LocalDateTime localDateTime5=localDateTime.plusDays(10);
 System.out.println("当前时间:"+localDateTime);
 System.out.println("相加之后:"+localDateTime5);

 //minusXXX:减少相关属性
 LocalDateTime localDateTime6=localDateTime.minusDays(10);
 System.out.println("当前时间:"+localDateTime);
 System.out.println("相减之后:"+localDateTime6);

LocalDate ,LocalTime ,LocalDateTime 它们之间的互相转换: 

 /**
  * LocalDate ,LocalTime,LocalDateTime 互相转换
  */
 @Test
 public void test5(){
     String date = "2020-7-12";
     String time = "15:51:30";
     LocalDate localDate = LocalDate.parse(date);
     LocalTime localTime = LocalTime.parse(time);

     LocalDateTime localDateTime = LocalDateTime.of(2020, 7, 13, 16, 01, 30, 888);
     LocalDateTime localDateTime1 = LocalDateTime.of(localDate, localTime);

     //localDateTime-->LocalDate,LocalTime
     LocalDate localDate1 = localDateTime.toLocalDate();
     LocalTime localTime1 = localDateTime.toLocalTime();

     // LocalDate,LocalTime --> LocalDateTime
     LocalDateTime localDateTime2 = localDate.atTime(16, 02, 30);
     LocalDateTime localDateTime3 = localTime.atDate(localDate);

 }

3、瞬时(Instant)

Instant类:时间线上的一个瞬时点,设计初衷是为了便于机器使用,不提供人类意义上的时间单位,获取当前时刻的时间戳;它只是简单的从1970年1月1日0时0分0秒(UTC)开始的秒数。

常用方法:

  • now():静态方法,返回默认的UTC时区的Instant类的对象
  • atOffset(ZoneOffset offset):将此瞬间与偏移组合起来创建一个OffsetDateTime
  • toEpochMilli():返回1970-01-01 00:00:00到当前的毫秒数,即时间戳
  • ofEpochMilli(long epochMilli):静态方法,返回在1970-01-01 00:00:00基础加上指定毫秒数之后的Instant类的对象
  • ofEpochSecond(long epochSecond):静态方法,返回在1970-01-01 00:00:00基础加上指定秒数之后的Instant类的对象

方法使用举例:

 @Test
 public void testInstant() {
     //now():获取标准时间,即本初子午线的时间,没有偏移量
     Instant instant = Instant.now();
     System.out.println(instant);

     //atOffset:添加偏移量,北京在东八区,时区加八即为北京时间
     OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
     System.out.println(offsetDateTime);

     //toEpochMilli:获取1970-01-01 00:00:00 开始的毫秒;类似Date的getTime
     long epochMilli = instant.toEpochMilli();
     System.out.println(epochMilli);

     //ofEpochMilli:通过给定的毫秒数,获取Instant实例;类似Date(long millis)
     Instant ofEpochMilli = Instant.ofEpochMilli(1562384592201L);
     System.out.println(ofEpochMilli);
 }

4、日期间隔,持续时间 (Period 和 Duration)

Java 8 中还引入的两个与日期相关的新类:Period 和 Duration。两个类分别表示时间量或两个日期之间的差,两者之间的差异为:Period基于日期值,而Duration基于时间值。

实例:

     @Test
     public void testDurationAndPeriod(){
         //Duration
         LocalDate date1 = LocalDate.of(2020, 7, 6);
         LocalDate date2 = LocalDate.of(2025, 9, 10);
         LocalTime time1 = LocalTime.of(15, 7, 50);
         LocalTime time2 = LocalTime.of(17, 8, 53);
         LocalDateTime dateTime1 = LocalDateTime.of(2020, 5, 12, 14, 22, 28);
         LocalDateTime dateTime2 = LocalDateTime.of(2024, 5, 12, 14, 22, 28);
         Instant instant1 = Instant.ofEpochSecond(1);
         Instant instant2 = Instant.now();
         Duration d1 = Duration.between(time1, time2);
         Duration d2 = Duration.between(dateTime1, dateTime2);
         Duration d3 = Duration.between(instant1, instant2);
         // 这里会抛异常java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Seconds
         //需要使用Period类进行操作日期
         //Duration d4 = Duration.between(date1, date2);
         System.out.println("LocalTime持续秒数:" + d1.getSeconds());
         System.out.println("LocalDateTime持续秒数:" + d2.getSeconds());
         System.out.println("Instant持续秒数" + d3.getSeconds());

         //Period
         Period period=Period.between(date1, date2);
         System.out.println(period.getYears());
         System.out.println(period.getMonths());
         System.out.println(period.getDays());
         System.out.println(period.toTotalMonths());
     }

5、日期校正器TemporalAdjusters

到现在你所看到的所有日期操作都是相对比较直接的。有的时候,你需要进行一些更加 复杂的操作,比如,将日期调整到下个周日、下个工作日,或者是本月的最后一天。这时,你可以使用重载版本的with方法,向其传递一个提供了更多定制化选择的TemporalAdjusters对象, 更加灵活地处理日期。对于最常见的用例,日期和时间API已经提供了大量预定义的 TemporalAdjusters。你可以通过TemporalAdjusters类的静态工厂方法访问它们,如下所示:

下面是TemporalAdjusters类中的方法:

  • dayOfWeekInMonth(int ordinal,DayOfWeek dayOfWeek):返回一个新的日期,它的值为同一个月中每一周的第几天
  • firstDayOfMonth():返回一个新的日期,它的值为当月的第一天
  • firstDayOfNextMonth():返回一个新的日期,它的值为下月的第一天
  • firstDayOfNextYear():返回一个新的日期,它的值为明年的第一天
  • firstDayOfYear():返回一个新的日期,它的值为当年的第一天
  • firstInMonth(DayOfWeek dayOfWeek):返回一个新的日期,它的值为同一个月中,第一个符合星期几要求的值
  • lastDayOfMonth():返回一个新的日期,它的值为当月的最后一天
  • lastDayOfNextMonth():返回一个新的日期,它的值为下月的最后一天
  • lastDayOfNextYear():返回一个新的日期,它的值为明年的最后一天
  • lastDayOfYear():返回一个新的日期,它的值为今年的最后一天
  • lastInMonth(DayOfWeek dayOfWeek):返回一个新的日期,它的值为同一个月中,最后一个符合星期几要求的值
  • next(DayOfWeek dayOfWeek)、previous(DayOfWeek dayOfWeek):返回一个新的日期,并将其值设定为日期调整后或者调整前,第一个符合指定星期几要求的日期
  • nextOrSame(DayOfWeek dayOfWeek)、previousOrSame(DayOfWeek dayOfWeek):返回一个新的日期,并将其值设定为日期调整后或者调整前,第一个符合指定星期几要求的日期,如果该日期已经符合要求,直接返回该对象

方法使用举例:

 @Test
 public void testTemporalAdjusters(){
     //dayOfWeekInMonth:返回这个月第二周星期二的日期
     LocalDate localDate1=LocalDate.of(2020,9,15);
     LocalDate localDate2 = localDate1.with(TemporalAdjusters.dayOfWeekInMonth(2, DayOfWeek.TUESDAY));
     System.out.println("默认时间:"+localDate1);
     System.out.println("更改时间:"+localDate2);

     //firstDayOfMonth():这个月第一天
     System.out.println("---------");
     LocalDate localDate3=localDate1.with(TemporalAdjusters.firstDayOfMonth());
     System.out.println("默认时间:"+localDate1);
     System.out.println("更改时间:"+localDate3);

     //lastDayOfMonth():这个月最后一天
     System.out.println("---------");
     LocalDate localDate4=localDate1.with(TemporalAdjusters.lastDayOfMonth());
     System.out.println("默认时间:"+localDate1);
     System.out.println("更改时间:"+localDate4);

     //nextOrSame():获取周2时间,如果当前时间刚好是星期2,那么就返回当前时间
     System.out.println("---------");
     LocalDate localDate5 = localDate1.with(TemporalAdjusters.nextOrSame(DayOfWeek.TUESDAY));
     System.out.println("默认时间:"+localDate1);
     System.out.println("更改时间:"+localDate5);
 }

运行结果:

6、Java 8日期解析和格式化(DateTimeFormatter)

之前格式化有SimpleDateFormat和DateFormat,但是它们两者都是线程不安全的!啥情况下会有这样的问题呢?如果我们为了实现日期转换这样的工具,每次都new一个对象,但是用完了就不用了,就造成了浪费,为此我们会将它写成单例的,但是单例的同时,一个对象供多个线程使用的时候,就会出现线程安全的问题。这个时候就需要这个新的jdk8出的DateTimeformatter这个类。
由字符串转为日期的方法:

如果是默认的格式,yyyy-MM-dd 这种日期格式字符串,直接用LocalDate.parse()进行转换就行了,相对应的时间也是。既有时间又有日期的用DateTimeformatte这个类就行。

 String time="2019-02-16";
 LocalDate localDate=LocalDate.parse(time);
 System.out.println(localDate);

有时间有日期:

 String datetime1="2019-05-24 18:15:56";
 DateTimeFormatter formatter1=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
 LocalDateTime localDateTime1=LocalDateTime.parse(datetime1,formatter1);
 System.out.println(localDateTime1);

 或者:
 String datetime2="2019-05-24 18:15:56";
 DateTimeFormatter formatter2=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
 TemporalAccessor parse = formatter2.parse(datetime2);
 LocalDateTime localDateTime=LocalDateTime.from(parse);
 System.out.println(localDateTime);

由日期转为字符串的方法:

  • 如果是LocalDate这种标准格式的,直接toString就可以了,
  • 如果是LocalTime这种格式的,toString会附带纳秒值21:06:30.760163, 这个时候你可以使用日期格式器,或者这样 LocalTime time = LocalTime.now().withNano(0),把纳秒直接清0.
  • 如果是LocalDateTime,这个时候是需要一个日期转换器的。才能由时间+日期->想要的时间,
 LocalDate localDate=LocalDate.now();
 System.out.println(localDate.toString());

 DateTimeFormatter formatter=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
 LocalDateTime localDateTime=LocalDateTime.now();
 String result=localDateTime.format(formatter);
 System.out.println(result);

7、JDBC中对应的日期

最新JDBC映射将把数据库的日期类型和Java 8的新类型关联起来:

SQL -> Java

---------------------

date -> LocalDate

time -> LocalTime

timestamp -> LocalDateTime

8、小结

这次主要学习了Java8中新的日期处理类

  1. LocalDate、LocalTime、LocalDateTime处理日期时间都非常的方便,而且它们是线程安全的,
  2. 新版的日期和时间API中,日期和时间对象是不可变的。
  3. LocalDate日期是一个便于使用的日期类,线程安全,Date类比较复杂,时间计算麻烦。
  4. DateTimeFormatter的使用也安全,方便。以后用它来代替SimpleDateFormat
  5. TemporalAdjuster 让你能够用更精细的方式操纵日期,不再局限于一次只能改变它的 一个值,并且你还可按照需求定义自己的日期转换器
  6. JDBC的TimeStamp类和LocalDateTime的转换也很方便,提供了相应的方法。
  7. 使用的时候,日期必须是标准的yyyy-MM-dd格式,比如1月必须写成01,不然会报错。

更多用例查看此文: https://www.cnblogs.com/comeboo/p/5378922.html

夯实Java基础(十四)——Java8新的日期处理类的更多相关文章

  1. Java基础20:Java8新特性终极指南

    更多内容请关注微信公众号[Java技术江湖] 这是一位阿里 Java 工程师的技术小站,作者黄小斜,专注 Java 相关技术:SSM.SpringBoot.MySQL.分布式.中间件.集群.Linux ...

  2. 对Java8新的日期时间类的学习(一)

    引用自Java译站http://it.deepinmind.com/java/2015/03/17/20-examples-of-date-and-time-api-from-Java8.html 除 ...

  3. Java基础(十四)--装箱、拆箱详解

    Java中基本数据类型都有相对应的包装类 什么是装箱?什么是拆箱? 在Java SE5之前,Integer是这样初始化的 Integer i = new Integer(10); 而在从Java SE ...

  4. 夯实Java基础(四)——面向对象之多态

    1.多态介绍 面向对象三大特征:封装.继承.多态.多态是Java面向对象最核心,最难以理解的内容.从一定角度来看,封装和继承几乎都是为多态而准备的. 多态就是指程序中定义的引用变量所指向的具体类型和通 ...

  5. java基础(十四)-----详解匿名内部类——Java高级开发必须懂的

    在这篇博客中你可以了解到匿名内部类的使用.匿名内部类要注意的事项.匿名内部类使用的形参为何要为final. 使用匿名内部类内部类 匿名内部类由于没有名字,所以它的创建方式有点儿奇怪.创建格式如下: n ...

  6. 对Java8新的日期时间类的学习(二)

    示例11 在Java中如何判断某个日期是在另一个日期的前面还是后面 这也是实际项目中常见的一个任务.你怎么判断某个日期是在另一个日期的前面还是后面,或者正好相等呢?在Java 8中,LocalDate ...

  7. Java8新特性-日期相关类操作

    JDK8以前使用SImpleDateFormate类格式化日期,因为在SImple DateFormate中存在Calendar实例引用,而在caleander中得establish中存在clear( ...

  8. 夯实Java基础系列目录

    自进入大学以来,学习的编程语言从最初的C语言.C++,到后来的Java,. NET.而在学习编程语言的同时也逐渐决定了以后自己要学习的是哪一门语言(Java).到现在为止,学习Java语言也有很长一段 ...

  9. 夯实Java基础(二十二)——Java8新特性之Lambda表达式

    1.前言 Java 8于14年发布到现在已经有5年时间了,经过时间的磨练,毫无疑问,Java 8是继Java 5(发布于2004年)之后的又一个非常最重要的版本.因为Java 8里面出现了非常多新的特 ...

随机推荐

  1. Fiddler如何过滤无用的链接

    场景:现在是移动端的天下,测试过程中,抓包工具肯定必不可少,如何使用这里就不赘述,这里给大家讲述下如何过滤那些没有的链接,js ,png等无用的信息 工具:fiddler-use Filters功能: ...

  2. asyncio系列之sleep()实现

    先来看个例子,自己实现的模拟耗时操作 例1 import types import select import time import socket import functools class Fu ...

  3. MyBatis 基础搭建及架构概述

    目录 MyBatis 是什么? MyBatis 项目构建 MyBatis 整体架构 接口层 数据处理层 基础支持层 MyBatis 是什么? MyBatis是第一个支持自定义SQL.存储过程和高级映射 ...

  4. Java线程池原理浅析

    什么是线程池? 为了避免频繁重复的创建和销毁线程,我们可以让这些线程进行复用,在线程池中,总会有活跃的线程在占用,但是线程池中也会存在没有占用的线程,这些线程处于空闲状态,当有任务的时候会从池子里面拿 ...

  5. scrapy基础知识之 CrawlSpiders:

    通过下面的命令可以快速创建 CrawlSpider模板 的代码: scrapy genspider -t crawl spidername xx.com LinkExtractors class sc ...

  6. 网络下载器 迅雷大众版 v7.9.42.5050 精简绿色版

    下载地址:点我 基本介绍 迅雷大众版是一款采用了先进的超线程技术基于网格原理,能够将存在于第三方服务器和计算机上的数据文件进行有效整合,通过这种先进的超线程技术,用户能够以更快的速度从这些第三方节点平 ...

  7. 基于SpringBoot的Web API快速开发基础框架

    其实还是很因为懒,才会有这个案例项目的产生,每次开启一个终端的小服务都要整理一次框架,造成重复的.不必要的.缺乏创造性的劳动,SO,本着可以用.用着简单的原则上传代码到Github,希望有需要的朋友直 ...

  8. 有趣的PHP一句话

    今天看到如下图所示的PHP一句话,觉得挺有意思. 代码如下: <?=~$_='$<>/'^'{{{{';echo $_;@${$_}[_](@${$_}[__]);?> 效果图 ...

  9. ASP.NET 前端数据绑定---<%#%>及Eval()的使用

    ASP.NET 前端html代码中会经常出现的<%%>的代码,里面的文本其实就是不能直接输出到客户端浏览器的文本,是需要服务器解释的. 在ASP中,<%%>里面的文本是vbsc ...

  10. Quartus ii调试技巧_01

    前几天李主任跟我分享了一些特别好用的调试技巧: 1)System Sources and Probes Editor---类似于人为设置触发条件,创建虚拟按键等功能,这段时间一直在做一个电机的驱动,板 ...