Java8 新特性之日期时间对象及一些其他特性

日期时间对象

关于日期时间的操作可以分为两种:

  • 转换:与字符串的互相转换,与时间戳的互相转换
  • 计算:计算两个时间点之间的间隔、时间点与时间段的计算(计算下周N、下个月D日、去年M月D日等等)

Java8 提供了三个类:LocalDateLocalTimeLocalDateTime,它们的形式如 2020-01-0112:30:002020-01-01 12:30:00

创建对象

获取类对象的方法非常非常简单

LocalDate now = LocalDate.now();
LocalDate ld = LocalDate.of(2019, 1, 1);
// 获取年月日
now.getYear();
now.getMonthValue(); // 如果你调用了 now.getMonth() ,那么它将返回给你一个大写的英文月份单词
now.getDayOfMonth();
// 顾名应该思义
getDayOfWeek();
getDayOfYear(); 

// 设置年月日
LocalDate ld1 = ld.withYear(2021);  // 2021-01-01
LocalDate ld2 = ld.withMonth(12);  // 2019-12-01
LocalDate ld3 = ld.withDayOfMonth(12); // 2019-12-12
// 你可能会纳闷,既然是设置,为什么不用单词 set 呢,而用 with
// 因为,set 操作一般是改变调用对象本身,没有返回值;
// 而 with 是在调用对象基础上另外创建一个新对象,设置好值后返回,没有改变调用对象

// 如果你是那个打破砂锅的孩子,你可能会问:为什么不能改变调用对象?
// 因为 LocalDate 是 final 修饰的(final 人称 Java 界的自宫之刀)
// 从物理的角度来讲,目前人类无法改变时间(穿越)

// 如果你有 ld.withMonth(13) 这种反人类历法的操作,当然是会抛出异常的

LocalTime 和 LocalDateTime 都有类似于 LocalDate 的方法,这里就不一一列举了(因为我感觉自己越来越像 api 文档了)

Java8 API 官方文档直通车

转换

日期时间对象 和 字符串 之间的互相转换:

// LocalDateTime 对象 -> 字符串
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime now = LocalDateTime.now();
String dateTimeStr = now.format(dtf);
System.out.println(dateTimeStr);

// 字符串 -> LocalDateTime 对象
String str = "2022-01-30 12:15:20";
LocalDateTime dateTime = LocalDateTime.parse(str, dtf);
System.out.println(dateTime);

DateTimeFormatter 类还提供一些现成的 formatter ,比如

DateTimeFormatter.BASIC_ISO_DATE ==> DateTimeFormatter.ofPattern("yyyyMMdd")
DateTimeFormatter.ISO_LOCAL_DATE ==> DateTimeFormatter.ofPattern("yyyy-MM-dd")
// 更多 formatter 可以 api 文档中查询

学习的本质,不在于记住哪些知识,而在于它触发了你的思考。—— 迈克尔·桑德尔

日期时间 和 时间戳 之间的互相转换:

// LocalDateTime 对象 -> 时间戳
LocalDateTime now = LocalDateTime.now();
// 获取系统默认时区
ZoneId systemDefaultZoneId = ZoneId.systemDefault();
Instant instant = now.atZone(systemDefaultZoneId).toInstant();
long timestamp = instant.toEpochMilli();
System.out.println(timestamp);

// 时间戳 -> LocalDateTime 对象
long timestamp2 = 1578919583784L;
Instant instant2 = Instant.ofEpochMilli(timestamp2);
LocalDateTime dateTime2 = LocalDateTime.ofInstant(instant2, systemDefaultZoneId);
System.out.println(dateTime2);

“我不明白为什么要把时间戳搞得这么麻烦!”

另外:java.util.Date 与 java.time.LocalDateTime 之间的转换需要通过 Instant 实现,它俩都没有提供直接的转换方法

// 获取系统默认时区
ZoneId systemDefaultZoneId = ZoneId.systemDefault();
// Date 转为 LocalDateTime
Date date3 = new Date();
Instant instant3 = date3.toInstant();
LocalDateTime localDateTime3 = LocalDateTime.ofInstant(instant3, systemDefaultZoneId);

// LocalDateTime 转为 Date
Instant instant4 = now.atZone(systemDefaultZoneId).toInstant();
Date date4 = Date.from(instant4);

还有:LocalDateTime 可以由 LocalDate 和 LocalTime 组成,也可以拆分成它俩

LocalDate nowLocalDate = LocalDate.now();
LocalTime nowLocalTime = LocalTime.now();
LocalDateTime nowLocalDateTime = LocalDateTime.of(nowLocalDate, nowLocalTime);

