java.time 相当于 Joda-Time `withTimeAtStartOfDay`? (获取当天的第一刻)

java.time equivalent of Joda-Time `withTimeAtStartOfDay`? (get first moment of the day)

Joda-Time library, the DateTime class offers a method withTimeAtStartOfDay获得当天的第一刻。您可能会认为那一刻是 "midnight"。第一时刻通常是 00:00:00.000 但并非总是如此。

在 Java 8 及更高版本中找到的 java.time package 是否具有等效功能?

您可以使用 LocalDate 来执行此操作:

// or a similar factory method to get the date you want
LocalDateTime startOfDay = LocalDate.now().atStartOfDay();

Combines this date with the time of midnight to create a LocalDateTime at the start of this date. This returns a LocalDateTime formed from this date at the time of midnight, 00:00, at the start of this date.

https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html#atStartOfDay--

等同于使用一种特殊的方法,atStartOfDay, in the class LocalDate:

ZoneId zoneId = ZoneId.of("America/New_York");
ZonedDateTime zdt = LocalDate.now(zoneId).atStartOfDay(zoneId);

另请注意,在巴西相当于 Joda-Time DateTime is not LocalDateTime, but ZonedDateTime. The zoneId parameter matters here. Concrete example for migration - see also timezone website for details about Daylight Saving Time (DST) 转换:

Joda-Time(旧方法)

DateTime dt = 
  new DateTime(2015, 10, 18, 12, 0, DateTimeZone.forID("America/Sao_Paulo"));
dt = dt.withTimeAtStartOfDay();
System.out.println(dt); // 2015-10-18T01:00:00.000-02:00

请注意,此代码甚至会在调用 constructor.

的第一行中为午夜抛出异常

java.time(新方式)

ZoneId zoneId = ZoneId.of("America/Sao_Paulo");
ZonedDateTime zdt =
  ZonedDateTime.of(2015, 10, 18, 12, 0, 0, 0, zoneId);
zdt = zdt.toLocalDate().atStartOfDay(zoneId);
System.out.println(zdt); // 2015-10-18T01:00-02:00[America/Sao_Paulo]

第二个程序语句的行为与 Joda-Time 不同,因为它不会抛出异常,而是悄悄地将本地时间移动所讨论的时间间隔的大小,这里是一小时。这意味着,如果您选择了午夜,结果将是相同的(即 1:00)。如果您选择了 00:30,那么结果将是 01:30。上面给出的示例选择中午作为输入。

引用 ZonedDateTime.of(…) 的文档:

In most cases, there is only one valid offset for a local date-time. In the case of an overlap, when clocks are set back, there are two valid offsets. This method uses the earlier offset typically corresponding to "summer".

In the case of a gap, when clocks jump forward, there is no valid offset. Instead, the local date-time is adjusted to be later by the length of the gap. For a typical one hour daylight savings change, the local date-time will be moved one hour later into the offset typically corresponding to "summer".

不可能 100% 迁移所有细节,例如异常行为和应用的 DST 转换策略,因为两个库差异太大。但这是你的指导方针:

  • DateTime替换为ZonedDateTime
  • 考虑切换到 LocalDate 进行中间计算(参见示例)
  • 使用对时区的显式引用并将 DateTimeZone 替换为 ZoneId

TemporalAdjuster

每个 LocalTime is also a TemporalAdjuster,所以如果可以传递给大多数时间类型的 with() 方法,并将更新时间字段以匹配。

即:

@Test
public void date_time_at_start_of_day() throws Exception {
    assertThat(LocalDateTime.parse("2015-05-22T12:27:00")
                            .with(LocalTime.MIDNIGHT),
               equalTo(LocalDateTime.parse("2015-05-22T00:00:00")));
    assertThat(OffsetDateTime.parse("2015-05-22T12:27:00+01:00")
                             .with(LocalTime.MIDNIGHT),
               equalTo(OffsetDateTime.parse("2015-05-22T00:00:00+01:00")));
    assertThat(ZonedDateTime.parse("2015-05-22T12:27:00+01:00[Europe/London]")
                            .with(LocalTime.MIDNIGHT),
               equalTo(ZonedDateTime.parse("2015-05-22T00:00:00+01:00[Europe/London]")));
}

Java时间truncatedTo

虽然这是一个老问题,但我刚刚发现了另一种方法,使用 truncation,对我来说感觉更优雅:

ZonedDateTime now = ZonedDateTime.now();
ZonedDateTime today = now.truncatedTo(ChronoUnit.DAYS); // today, midnight

这更便于输入,并且在代码中需要更少的中间值。据我所知,语义与接受的答案相同。