目录
前言
案例导入
java.util.Date
java.text.SimpleDateFormat
java.util.Calendar
java.time
java.time.format.DateTimeFormatter
其他API
结束语
在本篇文章中,作者会向读者演示以下(包括但不仅限于)Java中的日期时间API的使用:
- java.util.Date类
- Date() / Date(long date)
- getTime()
- toString()
- java.text.SimpleDateFormat类
- SimpleDateFormat() / SimpleDateFormat(String pattern)
- format(Date date)
- parse(String source)
java.util.Calendar(日历)类
Calendar.getInstance()
get(int field)
getTime()
java.time( LocalDate、LocalTime、LocalDateTime)
now() / now(ZoneId zone)
of()
Instant
java.time.format.DateTimeFormatter 类
ofPattern(String pattern)
ofLocalizedDateTime(FormatStyle.LONG)
format(TemporalAccessor t)
parse(CharSequence text)
其他API
ZoneId
Clock
Duration、Period
TemporalAdjuster
说明:
1、 java.util.Date、java.text.SimpleDateFormat和java.util.Calendar理论上属于JDK8之前
2、java.time、java.time.format.DateTimeFormatter和其他API理论上属于JDK8之后
3、但JDK版本的迭代一般都是大版本兼容小版本,即在原有的版本上增加新内容,属于增量式开发,所以本文将两部分统一概述为JDK8的日期时间。
在开始讲述之前,我们先来看一个有趣的案例:
渔夫按照最佳的打鱼方式“三天打鱼,两天晒网”,问:从1998年8月8日开始打鱼,至今2021年10月16日,渔夫在打鱼还是在晒网?
此问题不难解决,只需要计算开始时间与结束时间的时间差,然后与5取余即可。余数为1,2,3,则渔夫在打鱼;余数为4和0,则渔夫在晒网。
下面介绍两个计算时间间隔的方法:
- 使用java.util.Date类中的getTime()方法获实现。
- 实现思路:
- 调用getTime() 方法获得两个日期的时间戳
- 然后计算时间戳的差值,转换成天数+1,作为一共相差的天数dayDistance
- 将dayDistant % 5做判断
- 使用java.util.Calendar类来实现。
- 实现思路:
- 通过get(Calendar.DAY_OF_YEAR)方法来获取天(endDays、startDays),通过get(Calendar.YEAR)方法获取年(endYears、startYears)
- 首先判断是否是同一年,如果是同一年,直接返回(endDays-startDays)+1作为一共相差的天数dayDistance
- 如果不是同一年,根据平年和闰年的不同,计算不同的时间间距timeDistance,然后返回timeDistance + (day2-day1) + 1作为一共相差的天数dayDistance
- 将dayDistant % 5做判断
说明:
1、计算的天数为什么还要+1呢?
举个例子来解释吧,假如渔夫10月01日开始打鱼,则10月09日后,一共经历9-1=8天,还是9-1+1=9天呢?显然应该是9天才对,即10月9日第9天渔夫在晒网。
2、如何判断是平年还是闰年呢?
代码演示:
public void test2() throws ParseException {
// 方法一
String startTime = "1998-08-08";
String endTime = "2021-10-16";
int dayDistance = farmerDemo(startTime,endTime);
System.out.printf("方式一:\n农夫%s开始打鱼,按照三天打鱼二天晒网,经过%d天后,即在%s,农夫的状态是", startTime, dayDistance, endTime);
frame(dayDistance);
// 方式二
int dayDistance2 = differentDays(startTime, endTime);
System.out.printf("方式二:\n农夫%s开始打鱼,按照三天打鱼二天晒网,经过%d天后,即在%s,农夫的状态是", startTime, dayDistance2, endTime);
frame(dayDistance2);
}
private void frame(int dayDistance) {
switch (dayDistance % 5) {
case 0:
case 4:
System.out.println("晒网。");
break;
case 1:
case 2:
case 3:
System.out.println("打鱼。");
break;
}
}
public static int farmerDemo(String startTime, String endTime) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date d1 = sdf.parse(startTime);
Date d2 = sdf.parse(endTime);
long dayDistance = ((d2.getTime() - d1.getTime()) / (1000 * 60 * 60 * 24))+ 1;
return (int) dayDistance;
}
public static int differentDays(String startTime, String endTime) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date1 = sdf.parse(startTime);
Date date2 = sdf.parse(endTime);
Calendar cal1 = Calendar.getInstance();
cal1.setTime(date1);
Calendar cal2 = Calendar.getInstance();
cal2.setTime(date2);
int startDays= cal1.get(Calendar.DAY_OF_YEAR);
int endDays = cal2.get(Calendar.DAY_OF_YEAR);
int startYear = cal1.get(Calendar.YEAR);
int endYear = cal2.get(Calendar.YEAR);
if(startYear != endYear) { //不同年
int timeDistance = 0 ;
for(int i = startYear ; i < endYear ; i ++) {
// 普通年能被4整除且不能被100整除的为闰年。(如2004年就是闰年,1900年不是闰年)
// 世纪年能被400整除的是闰年。(如2000年是闰年,1900年不是闰年)
if(i%4==0 && i%100!=0 || i%400==0) { //闰年
timeDistance += 366;
}
else { //不是闰年,就是平年
timeDistance += 365;
}
}
return timeDistance + (endDays-startDays) + 1;
}
else { //同年
return endDays - startDays + 1;
}
}
运行截图:
通过上述例子,作者向读者展示了java.util.Date、java.util.Date和java.util.Calendar三个类的使用,下面将具体介绍其用法。
表示特定的瞬间,精确到毫秒
构造器:
- Date():使用无参构造器创建的对象可以获取本地当前时间(精确到毫秒)。
- Date(long date):分配 Date 对象并初始化此对象,以表示自从标准基准时间(称为“历元(epoch)”,即 1970 年 1 月 1 日 00:00:00 GMT)以来的指定毫秒数。
常用方法
- getTime():返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。
- toString():把此 Date 对象转换为以下形式的 String: dow、 mon、 dd、hh:mm:ss、 zzz、 yyyy。
- dow 是一周中的某一天 (Sun, Mon, Tue,Wed, Thu, Fri, Sat)
- mon 是月份 (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec)。
- zzz 是时区(并可以反映夏令时)。
- 其它很多方法都过时了。
代码演示:
备注:
1、代码中 " // => xxxx" 表示输出结果
2、买一赠一,代码中介绍了java.util.Date的子类java.sql.Date
public void test1() {
// 创建一个date实例
Date date = new Date();
System.out.println(date); // => Sat Oct 16 17:49:16 CST 2021
System.out.println(date.toString()); // => Sat Oct 16 17:49:16 CST 2021
// 创建指定毫秒数的Date对象
Date date1 = new Date(1633828407854L);
System.out.println(date1); // => Sun Oct 10 09:13:27 CST 2021
// 创建java.sql.Date对象
java.sql.Date date2 = new java.sql.Date(1633828407854L);
System.out.println(date2); // => 2021-10-10
// 如何将java.util.Date对象转换为java.sql.Date对象
java.sql.Date date3 = new java.sql.Date(date1.getTime());
System.out.println(date3.toString()); // => 2021-10-10
// 不可使用强转,因为java.sql.Date继承了java.util.Date类
// 否则会报错:java.lang.ClassCastException: java.util.Date cannot be cast to java.sql.Date
java.sql.Date date4 = (java.sql.Date) date1;
}
Date类的API不易于国际化,大部分被废弃了,java.text.SimpleDateFormat类是一个不与语言环境有关的方式来格式化和解析日期的具体类。
它允许进行格式化:①日期 --->文本 ②解析:文本--->日期
格式化:
- SimpleDateFormat() :默认的模式和语言环境创建对象
- public SimpleDateFormat(String pattern):该构造方法可以用参数pattern指定的格式创建一个对象
- public String format(Date date):方法格式化时间对象date
解析:
- public Date parse(String source):从给定字符串的开始解析文本,以生成一个日期。
字母 日期或时间元素 示例 G
Era 标志符 AD
y
年 1996
;96
M
年中的月份 July
;Jul
;07
w
年中的周数 27
W
月份中的周数 2
D
年中的天数 189
d
月份中的天数 10
F
月份中的星期 2
E
星期中的天数 Tuesday
;Tue
a
Am/pm 标记 PM
H
一天中的小时数(0-23) 0
k
一天中的小时数(1-24) 24
K
am/pm 中的小时数(0-11) 0
h
am/pm 中的小时数(1-12) 12
m
小时中的分钟数 30
s
分钟中的秒数 55
S
毫秒数 978
z
时区 Pacific Standard Time
;PST
;GMT-08:00
Z
时区 -0800
Calendar是一个抽象基类,主用用于完成日期字段之间相互操作的功能。
获取Calendar实例的方法
- 使用Calendar.getInstance()方法
- 调用它的子类GregorianCalendar的构造器。
一个Calendar的实例是系统时间的抽象表示,通过get(int field)方法来取得想要的时间信息。比如YEAR、MONTH、DAY_OF_WEEK(一个星期中的某天)、HOUR_OF_DAY 、MINUTE、SECOND
常用方法
- public void set(int field,int value):将给定的日历字段(field)设置为给定值(value)
- public void add(int field,int amount):根据日历的规则,为给定的日历字段添加或减去指定的时间量。
- public final Date getTime():返回一个表示此 Calendar 时间值(从历元至现在的毫秒偏移量)的 Date 对象
- public final void setTime(Date date) :使用给定的 Date 设置此 Calendar 的时间。
注意:
- 获取月份时:一月是0,二月是1,以此类推,12月是11
- 获取星期时:周日是1,周二是2 ,以此类推,周六是7
代码演示:
public void testCalendar() {
// 获取日历类的实例
Calendar instance = Calendar.getInstance(TimeZone.getTimeZone("PRC"));
// 使用给定的 Date 设置此 Calendar 的时间
Date date = new Date(1634378890294L);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd EEE a HH:mm:ss");
instance.setTime(date);
System.out.println("当前时区的ID: " + instance.getTimeZone().getID());
System.out.println("当前时间: "+ sdf.format(instance.getTime()));
System.out.println("一个星期中的第 " + instance.get(Calendar.DAY_OF_WEEK) + "天");
System.out.println("一年中的第 " + instance.get(Calendar.DAY_OF_YEAR) + "天");
System.out.println("获取月份 " + instance.get(Calendar.MONTH));
instance.set(Calendar.DAY_OF_MONTH, 8);
System.out.println("当前时间日设置为8后,时间是:" + sdf.format(instance.getTime()));
instance.add(Calendar.HOUR, 2);
System.out.println("当前时间加2小时后,时间是:" + sdf.format(instance.getTime()));
instance.add(Calendar.MONTH, -2);
System.out.println("当前日期减2个月后,时间是:" + sdf.format(instance.getTime()));
}
输出结果如图:
说明:
1、星期六为7,10月为9(与前面所述一致)
2、看到这,读者是否会产生疑问,时间应该是一个不可变(不能任意修改)的值,但Calendar类对时间进行了修改,导致当前时间不再是当前时间,这暴露了Calendar的缺陷。
Calendar类与Date类的不足:
JDK 1.0中包含了一个java.util.Date类,但是它的大多数方法已经在JDK 1.1引入Calendar类之后被弃用了。而Calendar并不比Date好多少。它们面临的问题是:
- 可变性:像日期和时间这样的类应该是不可变的。
- 偏移性:Date中的年份是从1900开始的,而月份都从0开始。
- 格式化:格式化只对Date有用,Calendar则不行。
- 此外,它们也不是线程安全的;不能处理闰秒等。
这些问题,随着JDK8的问世而得以解决。
备注:什么是润秒?
目前国际标准时间,是以铯原子的震动周期作为参考,而依据地球自转为准的时间尺度是叫做世界时,专用天文观测。因为地球自转受到月球潮汐产生不稳定,为使国际标准时间跟世界时差异接近,所以要校时。
世界协调时(UTC)为目前的国际标准时间,系以铯原子振动周期作为参考的高精度原子时。另一种则根据地球自转为准的时间尺度,称为世界时,属天文观测时间。
当前几乎所有操作系统都假定 1 天 = 24 × 60 × 60 = 86400 秒。但对于 UTC,大约每一两年出现一次额外的一秒,称为“闰秒”。闰秒始终作为当天的最后一秒增加,并且始终在 12 月 31 日或 6 月 30 日增加。
Java 8 吸收了 Joda-Time 的精华,以一个新的开始为 Java 创建优秀的 API。新的 java.time 中包含了所有关于本地日期(LocalDate)、本地时间(LocalTime)、本地日期时间(LocalDateTime)、时区(ZonedDateTime)和持续时间(Duration)的类。
JDK8针对之前版本的不足,做出了如下改变
- 解决可变性:调用修改日期值后返回新的对象
- 解决偏移性:java.time将月份和星期都改成了enum
- 解决格式化:使用 DateTimeFormatter类
- 解决线程安全:java.time中的日期和时间和最基本的String一样,是不变类型,不但线程安全,而且不能修改。
- 解决润秒:使用ISO-8601日历系统
历史悠久的 Date 类新增了 toInstant() 方法,用于把 Date 转换成新的表示形式。这些新增的本地化时间日期 API 大大简化了日期时间和本地化的管理。
LocalDate、LocalTime、LocalDateTime 类是其中较重要的几个类,它们的实例
是不可变的对象,分别表示使用 ISO-8601日历系统的日期、时间、日期和时间。它们提供了简单的本地日期或时间,并不包含当前的时间信息,也不包含与时区相关的信息。该类不存储或表示时区,而仅仅只是描述。
- LocalDate代表IOS格式(yyyy-MM-dd)的日期,可以存储 生日、纪念日等日期。
- LocalTime表示一个时间,而不是日期。
- LocalDateTime是用来表示日期和时间的,这是一个最常用的类之一。
注:ISO-8601日历系统是国际标准化组织制定的现代公民的日期和时间的表示法,也就是公历;它适用于闰年规则并一直用于日常生活中公历日历系统。
下面列举一些常用的方法,在代码中并不会都体现。
方法 | 描述 |
now() now(ZoneId zone) |
静态方法,根据当前时间创建对象(指定时区的对象) |
of() | 静态方法,根据指定日期/时间创建对象 |
getDayOfMonth() getDayOfYear() |
获得月份天数(1-31) 获得年份天数(1-366) |
getDayOfWeek() | 获得星期几(返回一个 DayOfWeek 枚举值) |
getMonth() | 获得月份, 返回一个 Month 枚举值 |
getMonthValue() getYear() |
获得月份(1-12) 获得年份 |
getHour() getMinute() getSecond() |
获得当前对象对应的小时、分钟、秒 |
withDayOfMonth()
withDayOfYear()
withMonth()/withYear()
|
将月份天数、年份天数、月份、年份修改为指定的值并返回新的对象 |
plusDays()
plusWeeks()
plusMonths()
plusYears()
plusHours()
|
向当前对象添加几天、几周、几个月、几年、几小时 |
minusMonths()
minusWeeks()
minusDays()
minusYears()
minusHours()
|
从当前对象减去几月、几周、几天、几年、几小时 |
代码演示:
public void testLocal() {
Date date = new Date();
System.out.println(date.toString()); // => Sat Oct 16 18:46:01 CST 2021
// 此方法获取的时间会比实际时间晚8小时
// 可以设置时区来获取对应的时间
Instant instant = date.toInstant();
System.out.println(instant.toString()); // => 2021-10-16T10:46:01.208Z
ZonedDateTime prc = instant.atZone(ZoneId.of("PRC"));
System.out.println(prc); // => 2021-10-16T16 18:46:01.208+08:00[PRC]
//now():获取当前的日期、时间、日期+时间
System.out.println(LocalDate.now()); // => 2021-10-16
System.out.println(LocalTime.now()); // => 18:46:01.208
LocalDateTime nowDate = LocalDateTime.now();
System.out.println(nowDate); // => 2021-10-16T18:46:01.208
//DayOfWeek 是一个枚举类
DayOfWeek dayOfWeek = nowDate.getDayOfWeek();
System.out.println(dayOfWeek); // => SATURDAY
//of():设置指定的年、月、日、时、分、秒、纳秒。没有偏移量
// 1秒 = 1000毫秒 =10^6微秒=10^9纳秒
LocalDateTime localDateTime1 = LocalDateTime.of(2021, 10, 6, 13, 23, 43);
LocalDateTime localDateTime2 = LocalDateTime.of(2021, 10, 6, 13, 23, 43, 295 * 1000000);
System.out.println(localDateTime1); // 2021-10-06T13:23:43
System.out.println(localDateTime2); // 2021-10-06T13:23:43.295
// of扩展
//获取秒数
Long second = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
//获取毫秒数
Long milliSecond = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
// 修改时间后,以新的对象返回,不会影响原时间
LocalDateTime newDate = localDateTime1.withDayOfMonth(30);
System.out.println("原来时间:" + localDateTime1); // => 原来时间:2021-10-06T13:23:43
System.out.println("修改后的时间:" + newDate); // => 修改后的时间:2021-10-30T13:23:43
LocalDateTime newDate2 = localDateTime1.plusDays(10L);
System.out.println("修改后的时间:" + newDate2); // => 修改后的时间:2021-10-16T13:23:43
}
备注:补充瞬时——Instant
- Instant:时间线上的一个瞬时点。 这可能被用来记录应用程序中的事件时间戳。
- 在处理时间和日期的时候,我们通常会想到年,月,日,时,分,秒。然而,这只是时间的一个模型,是面向人类的。第二种通用模型是面向机器的,或者说是连续的。在此模型中,时间线中的一个点表示为一个很大的数,这有利于计算机处理。在UNIX中,这个数从1970年开始,以秒为的单位;同样的,在Java中,也是从1970年开始,但以毫秒为单位。
- java.time包通过值类型Instant提供机器视图,不提供处理人类意义上的时间单位。Instant表示时间线上的一点,而不需要任何上下文信息,例如,时区。概念上讲,它只是简单的表示自1970年1月1日0时0分0秒(UTC)开始的秒数。因为java.time包是基于纳秒计算的,所以Instant的精度可以达到纳秒级。
- (1 ns = 10-9 s) 1秒 = 1000毫秒 =10^6微秒=10^9纳秒
该类提供了三种格式化方法:
预定义的标准格式
- ISO_LOCAL_DATE_TIME
- ISO_LOCAL_DATE
- ISO_LOCAL_TIME
本地化相关的格式
- ofLocalizedDateTime(FormatStyle.LONG)
- FormatStyle.LONG:长的文本样式,有很多的细节。
- FormatStyle.FULL:完整的文本样式,最详细的
- FormatStyle.MEDIUM:中文本风格,有一定的细节。
- FormatStyle.SHORT:短文本样式,通常是数字。
自定义的格式
- ofPattern(“yyyy-MM-dd hh:mm:ss”)
常用的方法
- ofPattern(String pattern) 静态方法 , 返 回 一 个 指 定 字 符 串 格 式 的DateTimeFormatter
- format(TemporalAccessor t) 格式化一个日期、时间,返回字符串
- parse(CharSequence text) 将指定格式的字符序列解析为一个日期、时间
代码演示:
public void testDTF() {
//方式一:预定义的标准格式。如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME
DateTimeFormatter isoLocalDate = DateTimeFormatter.ISO_LOCAL_DATE;
//格式化:日期-->字符串
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime + "-->" + isoLocalDate.format(localDateTime)); // => 2021-10-16T19:20:14.506-->2021-10-16
//解析:字符串 -->日期
DateTimeFormatter isoLocalDateTime = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
System.out.println(isoLocalDateTime.parse("2021-10-10T12:34:27.121")); // => {},ISO resolved to 2021-10-10T12:34:27.121
// 方式二:
// 本地化相关的格式。如:ofLocalizedDateTime()
// FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT :适用于LocalDateTime
DateTimeFormatter dateTimeFormatter0 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL)
.withZone(ZoneId.of("Asia/Shanghai"));
System.out.println("FULL: " + dateTimeFormatter0.format(LocalDateTime.now())); // => FULL:2021年10月10日 星期日 下午01时10分24秒 CT
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);
System.out.println("MEDIUM: " + dateTimeFormatter.format(LocalDateTime.now())); // => MEDIUM: 2021-10-10 12:56:17
DateTimeFormatter dateTimeFormatter1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);
System.out.println("LONG: " + dateTimeFormatter1.format(LocalDateTime.now())); // => LONG: 2021年10月10日 下午12时56分17秒
DateTimeFormatter dateTimeFormatter2 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);
System.out.println("SHORT: " + dateTimeFormatter2.format(LocalDateTime.now())); // => SHORT:21-10-10 下午12:58
// 解析
TemporalAccessor parse = dateTimeFormatter1.parse("2021年10月10日 下午12时56分17秒");
System.out.println(dateTimeFormatter2.format(parse)); // => 21-10-10 下午12:56
// 重点: 方式三:自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”)
DateTimeFormatter pa = DateTimeFormatter.ofPattern("yyyy-MM-dd EEE HH:mm:ss");
TemporalAccessor parse1 = pa.parse("2021-10-09 星期六 05:57:58");
System.out.println(dateTimeFormatter0.format(parse1)); // => 2021年10月9日 星期六 上午05时57分58秒 CT
}
- ZoneId:该类中包含了所有的时区信息,一个时区的ID,如 Europe/Paris
- ZonedDateTime:一个在ISO-8601日历系统时区的日期时间,如 2021-10-16T20:15:30+01:00 Europe/Paris。 其中每个时区都对应着ID,地区ID都为“{区域}/{城市}”的格式,例如:Asia/Shanghai等。
- Clock:使用时区提供对当前即时、日期和时间的访问的时钟。以前用到System.currentTimeInMillis()和TimeZone.getDefault()的地方都可用Clock替换。
- 持续时间:Duration,用于计算两个“时间”间隔
- 日期间隔:Period,用于计算两个“日期”间隔
- TemporalAdjuster : 时间校正器。有时我们可能需要获取例如:将日期调整到“下一个工作日”等操作。
- TemporalAdjusters : 该类通过静态方法(firstDayOfXxx()/lastDayOfXxx()/nextXxx())提供了大量的常用TemporalAdjuster 的实现。
代码演示:
public void testNewAPI(){
//以前用到System.currentTimeInMillis()和TimeZone.getDefault()的地方都可用Clock替换。
// Z 代表世界时(协调时,UTC)
Clock clock = Clock.systemDefaultZone();
Clock clock1 = Clock.systemUTC();
// 可以自由设置时区,获取相应的时间
Clock clock2 = Clock.system(ZoneId.of("Asia/Tokyo"));
System.out.println(clock.getZone() + "\t" + clock1.getZone() + " \t" + clock2.getZone()); // =>Asia/Shanghai Z Asia/Tokyo
System.out.println(clock + "\t" + TimeZone.getDefault().getID()); // =>SystemClock[Asia/Shanghai] Asia/Shanghai
System.out.println(clock.millis() + "\t" + System.currentTimeMillis()); // => 1634440421440 1634440421440
// 打印上海时间、UTC时间和东京时间
LocalDateTime nowShanghai = LocalDateTime.now(clock);
LocalDateTime nowUTC = LocalDateTime.now(clock1);
LocalDateTime nowTokyo = LocalDateTime.now(clock2);
System.out.println(nowShanghai); // => 2021-10-16T11:16:00.246
System.out.println(nowUTC); // => 2021-10-16T03:16:00.246
System.out.println(nowTokyo); // => 2021-10-16T12:16:00.246
//ZoneId:类中包含了所有的时区信息
// ZoneId的getAvailableZoneIds():获取所有的ZoneId
Set zoneIds = ZoneId.getAvailableZoneIds();
System.out.println("所有的时区信息: ");
for (String s : zoneIds) {
System.out.print(s + "\t");
}
System.out.println();
// ZoneId的of():获取指定时区的时间
LocalDateTime localDateTime = LocalDateTime.now(ZoneId.of("Asia/Tokyo"));
System.out.println(localDateTime); // => 2021-10-17T00:50:57.604
//ZonedDateTime:带时区的日期时间
// ZonedDateTime的now():获取本时区的ZonedDateTime对象
ZonedDateTime zonedDateTime = ZonedDateTime.now();
System.out.println(zonedDateTime); // => 2021-10-16T23:50:57.718+08:00[Asia/Shanghai]
// ZonedDateTime的now(ZoneId id):获取指定时区的ZonedDateTime对象
ZonedDateTime zonedDateTime1 = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
System.out.println(zonedDateTime1); // => 2021-10-17T00:50:57.719+09:00[Asia/Tokyo]
//Duration:用于计算两个“时间”间隔,以秒和纳秒为基准
LocalTime localTime = LocalTime.now();
LocalTime localTime1 = LocalTime.of(15, 23, 32);
//between():静态方法,返回Duration对象,表示两个时间的间隔
Duration duration = Duration.between(localTime1, localTime);
System.out.println(duration); // => PT8H27M25.719S
System.out.println(duration.getSeconds()); // => 30445
System.out.println(duration.getNano()); // => 719000000
LocalDateTime localDateTime1 = LocalDateTime.of(2016, 6, 12, 15, 23, 32);
LocalDateTime localDateTime2 = LocalDateTime.of(2027, 9, 12, 15, 23, 32);
Duration duration1 = Duration.between(localDateTime1, localDateTime2);
System.out.println(duration1.toDays()); // => 365
//Period:用于计算两个“日期”间隔,以年、月、日衡量
LocalDate localDate = LocalDate.now();
LocalDate localDate1 = LocalDate.of(2028, 3, 18);
Period period = Period.between(localDate, localDate1);
System.out.println(period); // => P6Y5M2D
System.out.println(period.getYears()); // => 6
System.out.println(period.getMonths());// => 5
System.out.println(period.getDays()); // => 2
Period period1 = period.withYears(2);
System.out.println(period1); // => P2Y5M2D
// TemporalAdjuster:时间校正器
// 获取当前日期的下一个周日是哪天?
TemporalAdjuster temporalAdjuster = TemporalAdjusters.next(DayOfWeek.SUNDAY);
LocalDateTime localDateTime3 = LocalDateTime.now().with(temporalAdjuster);
System.out.println(localDateTime3); // => 2021-10-17T23:50:57.735
// 获取下一个工作日是哪天?
LocalDate localDate3 = LocalDate.now().with(new TemporalAdjuster() {
@Override
public Temporal adjustInto(Temporal temporal) {
LocalDate date = (LocalDate) temporal;
if (date.getDayOfWeek().equals(DayOfWeek.FRIDAY)) {
return date.plusDays(3);
} else if (date.getDayOfWeek().equals(DayOfWeek.SATURDAY)) {
return date.plusDays(2);
} else {
return date.plusDays(1);
} }
});
System.out.println("下一个工作日是:" + localDate3); // => 下一个工作日是:2021-10-18
}
以上内容是作者对JDK8的日期时间API的理解和实操,难免会有错误和不足,还望读者能发现其中的错误,及时留言评论,一同进步。
最后,具体的学习还应该返璞归真,查阅API文档。
路漫漫其修远兮,吾将上下而求索。 ---屈原