Java 1.8 时间功能

3
因此,Java 1.8引入了一系列新的(和旧的)类来管理时间计算:java.time.Instantjava.time.LocalTimejava.time.temporal.ChronoUnit,可能还有其他的...

但是为什么没有简单的方法来计算它们之间的时间差呢?我期望“time_later - time_earlier”是最常用的时间操作,但是这似乎无从下手。我不能将一个 LocalTime 减去另一个 LocalTime 并得到一个新的 LocalTime;我也不能将一个 Instant 减去另一个 Instant 并得到一个新的 Instant。相反,我必须使用 ChronoUnits.between 和长整型毫秒等杂项来实现这个非常有用的事情。

为什么会这样呢?肯定有什么我不理解的东西吧?或者我只是太蠢了...?


因为Java仅为原始类型定义运算符。主要问题是获取两个时间之间的差异并不简单。闰年/秒怎么办?不同的时区?夏令时?本地时间不连续性? - Boris the Spider
5
不,它不可用因为对于time1 - time2该做什么还没有清晰的想法!请参见上文。 - Boris the Spider
计算两个日期/时间之间的差异实际上非常复杂,当你考虑到闰年、千年和世纪边界等因素时,这就是为什么我们有一个Duration类。请查看日期和时间以获取更多详细信息。 - MadProgrammer
1
当飞行时,航班时间通常基于从旅客的角度观察到的时间长度。这并不意味着10小时的飞行将使您向后或向前推进10小时。 - MadProgrammer
@OppfinnarJocke 请更新你的问题标题以更准确地匹配其内容。 - Basil Bourque
显示剩余2条评论
4个回答

4
在Java 8之前,对于你的问题通常的答案是“使用Joda Time”。

但是Joda Time的作者Stephen Colebourne深度参与了Java 8新的时间类和方法的开发。以下是两篇非常好的文章:

针对您的具体问题,您可能需要考虑Java 8中的“Duration”、“LocalTime”、“LocalDate”和/或“LocalTimeDate”(还有其他选项):

// A duration of 3 seconds and 5 nanoseconds
Duration duration = Duration.ofSeconds(3, 5);
Duration oneDay = Duration.between(today, yesterday);

// Tomorrow
LocalDate tomorrow = LocalDate.now().plusDays(1);

// Yesterday
LocalDate yesterday = LocalDate.now().plusDays(-1);

// before 5 houres and 30 minutes
LocalDateTime dateTime = LocalDateTime.now().minusHours(5).minusMinutes(30);

我认为提问者已经知道Period或Duration等类,但他想要的是不可能实现的,详见我的答案。 - Meno Hochschild
1
FYI,Joda-Time 相对于 java.time 有一些优势。Joda-Time 和 java.time 都有各自的优缺点。幸运的是,如果我们在 import 语句上小心谨慎,我们可以同时使用两者。此外,还有一个 项目正在为 java.time 添加更多功能 - Basil Bourque

3

引用:

“我不能从一个LocalTime中减去另一个LocalTime并得到一个新的LocalTime”

这个想法基本上是错误的,主要原因是物理和数学方面的。像LocalTimeInstant等对象表示时间轴上的一个时间点。但是两个时间点之间的差异只能是持续时间,即时间长度。在数学上,您会得到另一维度的结果(点与线)。因此,两个时间点的相减操作不可能产生另一个时间点。

但是,在单位方面测量两个时间点之间的距离是有意义的,并且JSR-310(也称为java.time-package)支持此操作,正如您正确看到的那样。顺便说一下,持续时间/期间计算在某种程度上是有限制的(即没有混合年份、天数、小时-类似于Joda-Time的操作),但通常像ChronoUnit类中的between-methods并不是什么复杂的东西,“摆弄”起来很简单易懂。


是的,今天早上我意识到这是显而易见的答案。Instant、LocalTime等代表时间点,而对它们进行减法运算会生成一个时间间隔,这当然不能表示为一个时间点。我的错...谢谢。 - OppfinnarJocke
1
@OppfinnarJocke 嗯,我怀疑有些人已经将“日期”作为持续时间类型的替代品,因为 JDK 没有提供这样的类型。当然,这一直是一个危险的解决方法或者说肮脏的黑客技巧,因为有时人们也会忘记将时区设置为 UTC,然后甚至没有意识到奇怪的时区副作用... - Meno Hochschild

1
提供了计算两个时间点之间差异的方法。
Instant a = Instant.now().minusSeconds(2);
Instant b = Instant.now().plusSeconds(2);

Duration difference = Duration.between(a, b);

long secsBetween1 = a.until(b, ChronoUnit.SECONDS);
long secsBetween2 = ChronoUnit.SECONDS.between(a, b);

Duration 是表示一段时间的主要对象,Duration.between 是创建它的一个关键方法。

ChronoUnit.betweenTemporal.until 是略低级别的方法,以特定单位返回差异作为 long


0

你可以使用java.time.Instant.toEpochMilli()来获得所需的功能。这将为您提供与旧的java.util.Date.getTime()相同的功能。

只要您不必处理时区,Instant就是您所需要的全部。不要被其他所有东西搞混了。

如果您必须处理时区,则许多复杂性变得必要,尽管由于过度泛化而在包中存在一些额外的复杂性。


如果您不必处理时区,那么LocalXxx比Instant更合适,因为后者会让您回到遗留日期API的地狱中... - assylias
1
@assylias 实际上,如果您不必处理时区,则传统的日期 API 可以正常工作。只有当您需要开始在不同的时区中表达事物时,它才会成为一个问题。相比之下,如果您不小心使用 LocalXxx 类,可能会遇到各种麻烦;例如,它们不能用作时间戳,因为它们不标识单个时间点,而是不同时区中的不同时间点。 - Warren Dew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接