Duration(时间间隔,基于时间)

Duration 是基于时间的时间段(如 “34.5 秒”),以秒和纳秒为核心存储单位,也支持分钟、小时、天(1 天 = 24 小时,无视夏令时)等单位访问,与日期维度的 Period 对应。

Duration 用于表示两个时间点之间的时间间隔,主要用于处理短时间间隔,支持正负值(正表示时间在未来,负表示时间在过去)。尤其适合需要精确到秒 / 纳秒的场景(如程序执行时间统计、定时任务等)。

由于 Duration 的取值范围超出了长整型(long)的存储能力,为解决这一问题,此类通过两个字段存储持续时间:一个长整型(long)字段表示秒数,一个整型(int)字段表示 “秒内的纳秒数”(该字段的值始终在 0 到 999,999,999 之间)。

注意,Duration 被建模为“有方向的时间段”,这意味着其值可能为负。使用时需注意与 Period 的区别(Period 用于处理日期差),并合理选择时间单位转换方法。

  

常用方法及示例

创建 Duration 对象

Duration.ofXxx(long amount)

通过指定时间单位直接创建 Duration 实例,支持多种时间单位(从纳秒到天)。常用方法:

方法

说明

示例

ofNanos(long)

创建纳秒级间隔

Duration.ofNanos(1_000_000)

→ 1 毫秒

ofMillis(long)

创建毫秒级间隔

Duration.ofMillis(500)

→ 500 毫秒

ofSeconds(long)

创建秒级间隔(可额外加纳秒)

Duration.ofSeconds(60, 500_000_000)

→ 60.5 秒

ofMinutes(long)

创建分钟级间隔

Duration.ofMinutes(30)

→ 30 分钟

ofHours(long)

创建小时级间隔

Duration.ofHours(2)

→ 2 小时

ofDays(long)

创建天数间隔(按 24 小时计算)

Duration.ofDays(1)

→ 24 小时

Duration(时间间隔,基于时间)

注意:

  • 所有 ofXxx 方法都是静态方法,直接通过 Duration 类调用。

  • 参数为正数时表示正向间隔,负数时表示负向间隔。

  • 内部以秒 + 纳秒存储,无论输入单位如何,最终都会转换为这两个值。

示例代码:

package com.hxstrive.java_date_time.duration;

import java.time.Duration;

public class DurationOfExample {
    public static void main(String[] args) {
        Duration twoHours = Duration.ofHours(2);
        Duration halfMinute = Duration.ofSeconds(30);
        Duration oneAndHalfSecond = Duration.ofSeconds(1, 500_000_000); // 1秒 + 500纳秒
        
        System.out.println(twoHours); // PT2H(2小时)
        System.out.println(halfMinute); // PT30S(30秒)
        System.out.println(oneAndHalfSecond); // PT1.5S(1.5秒)
    }
}

运行结果:

PT2H
PT30S
PT1.5S

Duration.between(Temporal startInclusive, Temporal endExclusive)

计算两个时间点之间的间隔,返回一个 Duration 对象。两个参数必须是时间相关的 Temporal 类型(如 Instant、LocalTime、ZonedDateTime 等),且两个参数的类型必须兼容(例如不能一个是 LocalDate 另一个是 Instant)。

计算逻辑:

  • 结果 = 结束时间 - 开始时间(end - start)。

  • 若结束时间早于开始时间,返回负的 Duration(可通过 abs() 取绝对值)。

支持的时间类型:

  • 推荐搭配 Instant(计算 UTC 时间间隔)、LocalTime(计算当天时间间隔)使用。

  • 不支持 LocalDate(日期无时间信息,需用 Period 类)。

示例代码:

package com.hxstrive.java_date_time.duration;

import java.time.Duration;
import java.time.Instant;
import java.time.LocalTime;

public class DurationBetweenExample {
    public static void main(String[] args) {
        // 示例1:计算两个Instant之间的间隔(UTC时间)
        Instant start = Instant.parse("2025-09-19T10:00:00Z");
        Instant end = Instant.parse("2025-09-19T12:30:00Z");
        Duration interval = Duration.between(start, end);
        System.out.println(interval); // PT2H30M(2小时30分钟)
        
        // 示例2:计算两个LocalTime之间的间隔(当天时间)
        LocalTime morning = LocalTime.of(8, 30);
        LocalTime afternoon = LocalTime.of(15, 45);
        Duration workDuration = Duration.between(morning, afternoon);
        System.out.println(workDuration.toHours()); // 7(小时)
        
        // 示例3:结束时间早于开始时间(返回负间隔)
        Duration negativeDuration = Duration.between(end, start);
        System.out.println(negativeDuration); // PT-2H30M
        System.out.println(negativeDuration.abs()); // PT2H30M(取绝对值)
    }
}

运行结果:

