不灭的焱

革命尚未成功,同志仍须努力下载JDK17

作者:Albert.Wen  添加时间:2023-06-20 23:32:13  修改时间:2024-05-06 13:01:46  分类:Java基础  编辑

目录

前言

Java8中引入了两个与日期相关的新类

  • Period - 计算两个“日期”间隔的类
  • Duration - 计算两个“时间”间隔的类

Period 类与 Duration 类都是一段持续时间的概念,如果需要对比时间,它们就需要一个固定的时间值,所以就需要 LocalDate 类与 Instant 、LocalTime、LocalDateTime类来配合它们使用:

  • Period 对应使用 LocalDate ,它们的作用范围域都是日期(年/月/日)
  • Duration 对应使用 Instant、LocalTime、LocalDateTime,它们的作用范围域都是时间(天/时/分/秒/毫秒/纳秒)

一、Duration - 计算两个“时间”间隔的类

Duration 表示一个时间段,Duration 包含两部分:seconds 表示秒,nanos 表示纳秒,它们的组合表达了时间长度。

因为 Duration 表示时间段,所以 Duration 类中不包含 now() 静态方法。注意,Duration 不包含毫秒这个属性。

Duration只能处理两个时间类,例如LocalTime, LocalDateTime, ZonedDateTime; 如果传入的是LocalDate,将会抛出异常。

Duration默认输出格式为PTnHnMnS,如PT8H6M12.345S
以PT前缀开头,H:小时 M:分钟 S:秒
当Duration为0时,默认为:PT0S

1.1、Duration常用API:

方法 说明
static Duration between(Temporal startInclusive, Temporal endExclusive) 计算两个时间的间隔,默认是秒
boolean isNegative() 检查Duration实例是否小于0,若小于0返回true, 若大于等于0返回false
long toDays() 将时间转换为以天为单位的long值
long toHours() 将时间转换为以时为单位的long值
long toMinutes() 将时间转换为以分钟为单位的long值
long toSeconds() 将时间转换为以秒为单位的long值
long toMillis() 将时间转换为以毫秒为单位的long值
long toNanos() 将时间转换为以纳秒为单位的long值

使用示例:

LocalDateTime start = LocalDateTime.parse("2007-12-03T10:15:30");
LocalDateTime end = LocalDateTime.parse("2007-12-05T10:25:33");

//between的用法是end-start的时间,若start的时间大于end的时间,则所有的值是负的
Duration duration = Duration.between(start, end);

String timeString = duration.toString(); //此持续时间的字符串表示形式,使用基于ISO-8601秒*的表示形式,例如 PT8H6M12.345S
System.out.println("相差的天数="+duration.toDays());
System.out.println("相差的小时="+ duration.toHours());
System.out.println("相差的分钟="+duration.toMinutes());
System.out.println("相差的秒数="+duration.toSeconds());
System.out.println("相差的毫秒="+duration.toMillis());
System.out.println("相差的纳秒="+duration.toNanos());
System.out.println("timeString时间="+timeString);

//isNegative返回Duration实例对象是否为负 
System.out.println(Duration.between(start, end).isNegative());//false  end-start为正,所以此处返回false
System.out.println(Duration.between(end, start).isNegative());//true   start-end为负,所以此处返回true
System.out.println(Duration.between(start, start).isNegative());//false start-start为0,所以此处为false

执行结果:

相差的天数=2
相差的小时=48
相差的分钟=2890
相差的秒数=173403
相差的毫秒=173403000
相差的纳秒=173403000000000
timeString时间=PT48H10M3S

1.2、计算两个“时间”间隔

方法一:【推荐】通过Duration计算两个LocalTime相差的时间

LocalTime start = LocalTime.parse("10:51:01.167526700");
LocalTime end = LocalTime.parse("15:52:03.167526701");

//between的用法是end-start的时间,若start的时间大于end的时间,则所有的值是负的
Duration duration = Duration.between(start, end);
System.out.println("两个时间相差:"+duration.toSeconds()+"秒,相差:"+duration.toHours()+"小时,相差:"+duration.toMinutes()+"分钟");

输出:

两个时间相差:18062秒,相差:5小时,相差:301分钟

方法二:ChronoUnit也可以计算两个单元之间的差值。

我们使用ChronoUnit类的between() 方法来执行相同的操作

LocalTime start = LocalTime.parse("10:51:01.167526700");
LocalTime end = LocalTime.parse("15:52:03.167526701");

long seconds = ChronoUnit.SECONDS.between(start , end );
long hour = ChronoUnit.HOURS.between(start , end );
long minute = ChronoUnit.MINUTES.between(start , end );

System.out.println("两个时间相差:"+seconds+"秒,相差:"+hour+"小时,相差:"+minute+"分钟");

输出:

两个时间相差:18062秒,相差:5小时,相差:301分钟

