1. 概述
在Java中进行时间和持续时间计算时,TimeUnit
枚举提供了一种便捷的方式在不同时间单位间进行转换。
无论是将秒转换为分钟、毫秒转换为小时,还是执行其他任何时间单位转换,我们都可以使用TimeUnit
来简化代码、获得准确结果并提升可读性。
本教程将探讨如何使用TimeUnit
在Java中进行时间转换。
2. 理解TimeUnit
TimeUnit
是java.util.concurrent
包中的一个枚举,表示从纳秒到天的各种时间单位。它提供了一组预定义常量,每个常量对应特定的时间单位,包括:
-
DAYS
-
HOURS
-
MINUTES
-
SECONDS
-
MILLISECONDS
-
MICROSECONDS
-
NANOSECONDS
这些常量是时间转换的基础。
3. 使用TimeUnit
转换时间
执行时间转换时,我们需要一个表示待转换持续时间的值,并指定目标单位。**TimeUnit
提供了多种方法用于单位间转换**,如convert()
或toXXX()
(其中XXX
表示目标单位)。
3.1. 使用convert()
方法
首先看convert(long sourceDuration, TimeUnit sourceUnit)
方法,它将给定单位的时间持续时间转换为枚举值指定的单位。
将简单整数转换为分钟:
long minutes = TimeUnit.MINUTES.convert(60, TimeUnit.SECONDS);
assertThat(minutes).isEqualTo(1);
本例中,我们从60秒开始,将其转换为分钟。源时间单位作为第二个参数指定。输出单位始终由枚举值决定。
再看反向转换的例子:
long seconds = TimeUnit.SECONDS.convert(1, TimeUnit.MINUTES);
assertThat(seconds).isEqualTo(60);
可见,**convert()
方法可在不同时间单位间进行转换**。
3.2. 使用toXXX()
方法
现在探索toXXX(long sourceDuration)
方法。签名中的XXX
指定目标单位。
可选择toNanos()
、toMicros()
、toMillis()
、toSeconds()
、toMinutes()
、toHours()
和toDays()
。
使用toXXX()
方法重写之前的代码片段:
long minutes = TimeUnit.SECONDS.toMinutes(60);
assertThat(minutes).isEqualTo(1);
同样,我们将60秒转换为分钟。
反向转换:
long seconds = TimeUnit.MINUTES.toSeconds(1);
assertThat(seconds).isEqualTo(60);
结果与之前一致,两种签名等效。但与convert()
不同,使用toXXX()
时,枚举值代表源时间单位。
4. 特定用例
了解TimeUnit
方法的转换原理后,我们深入探讨一些具体场景。
4.1. 负输入处理
首先检查转换方法是否支持负输入值:
long minutes = TimeUnit.SECONDS.toMinutes(-60);
assertThat(minutes).isEqualTo(-1);
示例表明,转换方法也能正确处理负输入,返回结果依然准确。
4.2. 舍入处理
当将较小单位转换为较大单位(预期结果为非整数)时会发生什么?所有方法仅声明返回long
类型,因此无法返回小数结果。
通过秒转分钟测试舍入规则:
long positiveUnder = TimeUnit.SECONDS.toMinutes(59);
assertThat(positiveUnder).isEqualTo(0);
long positiveAbove = TimeUnit.SECONDS.toMinutes(61);
assertThat(positiveAbove).isEqualTo(1);
再测试负输入:
long negativeUnder = TimeUnit.SECONDS.toMinutes(-59);
assertThat(negativeUnder).isEqualTo(0);
long negativeAbove = TimeUnit.SECONDS.toMinutes(-61);
assertThat(negativeAbove).isEqualTo(-1);
所有转换均正常执行,无错误抛出。
注意:所有方法均实现向零舍入规则,直接截断小数部分。
4.3. 溢出处理
基本类型都有其值限制。当结果超出限制时会发生什么?
检查将天的最大/最小long
值转换为毫秒的结果:
long maxMillis = TimeUnit.DAYS.toMillis(Long.MAX_VALUE);
assertThat(maxMillis).isEqualTo(Long.MAX_VALUE);
long minMillis = TimeUnit.DAYS.toMillis(Long.MIN_VALUE);
assertThat(minMillis).isEqualTo(Long.MIN_VALUE);
代码执行无异常抛出。需注意:结果无效,因为溢出结果总是被截断为long
原语定义的最小/最大值。
5. 转换为最细粒度单位
有时需要将持续时间转换为TimeUnit
中最细粒度的单位组合(如将秒转换为小时、分钟和剩余秒)。可惜没有现成方法,因为所有转换方法总是返回给定持续期内完整周期的总数。
要转换为最细粒度单位,需自定义实现。以3672秒为例,期望得到1小时1分钟12秒的组合。
提取小时部分:
long inputSeconds = 3672;
long hours = TimeUnit.SECONDS.toHours(inputSeconds);
assertThat(hours).isEqualTo(1);
提取剩余分钟时,需从输入值中减去小时对应的秒数,再用差值计算:
long secondsRemainingAfterHours = inputSeconds - TimeUnit.HOURS.toSeconds(hours);
long minutes = TimeUnit.SECONDS.toMinutes(secondsRemainingAfterHours);
assertThat(minutes).isEqualTo(1);
成功计算出小时和分钟。最后提取剩余秒数:
long seconds = secondsRemainingAfterHours - TimeUnit.MINUTES.toSeconds(minutes);
assertThat(seconds).isEqualTo(12);
示例中,我们将3672毫秒转换为包含小时、分钟和秒的最细粒度表示。
6. 总结
本文探讨了使用Java的TimeUnit
枚举进行时间转换的多种方式。
TimeUnit
枚举通过convert()
和toXXX()
方法,提供了便捷高效的不同单位转换机制。
此外,它能正确处理负输入并返回准确结果。无论从小单位转大单位还是反向操作,均采用向零舍入规则。它还通过将结果截断为边界值,实现了基本的溢出保护。
若需将源持续时间转换为其他单位的组合(如天、小时、分钟和秒),可轻松实现附加逻辑。所有转换器均返回指定持续期内指定周期的总数。
如往常一样,示例源代码可在GitHub获取。