nowLocalDateTime.toLocalDate();
nowLocalDateTime.toLocalTime();

计算

计算时间点与时间点之间的间隔:

// 计算日期时间之间的间隔
LocalTime startTime = LocalTime.now();
LocalTime endTime = startTime.plusHours(1).plusMinutes(50);
Duration duration = Duration.between(startTime, endTime);

// 间隔秒数
duration.getSeconds();
// 间隔天数
duration.toDays();
// 间隔小时数
duration.toHours();
// 间隔分钟数
duration.toMinutes();

Duration.between(start, end) 的参数可以是 LocalDateTime 、LocalTime

它只会返回一个整数(舍掉小数后的整数,等同于 floor()),不会返回 1小时50分钟 这样的形式
如果你想要 y年M个月d天 H小时m分钟s秒 这种形式,或许你自己动手组装一下了

// 计算日期之间的间隔
LocalDate startDate = LocalDate.now();
LocalDate endDate = LocalDate.of(2031, 1, 1);
Period pe = Period.between(startDate, endDate);
pe.getYears();
pe.getMonths();
pe.getDays();

时间点与时间段的计算:

 public LocalDateTime plusYears(long years) {
  LocalDate newDate = date.plusYears(years);
  return with(newDate, time);
 }

 public LocalDateTime plusMonths(long months) {
  LocalDate newDate = date.plusMonths(months);
  return with(newDate, time);
 }

 public LocalDateTime plusWeeks(long weeks) {
  LocalDate newDate = date.plusWeeks(weeks);
  return with(newDate, time);
 }

 public LocalDateTime plusDays(long days) {
  LocalDate newDate = date.plusDays(days);
  return with(newDate, time);
 }

 public LocalDateTime plusHours(long hours) {
  return plusWithOverflow(date, hours, 0, 0, 0, 1);
 }

 public LocalDateTime plusMinutes(long minutes) {
  return plusWithOverflow(date, 0, minutes, 0, 0, 1);
 }

 public LocalDateTime plusSeconds(long seconds) {
  return plusWithOverflow(date, 0, 0, seconds, 0, 1);
 }

 public LocalDateTime plusNanos(long nanos) {
  return plusWithOverflow(date, 0, 0, 0, nanos, 1);
 }

 public LocalDateTime minusYears(long years) {
  return (years == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-years));
 }

 public LocalDateTime minusMonths(long months) {
  return (months == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-months));
 }

 public LocalDateTime minusWeeks(long weeks) {
  return (weeks == Long.MIN_VALUE ? plusWeeks(Long.MAX_VALUE).plusWeeks(1) : plusWeeks(-weeks));
 }

 public LocalDateTime minusDays(long days) {
  return (days == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-days));
 }

 public LocalDateTime minusHours(long hours) {
  return plusWithOverflow(date, hours, 0, 0, 0, -1);
 }

 public LocalDateTime minusMinutes(long minutes) {
  return plusWithOverflow(date, 0, minutes, 0, 0, -1);
 }

 public LocalDateTime minusSeconds(long seconds) {
  return plusWithOverflow(date, 0, 0, seconds, 0, -1);
 }

 public LocalDateTime minusNanos(long nanos) {
  return plusWithOverflow(date, 0, 0, 0, nanos, -1);
 }

看吧,加减年数、月数、天数、小时数、分钟数、秒数、毫秒数都有

想怎么用就怎么用,举个小例子:

LocalDateTime now = LocalDateTime.now();

// 30年后的今天(我还要上班,还没退休)
LocalDateTime after30Years = now.plusYears(30L);
System.out.println(after30Years);

// 347个月后(我就能还清贷款了 ╥﹏╥)
LocalDateTime after348Months = now.plusMonths(347L);
System.out.println(after348Months);

// 11天后(就是除夕了)
LocalDateTime after10Days = now.plusDays(10L);
System.out.println(after10Days);

// 8小时前(我在上班)
LocalDateTime before8Hours = now.minusHours(8L);
System.out.println(before8Hours);

// 3分钟前(我开始听 Let it go 这首歌)
LocalDateTime before3Before = now.minusMinutes(3L);
System.out.println(before3Before);

// 10秒前(写下下面这条代码)
LocalDateTime before10Second = now.minusSeconds(10L);
System.out.println(before10Second);

其实不用区分什么加减的,也可以用 plusXxx 做减法,只要传入负数参数就行了

另外这里还有一类需求,比如:

明年的感恩节是哪天?(每年11月的第四个星期四为感恩节)
下周五是哪天?

