tl;博士
LocalDate // Represents an entire day, without time-of-day and without time zone.
.now( // Capture the current date.
ZoneId.of( "Asia/Tokyo" ) // Returns a `ZoneId` object.
) // Returns a `LocalDate` object.
.atStartOfDay( // Determines the first moment of the day as seen on that date in that time zone. Not all days start at 00:00!
ZoneId.of( "Asia/Tokyo" )
) // Returns a `ZonedDateTime` object.
开始新的一天
获取在时区中看到的今天的完整长度。
使用半开放式方法,其中开头是包容性的,而结尾是排他性的。这种方法解决了代码中未能解释当天最后一秒的缺陷。
ZoneId zoneId = ZoneId.of( "Africa/Tunis" ) ;
LocalDate today = LocalDate.now( zoneId ) ;
ZonedDateTime zdtStart = today.atStartOfDay( zoneId ) ;
ZonedDateTime zdtStop = today.plusDays( 1 ).atStartOfDay( zoneId ) ;
zdtStart.toString() = 2020-01-30T00:00+01:00[非洲/突尼斯]
zdtStop.toString() = 2020-01-31T00:00+01:00[非洲/突尼斯]
在 UTC 中查看相同的时刻。
Instant start = zdtStart.toInstant() ;
Instant stop = zdtStop.toInstant() ;
Z = 2020-01-29T23:00:00Z
z = 2020-01-30T23:00:00Z
如果希望日期的一整天以 UTC 而不是时区显示,请使用 。OffsetDateTime
LocalDate today = LocalDate.now( ZoneOffset.UTC ) ;
OffsetDateTime odtStart = today.atTime( OffsetTime.MIN ) ;
OffsetDateTime odtStop = today.plusDays( 1 ).atTime( OffsetTime.MIN ) ;
odtStart.toString() = 2020-01-30T00:00+18:00
odtStop.toString() = 2020-01-31T00:00+18:00
这些对象已经是 UTC 格式,但如果需要这些对象,可以调用这些对象,这些对象根据定义始终采用 UTC 格式。OffsetDateTime
toInstant
Instant start = odtStart.toInstant() ;
Instant stop = odtStop.toInstant() ;
开始时间:2020-01-29T06:00:00Z
z = 2020-01-30T06:00:00Z
提示: 您可能有兴趣将 ThreeTen-Extra 库添加到项目中,以使用其 Interval
类来表示这对对象。此类提供了有用的比较方法,如 、、 等。Instant
abuts
overlaps
contains
Interval interval = Interval.of( start , stop ) ;
时间:2020-01-29T06:00:00Z/2020-01-30T06:00:00Z
半开式
mprivat的答案是正确的。他的观点是不要试图获得一天的结束,而是与“第二天开始之前”进行比较。他的想法被称为“半开放”方法,其中时间跨度具有包容性的开始,而结束是排他性的。
- Java的当前日期时间框架(java.util.Date/Calendar和Joda-Time)都使用纪元的毫秒。但在Java 8中,新的JSR 310 java.time.*类使用纳秒分辨率。如果切换到新类,则基于强制一天中最后一刻的毫秒数计数编写的任何代码都是不正确的。
- 如果其他来源的数据采用其他解决方案,则比较这些数据会出错。例如,Unix库通常使用整整几秒钟,而Postgres等数据库将日期时间解析为微秒。
- 一些夏令时更改发生在午夜,这可能会进一步混淆事情。

Joda-Time 2.3为此提供了一种方法,以获得一天中的第一刻:withTimeAtStartOfDay()
。同样,在 java.time 中,.LocalDate::atStartOfDay
在 StackOverflow 中搜索“joda half-open”,查看更多讨论和示例。
请参阅比尔·施耐德(Bill Schneider)的这篇文章,时间间隔和其他范围应该是半开放的。
避免使用旧日期时间类
java.util.Date 和 .日历课程是出了名的麻烦。避免它们。
使用 java.time 类。java.time框架是非常成功的Joda-Time库的官方继承者。
java.time
java.time 框架内置于 Java 8 及更高版本中。在ThreeTen-Backport项目中向后移植到Java 6和7,在ThreeTenABP项目中进一步适应Android。
即时
是时间轴上以 UTC 为单位的一个时刻,分辨率为纳秒。
Instant instant = Instant.now();
应用时区以获取某个位置的挂钟时间。
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
要获得一天中的第一个时刻,请浏览LocalDate
类及其atStartOfDay
方法。
ZonedDateTime zdtStart = zdt.toLocalDate().atStartOfDay( zoneId );
使用半开式方法,获得第二天的第一刻。
ZonedDateTime zdtTomorrowStart = zdtStart.plusDays( 1 );

目前,java.time框架缺少一个类,如下所述的Joda-Time。但是,ThreeTen-Extra项目使用其他类扩展了java.time。这个项目是未来可能添加到java.time的试验场。它的类之一是间隔
。通过传递一对对象来构造 。我们可以从对象中提取一个。Interval
Interval
Instant
Instant
ZonedDateTime
Interval today = Interval.of( zdtStart.toInstant() , zdtTomorrowStart.toInstant() );
关于 java.time
java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧旧日期时间类,如java.util.Date
,Calendar
和SimpleDateFormat
。
要了解更多信息,请参阅 Oracle 教程。搜索 Stack Overflow 以获取许多示例和解释。规格是JSR 310。
Joda-Time 项目现在处于维护模式,建议迁移到 java.time 类。
您可以直接与数据库交换 java.time 对象。使用符合 JDBC 4.2 或更高版本的 JDBC 驱动程序。不需要字符串,不需要类。Hibernate 5 & JPA 2.2 支持 java.time。java.sql.*
从哪里获取 java.time 类?
城大时间
更新:Joda-Time项目现在处于维护模式,并建议迁移到java.time类。我将这一部分保留为历史。
Joda-Time 有三个类,以各种方式表示时间跨度:、 和 。An在宇宙的时间轴上有一个特定的开始和结束。这符合我们表示“一天”的需要。Interval
Period
Duration
Interval
我们调用该方法,而不是将一天中的时间设置为零。由于夏令时和其他异常,一天中的第一刻可能不是 。withTimeAtStartOfDay
00:00:00
使用Joda-Time 2.3的示例代码。
DateTimeZone timeZone = DateTimeZone.forID( "America/Montreal" );
DateTime now = DateTime.now( timeZone );
DateTime todayStart = now.withTimeAtStartOfDay();
DateTime tomorrowStart = now.plusDays( 1 ).withTimeAtStartOfDay();
Interval today = new Interval( todayStart, tomorrowStart );
如果必须,可以转换为 java.util.Date。
java.util.Date date = todayStart.toDate();