Java 8 Time API
日期时间API 也是Java 8重要的更新之一,Java从一开始就缺少一致的日期和时间方法,Java 8 Date Time API是Java核心API的一个非常好的补充。
为什么需要新的日期时间API
Java中现有的与日期和时间相关的类存在一些问题:
- 日期时间类的定义不一致,在
java.util和java.sql包中都有Date类。同样,格式化和解析类是在java.text包中定义的。 java.util.Date同时包含日期和时间值,而java.sql.Date只包含日期值,把它放在java.sql包中是没有意义的。而且这两个类的名称相同,这本身就是一个非常糟糕的设计。- 没有为时间、时间戳、格式化和解析明确定义的类。我们有
java.text.DateFormat抽象类用于解析和格式化,通常使用SimpleDateFormat类解析和格式化。 - 所有
Date类都是可变的,所以它们不是线程安全的,这也是JavaDate和Calendar类最大的问题之一。 Date类不提供国际化,不支持时区。虽然引入了java.util.Calendar和java.util.TimeZone,但是它们也存在上面的问题。
在Date和Calendar类中定义的方法还有一些其他的问题,但是上面的问题清楚地表明,Java中需要一个健壮的日期时间API。这就是为什么 Joda Time 可以成为Java 日期时间高质量的替代品。
Java 8日期时间设计原则
Java 8日期时间API是基于 JSR-310 规范实现的。目的是为了解决遗留日期时间实现中的所有缺陷。新的日期时间API的一些设计原则如下:
不变性:新的日期时间API中的所有类都是不可变的,适用于多线程环境。
关注点分离:新的日期时间API明确区分了人类可读的日期、时间和机器时间(Unix时间戳),它为
Date、Time、DateTime、Timestamp、Timezone等定义单独的类。清晰性:所有的类中都清晰地定义了方法,并执行相同的操作。例如,要获取当前时间实例可以用
now()方法,在所有这些类中都定义了format()和parse()方法,而不是为它们单独定义一个类。所有类都使用工厂模式和策略模式来更好地操作。一旦您使用了其中一个类中的方法,使用其他类并不困难。
实用的操作:所有新的日期时间API类都常见的方法,比如加、减、格式化、解析、在日期/时间中获取单独的部分等等。
可扩展:新的日期时间API可以在
ISO-8601日历系统上工作,但是我们也可以在其他非ISO日历上使用它。
Java 8日期时间API的包
Java8日期时间API由以下包组成。
java.time:这是Java 8日期时间API的基本包。所有主要的基类都是这个包的一部分,例如LocalDate、LocalTime、LocalDateTime、Instant、Period、Duration等。所有这些类都是不可变的和线程安全的。大多数情况下,这些类足以处理常见的需求。java.time.chrono:这个包为非ISO日历系统定义了通用API。我们可以扩展AbstractChronology类来创建我们自己的日历系统。java.time.format:这个包包含用于格式化和解析日期时间对象的类。大多数时候我们不会直接使用它们,因为java.time包中的日期时间类已经提供了格式化和解析方法。java.time.temporal:这个包包含temporal对象,我们可以使用它来找出与日期/时间对象相关的特定日期或时间。例如,我们可以使用它们来查找一个月的第一天或最后一天。您可以很容易地识别这些方法,因为它们的格式总是withXXX。java.time.zone:这个包包含用于支持不同时区及其规则的类。
Java 8日期时间API类的示例
下面通过一些日期时间API类的示例,来更好的了解Java 8日期时间API
1.LocalDate
LocalDate是一个不可变的日期类,它以yyyy-MM-dd的默认格式表示日期。可以使用now()方法来获取当前日期,还可以提供年、月和日期的输入参数来创建LocalDate实例。
这个类为now()提供了一个重载方法,在这里可以传递ZoneId来获取特定时区中的日期。这个类提供了与java.sql.Date相同的功能。
// 当前日期
LocalDate today = LocalDate.now();
System.out.println("当前日期=" + today);
// 通过提供年月日参数创建日期
LocalDate nowYear_1024 = LocalDate.of(2022, Month.OCTOBER, 24);
System.out.println("参数日期=" + nowYear_1024);
// 通过时区获取当前日期
LocalDate todayShanghai = LocalDate.now(ZoneId.of("Asia/Shanghai"));
System.out.println("当前日期(CTT)=" + todayShanghai);
// 从纪元日(1970-01-01)开始的第多少天
LocalDate dateFromBase = LocalDate.ofEpochDay(365);
System.out.println("1970-01-01的第365天= " + dateFromBase);
// 某年的第多少天
LocalDate hundredDay2022 = LocalDate.ofYearDay(2022, 100);
System.out.println("2022年的第100天=" + hundredDay2022);
运行之后结果如下:
当前日期=2022-10-26
特殊日期=2022-10-24
当前日期(CTT)=2022-10-26
1970-01-01的第365天= 1971-01-01
2022年的第100天=2022-04-10
2.LocalTime
LocalTime是一个不可变的时间类,它以HH:mm:ss.SSS的默认格式表示时间。与LocalDate一样,这个类提供了时区支持,并可以通过传递小时、分钟和秒作为输入参数来创建实例。
// 当前时间
LocalTime time = LocalTime.now();
System.out.println("当前时间=" + time);
// 通过提供时分秒参数创建日期
LocalTime specificTime = LocalTime.of(12, 20, 25, 40);
System.out.println("参数时间=" + specificTime);
// 通过时区获取当前时间
LocalTime timeShanghai = LocalTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println("当前时间(CTT)=" + timeShanghai);
// 从纪元日开始的第多少秒
LocalTime specificSecondTime = LocalTime.ofSecondOfDay(100);
System.out.println("从纪元日开始的第100秒=" + specificSecondTime);
运行之后结果如下:
当前时间=15:39:18.948
参数时间=12:20:25.000000040
当前时间(CTT)=15:39:18.949
从0开始的第100秒=00:01:40
3.LocalDateTime
LocalDateTime是一个不可变的日期时间类,它以yyyy-MM-ddTHH:mm:ss.SSS的默认格式表示时间日期。它提供了一个工厂方法,该方法使用LocalDate和LocalTime作为参数创建LocalDateTime实例。
// 当前日期时间
LocalDateTime now = LocalDateTime.now();
System.out.println("当前日期时间=" + now);
// 通过提供LocalDate和LocalTime参数创建日期时间
now = LocalDateTime.of(LocalDate.now(), LocalTime.now());
System.out.println("当前日期时间=" + now);
// 通过提供年月日时分秒参数创建日期时间
LocalDateTime specificTime = LocalDateTime.of(2022, Month.OCTOBER, 24, 10, 24, 24);
System.out.println("参数日期时间=" + specificTime);
// 通过时区获取当前日期时间
LocalDateTime todayKolkata = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println("当前日期时间(CTT)=" + todayKolkata);
// 从纪元日开始的第多少秒
LocalDateTime dateFromBase = LocalDateTime.ofEpochSecond(100, 0, ZoneOffset.UTC);
System.out.println("从纪元日开始的第100秒= " + dateFromBase);
运行之后结果如下:
当前日期时间=2022-10-26T15:51:59.070
当前日期时间=2022-10-26T15:51:59.071
参数日期时间=2022-10-24T10:24:24
当前日期时间(CTT)=2022-10-26T15:51:59.071
从纪元日开始的第100秒=1970-01-01T00:01:40
注意:以上例子通过输入参数创建实例时,如果输入了无效的参数name将会抛出java.time.DateTimeException
4.Instant
instant类用于处理机器可读的时间格式。instant类将日期时间存储在unix时间戳中。
// 当期时间戳
Instant timestamp = Instant.now();
System.out.println("当期时间戳= "+timestamp);
// 从纪元日开始的第多少毫秒
Instant specificTime = Instant.ofEpochMilli(timestamp.toEpochMilli());
System.out.println("从纪元日开始="+specificTime);
运行之后结果如下:
当期时间戳=2022-10-26T08:08:40.429Z
从纪元日开始=2022-10-26T08:08:40.429Z
Java8日期时间API类的实用方法
大多数日期时间类都会提供各种实用方法,例如加/减天数、周数、月数等。还有一些其他实用方法可以使用时间调整器TemporalAdjuster调整日期,并计算两个日期之间的时间段。
LocalDate today = LocalDate.now();
//获取年份,判断年份是否是闰年
System.out.println("Year "+today.getYear()+" is Leap Year? "+today.isLeapYear());
//比较两个时间
System.out.println("Today is before 01/01/2023? "+today.isBefore(LocalDate.of(2023,1,1)));
//通过LocalDate创建LocalDateTime
System.out.println("Current Time="+today.atTime(LocalTime.now()));
//加减操作
System.out.println("10 days after today will be "+today.plusDays(10));
System.out.println("3 weeks after today will be "+today.plusWeeks(3));
System.out.println("20 months after today will be "+today.plusMonths(20));
System.out.println("10 days before today will be "+today.minusDays(10));
System.out.println("3 weeks before today will be "+today.minusWeeks(3));
System.out.println("20 months before today will be "+today.minusMonths(20));
//时间调整器调整时间
System.out.println("First date of this month= "+today.with(TemporalAdjusters.firstDayOfMonth()));
LocalDate lastDayOfYear = today.with(TemporalAdjusters.lastDayOfYear());
System.out.println("Last date of this year= "+lastDayOfYear);
Period period = today.until(lastDayOfYear);
System.out.println("Period Format= "+period);
System.out.println("Months remaining in the year= "+period.getMonths());
运行之后结果如下:
Year 2022 is Leap Year? false
Today is before 01/01/2023? true
Current Time=2022-10-26T16:25:04.740
10 days after today will be 2022-11-05
3 weeks after today will be 2022-11-16
20 months after today will be 2024-06-26
10 days before today will be 2022-10-16
3 weeks before today will be 2022-10-05
20 months before today will be 2021-02-26
First date of this month= 2022-10-01
Last date of this year= 2022-12-31
Period Format= P2M5D
Months remaining in the year= 2
Java8日期时间的解析和格式化
经常用到的操作有:将日期时间格式化为不同格式String,解析String以获得日期时间对象。
// 格式化
LocalDate date = LocalDate.now();
// 默认格式
System.out.println("Default format of LocalDate=" + date);
// 自定义格式
System.out.println(date.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
System.out.println(date.format(DateTimeFormatter.BASIC_ISO_DATE));
LocalDateTime dateTime = LocalDateTime.now();
// 默认格式
System.out.println("Default format of LocalDateTime=" + dateTime);
// 自定义格式
System.out.println(dateTime.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时mm分ss秒")));
System.out.println(dateTime.format(DateTimeFormatter.BASIC_ISO_DATE));
Instant timestamp = Instant.now();
// 默认格式
System.out.println("Default format of Instant=" + timestamp);
// 解析
LocalDateTime dt = LocalDateTime.parse("2022年10月24日10时24分24秒",
DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时mm分ss秒"));
System.out.println("Default format after parsing = " + dt);
运行之后结果如下:
Default format of LocalDate=2022-10-26
2022年10月26日
20221026
Default format of LocalDateTime=2022-10-26T16:37:51.300
2022年10月26日16时37分51秒
20221026
Default format of Instant=2022-10-26T08:37:51.301Z
Default format after parsing = 2022-10-24T10:24:24
对遗留日期时间的支持
遗留日期/时间类几乎在所有应用程序中都使用,因此必须有向下兼容。这就是为什么我们可以通过一些实用方法将遗留类转换为新类,反之亦然。
//Date转Instant
Instant timestamp = new Date().toInstant();
//Instant转LocalDateTime
LocalDateTime date = LocalDateTime.ofInstant(timestamp,
ZoneId.of(ZoneId.SHORT_IDS.get("CTT")));
System.out.println("Date = " + date);
//Calendar转Instant
Instant time = Calendar.getInstance().toInstant();
System.out.println(time);
//TimeZone转ZoneId
ZoneId defaultZone = TimeZone.getDefault().toZoneId();
System.out.println(defaultZone);
//ZonedDateTime from specific Calendar
ZonedDateTime gregorianCalendarDateTime = new GregorianCalendar().toZonedDateTime();
System.out.println(gregorianCalendarDateTime);
//Date API to Legacy classes
Date dt = Date.from(Instant.now());
System.out.println(dt);
TimeZone tz = TimeZone.getTimeZone(defaultZone);
System.out.println(tz);
GregorianCalendar gc = GregorianCalendar.from(gregorianCalendarDateTime);
System.out.println(gc);
运行之后结果如下:
Date = 2022-10-26T16:47:38.329
2022-10-26T08:47:38.429Z
Asia/Shanghai
2022-10-26T16:47:38.455+08:00[Asia/Shanghai]
Wed Oct 26 16:47:38 CST 2022
sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=31,lastRule=null]
java.util.GregorianCalendar[time=1666774058455,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=31,lastRule=null],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2022,MONTH=9,WEEK_OF_YEAR=43,WEEK_OF_MONTH=4,DAY_OF_MONTH=26,DAY_OF_YEAR=299,DAY_OF_WEEK=4,DAY_OF_WEEK_IN_MONTH=4,AM_PM=1,HOUR=4,HOUR_OF_DAY=16,MINUTE=47,SECOND=38,MILLISECOND=455,ZONE_OFFSET=28800000,DST_OFFSET=0]
可以看到,遗留的TimeZone和GregorianCalendar类toString()方法过于冗长,对用户不友好。
Java 8 Time API的更多相关文章
- Java 8 Stream API详解--转
原文地址:http://blog.csdn.net/chszs/article/details/47038607 Java 8 Stream API详解 一.Stream API介绍 Java8引入了 ...
- Java 8 Stream API Example Tutorial
Stream API Overview Before we look into Java 8 Stream API Examples, let’s see why it was required. S ...
- java微信开发API解析(二)-获取消息和回复消息
java微信开发API解析(二)-获取消息和回复消息 说明 * 本演示样例依据微信开发文档:http://mp.weixin.qq.com/wiki/home/index.html最新版(4/3/20 ...
- 文件IO 相关的包:java.io文件——API
文件IO 相关的包:java.io文件——API 1.Java.io.File类的使用(1)两种路径绝对路径:相对于当前路径:当前为 “工程名”(2)File类创建,对象为一个文件/目录,可能存在或不 ...
- Elasticsearch Java Rest Client API 整理总结 (一)——Document API
目录 引言 概述 High REST Client 起步 兼容性 Java Doc 地址 Maven 配置 依赖 初始化 文档 API Index API GET API Exists API Del ...
- Elasticsearch Java Rest Client API 整理总结 (二) —— SearchAPI
目录 引言 Search APIs Search API Search Request 可选参数 使用 SearchSourceBuilder 构建查询条件 指定排序 高亮请求 聚合请求 建议请求 R ...
- Elasticsearch Java Rest Client API 整理总结 (三)——Building Queries
目录 上篇回顾 Building Queries 匹配所有的查询 全文查询 Full Text Queries 什么是全文查询? Match 全文查询 API 列表 基于词项的查询 Term Term ...
- Java 8 Stream API
Java 8 Stream API JDK8 中有两大最为重要的改变.第一个是 Lambda 式:另外 Stream API(java.util.stream.*) Stream 是 JDK8 中处理 ...
- Java学习(API及Object类、String类、StringBuffer字符串缓冲区)
一.JAVA的API及Object类 1.API 概念: Java 的API(API: Application(应用) Programming(程序) Interface(接口)) Java API就 ...
- java.io.BufferedWriter API 以及源码解读
下面是java se 7 API 对于java.io.BufferedWriter 继承关系的描述. BufferedWriter可以将文本写入字符流.它会将字符缓存,目的是提高写入字符的效率. bu ...
随机推荐
- ARC120F Wine Thief (组合数学)
题面 有一个长为 N N N 的序列,相邻的两个数中只能选一个,总共选 k k k 个数,一种方案的价值为选的 k k k 个数的和,问所有合法方案的价值总和,答案对 998244353 取模. 1 ...
- java数组---稀疏数组与数组之间的相互转化
public static void main(String[] args) { int[][]array1=new int[11][11]; array1[1][2]=1; array1[2][3] ...
- Mybatis中多对一与一对多
多对一的处理 在pojo中就有 Student private String name; private String id; private Teacher teacher; 比如说多个学生对应着一 ...
- 第三十五篇:vue3,(组合式api的初步理解)
好家伙, 来一波核心概念:数据劫持是响应式的核心 1.由set up开始 (1)vue3中的一个新的配置项,值为一个函数. (2)组件中所用的到的:数据,方法,计算属性均要配置在set up中. (3 ...
- 第十五章 部署zookeeper集群
1.集群规划 主机名 角色 IP hdss7-11.host.com k8s代理节点1.zk1 10.4.7.11 hdss7-12.host.com k8s代理节点2.zk2 10.4.7.12 h ...
- 电商平台物流模块自建OR对接第三方物流平台
前沿 近几年来,电商行业竞争变得愈加激烈,公域流量获客成本越来越高,电商平台规则也越来越严格,数据无法出塔,商家无法自主运营用户群等等原因,很多大品牌纷纷开始搭建自有商城,运营私域流量,以此来降低 ...
- Centos下使用containerd管理容器:5分钟从docker转型到containerd
目录 一.系统环境 二.前言 三.containerd 四.部署containerd 4.1 安装containerd 4.2 containerd配置文件 4.3 配置containerd阿里云镜像 ...
- 深度剖析js闭包
一.什么是闭包? 方法里面返回一个方法 二.闭包存在的意义 延长变量的生命周期 作用域链 沟通内外部方法的桥梁 闭包会常驻内存 ==>慎用闭包 闭包里的变量不会被回收 创建私有环建 例 ...
- 生信云实证Vol.12:王者带飞LeDock!开箱即用&一键定位分子库+全流程自动化,3.5小时完成20万分子对接
LeDock是苏黎世大学Zhao HongTao在博士期间开发的一款分子对接软件,专为快速准确地将小分子灵活对接到蛋白质而设计.LeDock优于大部分商业软件,在Astex多样性集合上实现了大于90% ...
- .NET 实现启动时重定向程序运行路径及 Windows 服务运行模式部署
日常工作中有时候会遇到需要将程序直接在服务器上运行,而不依赖于 IIS 托管的情况,直接运行有两种方式,一种是部署为 服务模式,另一种则是 直接启动 .NET 发布之后的 exe 文件以 控制台模式运 ...