方法三:调用LocalDateTime类的.until方法,返回 总的相差的年数、月数、天数、时、分、秒

// 代码略(看文章后面的.until方法示例)

方法四:通过LocalTime类的toSecondOfDay()方法,返回时间对应的秒数,然后计算出两个时间相差的间隔

LocalTime start = LocalTime.parse("10:51:01.167526700");
LocalTime end = LocalTime.parse("15:52:03.167526701");

int time = end.toSecondOfDay() - start.toSecondOfDay();
System.out.println("两个时间相差:"+time+"秒");

输出:

两个时间相差:18062秒

1.3、计算两个“时间戳”间隔

项目中经常会有时间戳的值,下面的示例一起看一下如何比较时间戳。

long todayTimeMillis = System.currentTimeMillis();
long yesterdayTimeMillis = todayTimeMillis - 24 * 60 * 60 * 1000;
//通过Instant类,可以直接将毫秒值转换为Instant对象
Instant yesterday = Instant.ofEpochMilli(yesterdayTimeMillis);
Instant today = Instant.ofEpochMilli(todayTimeMillis);

Duration duration = Duration.between(yesterday, today);
System.out.println("天数 = "+duration.toDays()); //天数 = 1

二、Period - 计算两个“日期”间隔的类

Period 在概念上和 Duration 类似,区别在于 Period 是以年月日来衡量一个时间段。Duration 用于计算两个时间间隔,Period 用于计算两个日期间隔,所以 between() 方法只能接收 LocalDate 类型的参数。

说明:

Period可以用于计算两个“日期”之间的间隔,但是得到的是年月日,如两个日期相差1年2月3天,但是没办法知道1年2月3天具体是多少天,下面有讲通过调用ChronoUnit.between()方法计算两个单元相差的天数、月数、年数…

Period默认输出格式为PnYnMnD,如P2021Y12M3D
以P前缀开头,Y:年 M:月份 D:天
当Period为0时,默认为:P0D

2.1、Period常用API:

方法 说明
static Period between(LocalDate startDateInclusive, LocalDate endDateExclusive) 计算两个日期之间的间隔
boolean isNegative() 检查此时间段的三个单位中是否有一个为负数。这将检查年,月或天的单位是否小于零。如果此期间的任何单位为负,则为true
int getYears() 获取年
int getMonths() 获取月
int getDays() 获取日
Period p = Period.of(2021, 12, 3);
System.out.println("年月日:"+p);
p = Period.ofYears(1);
System.out.println("年:"+p);
p = Period.ofWeeks(2);
System.out.println("周的天数"+p);

Period period = Period.of(2021,-1,8);
System.out.println("校验年月日任何一位值是否有负数:{}",period.isNegative());//true

输出:

年月日:P2021Y12M3D
年:P1Y
周的天数P14D

注意

  • getYears()、getMonths()、getDays()只能输出Period中的年月日。像如下的示例,想知道两个日期相差多少天需要用ChronoUnit.between()方法。
LocalDate start = LocalDate.of(2020,2,28);
LocalDate end = LocalDate.of(2021,12,3);
Period period = Period.between(start,end);
System.out.println("两个时间之间的差值  年:"+period.getYears()+",月:"+period.getMonths()+",日:"+period.getDays());

输出:

两个时间之间的差值  年:1,月:9,日:5

2.2、计算两个日期相差的具体天数

方法一:ChronoUnit也可以计算两个单元之间的天数、月数或年数。

我们使用ChronoUnit类的between() 方法来执行相同的操作:

LocalDate start = LocalDate.of(2020,2,28);
LocalDate end = LocalDate.of(2021,12,3);
long seconds = ChronoUnit.DAYS.between(start , end );
// 结果:644
long month= ChronoUnit.MONTHS.between(start , end );
// 结果:21
long year= ChronoUnit.YEARS.between(start , end );
// 结果:1

方法二:调用LocalDate类的.until方法,返回 总的相差的年数、月数与天数

// 指定转换格式
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
 
LocalDate startDate = LocalDate.parse("2019-03-01",fmt);
LocalDate endDate = LocalDate.parse("2020-04-02",fmt);
 
System.out.println("总相差的天数:" + startDate.until(endDate, ChronoUnit.DAYS));
System.out.println("总相差的月数:" + startDate.until(endDate, ChronoUnit.MONTHS));
System.out.println("总相差的年数:" + startDate.until(endDate, ChronoUnit.YEARS));

输出:

总相差的天数:398
总相差的月数:13
总相差的年数:1

方法三:调用LocalDate类的toEpochDay方法,返回距离1970年1月1日的long值

此方法只能计算两个LocalDate日期间的天数,不能计算月份、年数

LocalDate start = LocalDate.of(2020,2,28);
LocalDate end = LocalDate.of(2021,12,3);

System.out.println("两个时间之间的相差的天数: "+(end.toEpochDay()-start.toEpochDay())); //644