tl;博士
例如,如果 startTime 为 23:00,endTime 为 1:00,则持续时间为 2:00。
不可能。如果您只有一天中的时间,则时钟会在午夜停止。如果没有日期的上下文,我们怎么知道您是指第二天、下周还是下一个十年的凌晨 1 点?
因此,从晚上 11 点到凌晨 1 点意味着时间向后移动 22 小时,逆时针转动时钟的指针。请参阅下面的结果,否定 22 小时。
Duration.between( // Represent a span of time a total number of seconds plus a fractional second in nanoseconds.
LocalTime.of( 23 , 0 ) , // A time-of-day without a date and without a time zone.
LocalTime.of( 1 , 0 ) // A time-of-day clock stops at midnight. So getting to 1 AM from 11 PM means going backwards 22 hours.
) // Return a `Duration` object.
.toString() // Generate a `String` representing this span of time using standard ISO 8601 format: PnYnMnDTnHnMnS
PT-22H
除了时间之外,跨越午夜还需要更大的日期上下文(见下文)。
如何在 Java 中测量经过的时间?
- 使用
Instant.now() 捕捉UTC 中的当前时刻。
- 稍后再拍摄一个这样的时刻。
- 将两者都传递给
Duration.between。
- (a) 从生成的
Duration 对象中,通过调用各种 to…Part 方法,提取 24 小时天数、小时、分钟、秒和小数秒(以纳秒为单位)。
(b) 或, 调用toString 在standard ISO 8601 format 的PnYnMnDTnHnMnS 中生成一个String。
示例代码,使用一对 Instant 对象。
Duration.between( // Represent a span of time a total number of seconds plus a fractional second in nanoseconds.
then , // Some other `Instant` object, captured earlier with `Instant.now()`.
Instant.now() // Capture the current moment in UTC with a resolution as fine as nanoseconds, depending on the limits of your host computer hardware clock and operating system. Generally you will get current moment in microseconds (six decimal digits of fractional second) in Java 9, 10, and 11, but only milliseconds in Java 8.
) // Return a `Duration` object.
.toString() // Generate a `String` representing this span of time using standard ISO 8601 format: PnYnMnDTnHnMnS
PT3M27.602197S
Java 8+ 中的新技术
我们现在在 Java 8 及更高版本中内置了这方面的新技术,java.time 框架。
java.time
java.time 框架由JSR 310 定义,灵感来自非常成功的Joda-Time 项目,由ThreeTen-Extra 项目扩展,并在Oracle Tutorial 中进行了描述。
Java.util.Date/.Calendar 等旧的日期时间类与 Java 的最早版本捆绑在一起,已被证明设计不佳、令人困惑和麻烦。它们被 java.time 类所取代。
分辨率
其他答案讨论解决方案。
java.time 类具有nanosecond 分辨率,最多为一秒的十进制小数的九位。例如,2016-03-12T04:29:39.123456789Z。
旧的 java.util.Date/.Calendar 类和 Joda-Time 类都具有毫秒分辨率(3 位小数)。例如,2016-03-12T04:29:39.123Z。
在 Java 8 中,由于遗留问题,当前时刻的获取分辨率最高仅为毫秒。在 Java 9 及更高版本中,如果您的计算机的硬件时钟运行良好,则当前时间可以被确定为纳秒级分辨率。
时间
如果您真的只想使用缺少任何日期或时区的时间,请使用 LocalTime 类。
LocalTime sooner = LocalTime.of ( 17, 00 );
LocalTime later = LocalTime.of ( 19, 00 );
Duration 表示时间跨度,它以秒数加上纳秒数表示。
Duration duration = Duration.between ( sooner, later );
转储到控制台。
System.out.println ( "sooner: " + sooner + " | later: " + later + " | duration: " + duration );
较早:17:00 |稍后:19:00 |持续时间:PT2H
ISO 8601
注意Duration::toString 的默认输出是标准ISO 8601 格式。在这种格式中,P 标志着开始(如“期间”),T 将任何年-月-日部分与小时-分钟-秒部分分开。
穿越午夜
不幸的是,只有当您绕着时钟穿过午夜时,处理时间才会变得棘手。 LocalTime 类通过假设您想回到当天的早些时候来处理这个问题。
使用与上述相同的代码,但从 23:00 变为 01:00 会导致负 22 小时 (PT-22H)。
LocalTime sooner = LocalTime.of ( 23, 0 );
LocalTime later = LocalTime.of ( 1, 0 );
更早:23:00 |稍后:01:00 |持续时间:PT-22H
日期时间
如果您打算跨过午夜,那么使用日期时间值而不是仅时间值可能对您来说是有意义的。
时区
时区对于日期至关重要。因此,我们指定了三个项目:(1) 所需日期,(2) 所需时间,以及 (3) 时区作为解释该日期和时间的上下文。这里我们随意选择Montréal区域的时区。
如果您仅通过 offset-from-UTC 定义日期,请使用 ZoneOffset 和 OffsetDateTime。如果您有一个完整的时区(偏移量加上处理异常情况的规则,例如夏令时),请使用 ZoneId 和 ZonedDateTime。
LocalDate localDate = LocalDate.of ( 2016, 1, 23 );
ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime sooner = ZonedDateTime.of ( localDate, LocalTime.of ( 23, 0 ), zoneId );
我们指定较晚的时间为第二天凌晨 1:00。
ZonedDateTime later = ZonedDateTime.of ( localDate.plusDays ( 1 ), LocalTime.of ( 1, 0 ), zoneId );
我们以与上述相同的方式计算Duration。现在我们得到了这个问题所期望的两个小时。
Duration duration = Duration.between ( sooner, later );
转储到控制台。
System.out.println ( "sooner: " + sooner + " | later: " + later + " | duration: " + duration );
较早:2016-01-23T23:00-05:00[美国/蒙特利尔] |稍后:2016-01-24T01:00-05:00[美国/蒙特利尔] |持续时间:PT2H
夏令时
如果手头的日期时间涉及夏令时 (DST) 或其他此类异常,java.time 类将根据需要进行调整。阅读课程文档了解详情。
关于java.time
java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date、Calendar 和 SimpleDateFormat。
Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。
要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。
您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。
从哪里获得 java.time 类?
ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如Interval、YearWeek、YearQuarter 和more。