这就要用到时间校正器 TemporalAdjuster
这里容我先介绍一下 TemporalAdjuster,它是一个函数式接口,只有一个方法 adjustInto

@FunctionalInterface
public interface TemporalAdjuster {
 Temporal adjustInto(Temporal temporal);
}

Temporal 是一个接口,LocalDateTime 、LocalDate 、 LocalTime 都是它的实现类

在 LocalDateTime 、LocalDate 、 LocalTime 中都有 with(TemporalAdjuster adjuster) 这个方法用来实现上面提到的另类需求。

// 下周五
LocalDateTime now = LocalDateTime.now();
LocalDateTime nextFriday = now.with(dt -> {
 // dt 是 `Temporal` 对象,但实质上是调用对象的类型
 LocalDateTime dateTime = (LocalDateTime) dt;
 // 非常可惜,没有 withDayOfWeek() 这个方法,要不然就会非常方便了
 int dayOfWeekValue = dateTime.getDayOfWeek().getValue();
 int fridayValue = DayOfWeek.FRIDAY.getValue();
 return dateTime.plusWeeks(1L)
    .plusDays(fridayValue - dayOfWeekValue);
});
System.out.println(nextFriday);

// 明年的感恩节(明年11月第四个星期四)
LocalDate thanksGivingDay = LocalDate.now().with( t -> {
 LocalDate d = (LocalDate) t;
 // 明年11月1日
 LocalDate newDate = d.plusYears(1L).withMonth(11).withDayOfMonth(1);

 int dayOfWeekValue = newDate.getDayOfWeek().getValue();
 int thursdayValue = DayOfWeek.THURSDAY.getValue();
 long plusWeeks = dayOfWeekValue > thursdayValue ? 4L : 3L;
 return newDate.plusWeeks(plusWeeks)
     .plusDays(thursdayValue - dayOfWeekValue);
});
System.out.println(thanksGivingDay);

其实 TemporalAdjusters 提供了许多 TemporalAdjuster 对象,就像上一节 Stream 中 Collectors 之于 Collector 一样 。

使用 TemporalAdjusters 能够十分方便的实现上面的需求

// 下个周五
LocalDateTime nextFriday = LocalDateTime.now().with(TemporalAdjusters.next(DayOfWeek.FRIDAY));
System.out.println(nextFriday);

// 明年的感恩节(明年11月第四个星期四)
LocalDate date = LocalDate.now().plusYears(1L).withMonth(11);
LocalDate thanksGivingDay = date.with(TemporalAdjusters.dayOfWeekInMonth(4, DayOfWeek.THURSDAY));
System.out.println(thanksGivingDay);

注意: TemporalAdjusters.next(DayOfWeek day) 方法返回的是 接下来第一个周五,并不是我们一般理解的 下周五,比如说:今天 2020-01-13(周一),那么返回的就是 2020-01-17 四天后的周五。

另外 TemporalAdjusters 并不止提供了上面这2个方法,还有很多其他方法, API 文档 中给出了足够多的例子,一看就明白了。

建议有兴趣的同学,去阅读一些源码,参考 Java8 代码逻辑,然后用其他编程语言实现相同的日期时间操作,因为在其他编程中(比如 javaScript)也会经常用到日期时间的操作

其他特性

罗列出来表示我知道他们,但不表示我理解他们,所以 Let It Go!

接口中的默认方法

接口中的静态方法

Optional 类

Optional<String> op = Optional.of(str);

它是用来标识这个变量有可能为空。

如果一个变量有可能为空,Java8 之前我们每次使用这个变量时,都必须判断它是否为空。现在也是!!

Optional 并不能避免空指针异常,仅仅是表示标识变量可能为空。打个比方:

前面一条路上埋了地雷,但从表面上完全看不出来,除非我们走一步都扔石头试一下,否则说不准哪一步就炸了。而 Optional就是用来标识地雷位置的,我们知道了哪个位置有雷,就会绕着走,从而能够安全通过

另外 Optional 还提供了一个设置默认值的功能,挺好玩的。

Integer pageSize = null;
// 以前我们设置默认值
//pageSize = pageSize == null ? 10 : pageSize;
//System.out.println(pageSize);

// 使用 Optional 设置默认值
pageSize = Optional.ofNullable(pageSize)
 .orElse(20);
System.out.println(pageSize);

// 自定义默认值
Integer defaultPageSize = Optional.ofNullable(pageSize)
  .orElseGet(() -> {
   return new Integer(50);
  });

结语

Java8 新特性系列随便到此就结束了。