PT2H30M
7
PT-2H-30M
PT2H30M

获取时间单位值

toDays()

将 Duration 转换为总天数(向下取整)。

计算逻辑:总秒数 ÷ 86400(1 天 = 24×60×60 秒),结果向下取整。

注意:仅包含完整的天数,不足 1 天的部分会被舍弃。

Duration duration = Duration.ofHours(30); // 30小时
System.out.println(duration.toDays()); // 1(30小时 = 1天6小时 → 仅取1天)

toHours()

将 Duration 转换为总小时数(包含天数折算的小时)。

计算逻辑:总秒数 ÷ 3600(1 小时 = 60×60 秒),结果向下取整。

注意:会将所有天数转换为小时后累加(1 天 = 24 小时)。

Duration duration = Duration.ofDays(2).plusHours(3); // 2天3小时
System.out.println(duration.toHours()); // 51(2×24 + 3 = 51小时)

toMinutes()

将 Duration 转换为总分钟数(包含天数和小时折算的分钟)。

计算逻辑:总秒数 ÷ 60(1 分钟 = 60 秒),结果向下取整。

注意:会将所有天数、小时转换为分钟后累加。

Duration duration = Duration.ofHours(2).plusMinutes(30); // 2小时30分钟
System.out.println(duration.toMinutes()); // 150(2×60 + 30 = 150分钟)

getSeconds()

获取 Duration 的总秒数(基础单位,包含所有时间折算)。直接返回内部存储的总秒数(包含天数、小时、分钟等所有单位折算)。例如:

Duration duration = Duration.ofMinutes(2).plusSeconds(30); // 2分30秒
System.out.println(duration.getSeconds()); // 150(2×60 + 30 = 150秒)

getNano()

获取 Duration 中不足 1 秒的纳秒部分(仅表示小数部分),范围 0~999,999,999(1 秒 = 10 亿纳秒)。

注意:不包含完整的秒数,仅用于补充 getSeconds() 实现高精度表示。

Duration duration = Duration.ofSeconds(5, 750_000_000); // 5秒 + 750毫秒(750,000,000纳秒)
System.out.println(duration.getSeconds()); // 5(总秒数)
System.out.println(duration.getNano());    // 750000000(纳秒部分)

  

加减操作

plusXxx(long amount)

在当前 Duration 基础上增加指定单位的时间,返回新的 Duration 实例。常用方法如下:

方法

功能描述

示例

plusNanos(long)

增加纳秒数

duration.plusNanos(1_000_000)

→ 增加 1 毫秒

plusMillis(long)

增加毫秒数

duration.plusMillis(500)

→ 增加 500 毫秒

plusSeconds(long)

增加秒数

duration.plusSeconds(30)

→ 增加 30 秒

plusMinutes(long)

增加分钟数

duration.plusMinutes(15)

→ 增加 15 分钟

plusHours(long)

增加小时数

duration.plusHours(2)

→ 增加 2 小时

plusDays(long)

增加天数(按 24 小时计算)

duration.plusDays(1)

→ 增加 24 小时

注意:

  • 参数 amount 可以是正数(增加)或负数(等于减少,建议优先使用 minusXxx 实现减少)。

  • 内部会自动处理单位转换(如增加 60 秒会转换为 1 分钟)。

示例代码:

package com.hxstrive.java_date_time.duration;

import java.time.Duration;

public class DurationPlusExample {
    public static void main(String[] args) {
        // 初始间隔:1小时
        Duration duration = Duration.ofHours(1);
        
        // 增加30分钟
        Duration plus30Minutes = duration.plusMinutes(30);
        System.out.println(plus30Minutes); // PT1H30M(1小时30分钟)
        
        // 再增加90秒(1分30秒)
        Duration plus90Seconds = plus30Minutes.plusSeconds(90);
        System.out.println(plus90Seconds); // PT1H31M30S(1小时31分30秒)
        
        // 增加1天(24小时)
        Duration plus1Day = plus90Seconds.plusDays(1);
        System.out.println(plus1Day.toHours()); // 25(总小时数)
    }
}

运行结果:

PT1H30M
PT1H31M30S
25

minusXxx(long amount)

在当前 Duration 基础上减少指定单位的时间,返回新的 Duration 实例。常用方法如下:

方法

功能描述

示例

minusNanos(long)

减少纳秒数

duration.minusNanos(500_000_000)

→ 减少 0.5 毫秒

minusMillis(long)

减少毫秒数

duration.minusMillis(1000)

→ 减少 1 秒

minusSeconds(long)

减少秒数

duration.minusSeconds(45)

→ 减少 45 秒

minusMinutes(long)

减少分钟数

duration.minusMinutes(20)

→ 减少 20 分钟

minusHours(long)

减少小时数

duration.minusHours(1)

→ 减少 1 小时

minusDays(long)

