In the Joda-Time library, the DateTime class offers a method withTimeAtStartOfDay to get the first moment of the day. You might think of that moment as \"midnight\". That first
The equivalent is using a special method, atStartOfDay, in the class LocalDate:
ZoneId zoneId = ZoneId.of("America/New_York");
ZonedDateTime zdt = LocalDate.now(zoneId).atStartOfDay(zoneId);
Please also note that the equivalent of 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) transition in Brazil:
Joda-Time (old way)
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
Note that this code would even throw an exception for midnight in first line with call to constructor.
java.time (new way)
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]
The second program statement behaves differently than Joda-Time because it will not throw an exception but silently shifts the local time by the size of the gap in question, here one hour. This means, if you had chosen midnight, the result would be the same (namely at 1:00). If you had chosen 00:30, then the result would be 01:30. The example given above chooses noon as input.
To quote the doc for 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".
A 100%-migration of all details like exception behaviour and applied DST transition strategies is not possible because both libraries are too different. But that is your guideline:
DateTime
by ZonedDateTime
LocalDate
for intermediate calculations (see example)DateTimeZone
by ZoneId
You can use LocalDate
to do this:
// 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--
While this is an old question, I've just discovered another way to do this, using truncation, which to me feels more elegant:
ZonedDateTime now = ZonedDateTime.now();
ZonedDateTime today = now.truncateTo(ChronoUnit.DAYS); // today, midnight
This is shorter to type and requires fewer intermediate values in code. As far as I can tell, the semantics are the same as the accepted answer's.
TemporalAdjuster
Every LocalTime is also a TemporalAdjuster, so if can be passed to the with()
method of most temporal types and will update the time fields to match.
That is:
@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]")));
}