最最关键的,还是多看 Java 官方 API 文档!!

我在想可能我们被矫枉过正了。各种各样技术群最多的回答都是:去问百度!! 百度全知道吗?!

说实在的,在今天这个时代,是个人都能在网络上发表文章言论,然后大家再互相转载,假的都能成为真的!
没有经过验证就转载的;在当时有效,现在过时了的;随便在文章中一个转载链接的 ... 比比皆是

总结

以上所述是小编给大家介绍的Java8 新特性之日期时间对象及一些其他特性,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

(0)

相关推荐

  • Java日期时间及日期相互转换实现代码

    这篇文章主要介绍了Java日期时间及日期相互转换实现代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 java.util 包提供了 Date 类来封装当前的日期和时间. Date 类提供两个构造函数来实例化 Date 对象. 第一个构造函数使用当前日期和时间来初始化对象. Java日期时间,以及相互转化,供大家参考,具体内容如下 package com.study.string; import java.text.ParseException

  • 如何通过Java实现时间轴过程解析

    这篇文章主要介绍了如何通过Java实现时间轴过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.需要添加FastJson的依赖处理数据. <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.47</version> </depen

  • Java使用DateTimeFormatter实现格式化时间

    用扫描器获取输入的时间(年月日时分),这个时间的格式是常用的格式,然后格式化这个时间,把格式化的时间输出到控制台,可以在控制台重复输入时间.格式化的时间参考企业微信聊天记录的展示时间.用DateTimeFormatter实现,功能如下: 同年: 不同年: 同月:月日+上午/下午+时分 同年不同月:月日+时分 今天:上午/下午+时分 明天:明天+上午/下午+时分 昨天:昨天+上午/下午+时分 包括今天在内的一周内:星期+上午/下午+时分 首先看一下测试类: package hrkj; import

  • java实现的日期时间转换工具类完整示例

    本文实例讲述了java实现的日期时间转换工具类.分享给大家供大家参考,具体如下: 最基础的东西,总结一下,下次用的时候就方便一些了.废话不多说,直接贴代码: package com.incar.base.util; import com.incar.base.exception.BaseRuntimeException; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDat

  • Java日期与时间类原理解析

    这篇文章主要介绍了Java日期与时间类原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 基础知识 日期: 类似于 2018-12-12 时间: 类似于 2018-12-12 12:12:12 时刻: 类似于 2018-12-12 12:12:12 地区: 计算机中的 Locale, 如 zh_CN, en_US 等, 影响着对于日期, 时间, 货币等格式的显示 EpochTime: 从 1970 年 1 月 1 日 UTC+00:00 到

  • 通过java记录数据持续变化时间代码解析

    这篇文章主要介绍了通过java记录数据持续变化时间代码解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.需求:获取count为null和不为null的持续变化 [{count=0, time=0}, {count=10, time=1000}, {count=20, time=2000}, {count=30, time=3000}, {count=40, time=4000}, {count=null, time=5000}, {cou

  • Java8新特性时间日期库DateTime API及示例详解

    Java8新特性的功能已经更新了不少篇幅了,今天重点讲解时间日期库中DateTime相关处理.同样的,如果你现在依旧在项目中使用传统Date.Calendar和SimpleDateFormat等API来处理日期相关操作,这篇文章你一定不要错过.来刷新你的知识库吧! 背景 Java对日期.日历及时间的处理一直以来都饱受诟病,比如java.util.Date和java.util.Calendar类易用性差,不支持时区,非线程安全:还有用于格式化日期的类DateFormat也是非线程安全的等问题. J

  • Java缓存Map设置过期时间实现解析

    这篇文章主要介绍了Java缓存Map设置过期时间实现解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 前言 最近项目需求需要一个类似于redis可以设置过期时间的K,V存储方式.项目前期暂时不引进redis,暂时用java内存代替. 解决方案 1. ExpiringMap 功能简介 : 1.可设置Map中的Entry在一段时间后自动过期. 2.可设置Map最大容纳值,当到达Maximum size后,再次插入值会导致Map中的第一个值过期.

  • Java8 新特性之日期时间对象及一些其他特性

    日期时间对象 关于日期时间的操作可以分为两种: 转换:与字符串的互相转换,与时间戳的互相转换 计算:计算两个时间点之间的间隔.时间点与时间段的计算(计算下周N.下个月D日.去年M月D日等等) Java8 提供了三个类:LocalDate.LocalTime.LocalDateTime,它们的形式如 2020-01-01.12:30:00.2020-01-01 12:30:00 创建对象 获取类对象的方法非常非常简单 LocalDate now = LocalDate.now(); LocalDa

  • java8新特性之日期时间API

    jdk8之前 一.java.lang.System long times = System.currentTimeMillis(); //返回的是当前时间与1970年1月1月1日0分0秒之间以毫秒为单位的时间差 //称为时间戳 System.out.println(times); 二.java.util.Date And java.sql.Date 将java.util.Date 对象转换为java.sql.Date对象: //将java.util.Date 对象转换为java.sql.Date

  • Python日期时间对象转换为字符串的实例

    1.标准转换格式符号说明 %a 本地星期的短名称 如:Sun, Mon, ..., Sat (en_US); So, Mo, ..., Sa (de_DE) %A 本地星期全名称 如 :Sunday, Monday, ..., Saturday (en_US);Sonntag, Montag, ..., Samstag (de_DE) %w 星期的数字表示,0表示周日,6表示周六 如:0,1,2,,,6 %d 日的数字表示,并且使用0来填补(0-9),如:01, 02, ..., 31 %b 月

  • 深入理解Java8新特性之新日期时间API的应用

    目录 1.新旧对比(线程安全问题) 2.LocalDate 3.LocalTime 4.LocalDateTime 5.Instant 6.Duration.Period 7.TestTemporalAdjuster.TestTemporalAdjusters 8.DateTimeFormatter 1.新旧对比(线程安全问题) 我们先来看下面的代码:

  • Spring Boot中是如何处理日期时间格式的

    在springboot中开发RESTful接口,经常会遇到日期时间转换相关的问题,例如我们明明输入看起来很正常的日期时间字符串,但是系统却报错无法解析: JSON parse error: Cannot deserialize value of type java.time.OffsetDateTime from String "2020-06-06 14:26:31" 或者接口返回的日期时间字符串是一个很奇怪的字符串: 2020-06-04 14:41:54.767135400+08

  • Ruby日期时间的比较,日期转换等时间日期处理方法大全

    Ruby中Date.Time. DateTime这3个类提供 了和日期时间相关的操作. Date只能处理日期Time能处理日期和时间DateTime也能处理日期和时间 其中,DateTime 是Date的一个子类,是对时间部分数据的补充.要使用Date和DateTime类,只需导入date库就可以,要使用Time类,导入time库就行. require 'date' # 提供Date和DateTime类 require 'time' # 提供Time类(可直接使用,但导入后有更多方法) 一般来说

  • Python日期时间模块datetime详解与Python 日期时间的比较,计算实例代码

    python中的datetime模块提供了操作日期和时间功能,该模块提供了五种核心对象:datetime时间日期类型,date日期类型,time时间类型,tzinfo时区类型,timedelta时间差类型,今天为大家介绍一下datetime模块的具体使用方法与python日期时间计算与比较的相关实例 一.Python中日期时间模块datetime介绍 (一).datetime模块中包含如下类: 类名 功能说明 date 日期对象,常用的属性有year, month, day time 时间对象

  • python GUI库图形界面开发之PyQt5日期时间控件QDateTimeEdit详细使用方法与实例

    PyQt5日期时间控件QDateTimeEdit介绍 QDateTimeEdit是一个允许用户编辑日期时间的控件,可以使用键盘上的上下键头按钮来增加或减少日期的时间值,QDateTimeEdit通过setDisplayFormat()函数来设置显示的日期时间格式 QDateTimeEdit类中常用方法 方法 描述 setDisplayFormat 设置日期的时间格式 yyyy:代表年份,用4为数表示 MM:代表月份,取值范围01-12 dd:代表日,取值范围01-31 HH:代表小时,取值范围0

  • Laravel中日期时间处理包Carbon的简单使用

    前言 我们大家在编写 PHP 应用时经常需要处理日期和时间,这篇文章带你了解一下 Carbon – 继承自 PHP DateTime 类的 API 扩展,它使得处理日期和时间更加简单. Laravel 中默认使用的时间处理类就是 Carbon. <?php namespace Carbon; class Carbon extends \DateTime { // code here } 你可以在 Carbon 命名空间的 Carbon 类中看到上面声明的代码片段. 安装 可以通过 Compose

  • 使用Python将字符串转换为格式化的日期时间字符串

    我正在尝试将字符串"20091229050936"转换为"2009年12月29日(UTC)" >>>import time >>>s = time.strptime("20091229050936", "%Y%m%d%H%M%S") >>>print s.strftime('%H:%M %d %B %Y (UTC)') 给 AttributeError: 'time.str

随机推荐