减少天数(按 24 小时计算)

duration.minusDays(1)

→ 减少 24 小时

注意:

  • 参数 amount 为正数时表示减少对应时间,负数时等效于增加(建议优先使用 plusXxx 实现增加)。

  • 若减少后结果为负数,会返回负的 Duration(可通过 abs() 方法取绝对值)。

示例代码:

import java.time.Duration;

public class DurationMinusExample {
    public static void main(String[] args) {
        // 初始间隔:3小时
        Duration duration = Duration.ofHours(3);
        
        // 减少1小时15分钟
        Duration minus1h15m = duration.minusHours(1).minusMinutes(15);
        System.out.println(minus1h15m); // PT1H45M(1小时45分钟)
        
        // 再减少2小时(结果为负数)
        Duration negativeDuration = minus1h15m.minusHours(2);
        System.out.println(negativeDuration); // PT-15M(负15分钟)
        
        // 取绝对值
        Duration absolute = negativeDuration.abs();
        System.out.println(absolute); // PT15M(15分钟)
    }
}

运行结果:

PT1H45M
PT-15M
PT15M

与 plus(Duration)/minus(Duration) 的区别:

  • plusXxx(long) / minusXxx(long) 直接按单位增加,更简洁(如 plusHours(2))。

  • plus(Duration) 用于累加另一个 Duration 对象(如 plus(Duration.ofHours(2)))。

// 初始间隔:3小时
Duration duration = Duration.ofHours(3);

// 累加1小时15分钟
Duration minus1h15m = duration.plus(Duration.ofHours(1)).plus(Duration.ofMinutes(15));
System.out.println(minus1h15m); // PT4H15M(4小时15分钟)

// 再累加2小时
Duration negativeDuration = minus1h15m.plus(Duration.ofHours(2));
System.out.println(negativeDuration); // PT6H15M(6小时15分钟)

这些方法使得 Duration 可以灵活地进行时间间隔的调整,适用于计算任务执行时间、调整超时设置等场景。

  

比较操作

compareTo(Duration other)

比较当前 Duration 与另一个 Duration 的大小关系,返回一个整数表示比较结果。

返回值规则:

  • 正数:当前 Duration 大于参数 Duration

  • 0:两个 Duration 相等

  • 负数:当前 Duration 小于参数 Duration

比较逻辑:基于时间间隔的总长度(纳秒级精度),先比较秒数,秒数相同则比较纳秒数。

示例代码:

package com.hxstrive.java_date_time.duration;

import java.time.Duration;

public class DurationCompareTo {
    public static void main(String[] args) {
        Duration d1 = Duration.ofHours(2);
        Duration d2 = Duration.ofMinutes(120); // 2小时(与d1相等)
        Duration d3 = Duration.ofHours(1);     // 1小时(小于d1)
        
        System.out.println(d1.compareTo(d2)); // 0(相等)
        System.out.println(d1.compareTo(d3)); // 1(d1 > d3)
        System.out.println(d3.compareTo(d1)); // -1(d3 < d1)
    }
}

运行结果:

0
1
-1

isZero()

判断当前 Duration 的时间间隔是否为 0 长度(即总时长为 0)。当 Duration 的总秒数和纳秒数均为 0 时返回 true,否则返回 false。适用于检查两个时间点是否完全相同、任务是否耗时为 0 等。

示例代码:

package com.hxstrive.java_date_time.duration;

import java.time.Duration;
import java.time.Instant;

public class DurationIsZero {
    public static void main(String[] args) {
        // 场景1:显式创建0长度的Duration
        Duration zero = Duration.ofSeconds(0);
        System.out.println(zero.isZero()); // true
        
        // 场景2:两个相同时间点的间隔
        Instant now = Instant.now();
        Duration sameTime = Duration.between(now, now);
        System.out.println(sameTime.isZero()); // true
        
        // 场景3:非零长度的Duration
        Duration oneHour = Duration.ofHours(1);
        System.out.println(oneHour.isZero()); // false
    }
}

运行结果:

true
true
false

isNegative()

判断当前 Duration 的时间间隔是否为 负值(即总时长小于 0)。当 Duration 的总时长小于 0 时返回 true,否则返回 false(包括 0 长度)。

示例代码:

package com.hxstrive.java_date_time.duration;

import java.time.Duration;
import java.time.Instant;

public class DurationIsNegative {
    public static void main(String[] args) {
        // 场景1:结束时间早于开始时间(负间隔)
        Instant earlier = Instant.parse("2025-09-19T10:00:00Z");
        Instant later = Instant.parse("2025-09-19T12:00:00Z");
        Duration negative = Duration.between(later, earlier); // later -> earlier 是反向
        System.out.println(negative.isNegative()); // true
        
        // 场景2:正常正向间隔(非负)
        Duration positive = Duration.between(earlier, later);
        System.out.println(positive.isNegative()); // false
        
        // 场景3:0长度间隔(非负)
        Duration zero = Duration.ofSeconds(0);
        System.out.println(zero.isNegative()); // false
    }
}

运行结果:

true
false
false

  

其他常用方法

multipliedBy(long factor)

将当前 Duration 时间间隔乘以指定系数,返回一个新的 Duration 实例(原实例不变)。参数 factor 表示乘数(可以是正数、负数或零)。注意:

  • 若乘数为正数,保持原间隔的正负性;若为负数,反转间隔的正负性

  • 若乘数为零,返回表示 "零间隔" 的 Duration

  • 内部通过对秒和纳秒分别乘以系数实现,可能导致精度溢出(超出范围时抛出 ArithmeticException)

示例代码:

package com.hxstrive.java_date_time.duration;

import java.time.Duration;

public class DurationMultipliedBy {
    public static void main(String[] args) {
        Duration original = Duration.ofHours(2); // PT2H(2小时)
        
        // 乘以正数:时间翻倍
        Duration doubled = original.multipliedBy(2);
        System.out.println(doubled); // PT4H(4小时)
        
        // 乘以负数:反转方向并缩放
        Duration negative = original.multipliedBy(-3);
        System.out.println(negative); // PT-6H(-6小时)
        
        // 乘以零:零间隔
        Duration zero = original.multipliedBy(0);
        System.out.println(zero); // PT0S(零秒)
    }
}

运行结果:

PT4H
PT-6H
PT0S

dividedBy(long divisor)

将当前 Duration 时间间隔除以指定系数,返回一个新的 Duration 实例(原实例不变)。参数 divisor 表示除数(必须是非零值,否则抛出 ArithmeticException)。注意:

  • 除法结果向下取整(截断小数部分)

  • 若除数为负数,结果的正负性与原间隔相反

  • 内部通过对总纳秒数进行除法运算实现

示例代码:

package com.hxstrive.java_date_time.duration;

import java.time.Duration;

public class DurationDividedBy {
    public static void main(String[] args) {
        Duration original = Duration.ofMinutes(15); // PT15M(15分钟)
        
        // 除以正数:时间减半
        Duration half = original.dividedBy(2);
        System.out.println(half); // PT7M30S(7分30秒)
        
        // 除以更大的数:向下取整
        Duration divided = original.dividedBy(4);
        System.out.println(divided); // PT3M(3分钟,截断剩余3分钟)
        
        // 负数除数:反转方向
        Duration negativeResult = original.dividedBy(-3);
        System.out.println(negativeResult); // PT-5M(-5分钟)
    }
}

运行结果:

PT7M30S
PT3M45S
PT-5M

abs()

返回当前 Duration 的绝对值(将负间隔转为正间隔,正间隔保持不变)。注意:

  • 仅影响间隔的正负性,不改变时间长度

  • 对于零间隔,返回自身(仍为零)

  • 常用于处理 Duration.between() 可能返回的负间隔情况

示例代码:

package com.hxstrive.java_date_time.duration;

import java.time.Duration;
import java.time.Instant;

public class DurationAbs {
    public static void main(String[] args) {
        // 计算一个负间隔(结束时间早于开始时间)
        Instant start = Instant.parse("2025-09-19T10:00:00Z");
        Instant end = Instant.parse("2025-09-19T08:00:00Z");
        Duration negative = Duration.between(start, end);
        System.out.println(negative); // PT-2H(-2小时)
        
        // 取绝对值
        Duration absolute = negative.abs();
        System.out.println(absolute); // PT2H(2小时)
        
        // 正数间隔取绝对值保持不变
        Duration positive = Duration.ofHours(3);
        System.out.println(positive.abs()); // PT3H(3小时)
    }
}

运行结果:

PT-2H
PT2H
PT3H

  

注意事项

精度处理

内部以秒 + 纳秒存储,超过 Long.MAX_VALUE 秒会抛出异常。

  • multipliedBy() 可能因数值过大导致溢出(如 Duration.ofSeconds(Long.MAX_VALUE).multipliedBy(2))

  • dividedBy() 采用截断除法(非四舍五入)

时间单位转换

  • toHours() 等方法返回的是总单位数(包含更小单位的折算),而 getHours() 仅返回小时部分(0-23)。

与日期类的交互

不能直接与 LocalDate 等日期类计算(需先转为 LocalDateTime)。

// 错误示例:LocalDate 没有时间信息,无法计算 Duration
Duration.between(LocalDate.now(), LocalDate.now().plusDays(1)); // 编译错误

运行抛出如下错误:

Exception in thread "main" java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Seconds
	at java.base/java.time.LocalDate.until(LocalDate.java:1636)
	at java.base/java.time.Duration.between(Duration.java:492)

  

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号