42

The javdoc for LocalDate#toDateMidnight reads as follows:

As from v1.5, you are recommended to avoid DateMidnight and use toDateTimeAtStartOfDay() instead because of the exception detailed below.

This method will throw an exception if the default time zone switches to Daylight Savings Time at midnight and this LocalDate represents that switchover date. The problem is that there is no such time as midnight on the required date, and as such an exception is thrown.

The fact that midnight does not exist in certain time zones seems like reason enough to avoid using DateMidnight entirely (assuming your code is not using a fixed time zone that is known not to have this DST situation and will never need to use different time zones in the future).

However, DateMidnight is not deprecated and there is no similar recommendation or warning in the javadoc for the DateMidnight class itself. Furthermore, the DateMidnight constructor happily accepts an instant and time zone such that midnight does not exist on the given day, rather than throwing an IllegalArgumentException like LocalDate#toDateMidnight. The resulting DateMidnight behaves like a DateTime with time at start of day.

When midnight does not exist on a given day, why does LocalDate#toDateMidnight throw an exception while the DateMidnight constructor does not? What is the recommended use case for DateMidnight if any?

acdcjunior
  • 132,397
  • 37
  • 331
  • 304
oby1
  • 1,302
  • 1
  • 13
  • 20

6 Answers6

45

There is no good reason to use DateMidnight. LocalDate is the better option. Thats because midnight does not occur once a year in certain time-zones, completely messing up the usability of the class, and creating bugs in applications.

The constructor was fixed to avoid the worst problem, however seeing a DateMidnight object with the internal millisecond value pointing at 01:00 isn't exactly great.

JodaStephen
  • 60,927
  • 15
  • 95
  • 117
37

new DateTime().withTimeAtStartOfDay() is recommended.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
Jerome Anthony
  • 7,823
  • 2
  • 40
  • 31
  • Actually not just recommended. All of the “midnight” related classes and methods in Joda-Time have been deprecated with an explanation that they are based on a faulty concept. You absolutely should be using `withTimeAtStartOfDay` instead. – Basil Bourque Oct 02 '16 at 02:16
8

Or better use the LocalDate method toDateTimeAtStartOfDay directly to bypass creation of DateTime object (in relation to answer above).

new LocalDate().toDateTimeAtStartOfDay( myDateTimeZone )
Community
  • 1
  • 1
t7tran
  • 1,899
  • 1
  • 18
  • 16
4

tl;dr

Use java.time classes, specifically LocalDate::atStartOfDay instead of the slippery idea of “midnight”.

ZoneId z = ZoneId.of( "America/Montreal" );  // A time zone.
ZonedDateTime todayStart = LocalDate.now( z ).atStartOfDay( z );  // Produces a LocalDate (a whole day without time zone), then transforms into a `ZonedDateTime` (a moment on the timeline)

java.time

Since the Joda-Time project is now in maintenance mode, and the team advises migration to the java.time classes, I will add example using java.time.

If you want to represent the entire day as a whole, use the LocalDate class. The LocalDate class represents a date-only value without time-of-day and without time zone.

A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.

ZoneId z = ZoneId.of( “America/Montreal” );
LocalDate today = LocalDate.now( z );

As discussed on this page, trying to pinpoint the end of the day is poor practice. For one thing, you have the problem of an infinitely divisible fraction for that last second of the day. Do you resolve to milliseconds, microseconds, nanoseconds, or something else, as all of these are in common use? Instead use the first moment of the new day.

Let java.time determine the wall-clock time of that first moment of the day. Do not assume the time will be 00:00:00 as anomalies such as Daylight Saving Time (DST) may mean the first moment is a time such as 01:00:00. Such DST adjustments are currently use in time zones of multiple countries.

So, to get a moment, an actual point on the timeline, for the start of the day call LocalDate::atStartOfDay. Notice this is a shorter version of the method name than used in Joda-Time’s withTimeAtStartOfDay method. Specify the desired/expected time zone in a ZoneId to produce a ZonedDateTime object.

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = today.atStartOfDay( z );

Half-Open

So how to represent a span of time? If I want to pinpoint the the beginning and ending of this single day, how do I do that while also following this advice? The solution commonly used in date-time work is the Half-Open approach. In this approach, the beginning of the span is inclusive while the ending is exclusive. So “today” means starting with the first moment of the day and running all the way up to, but not including, the first moment of the following day.

ZonedDateTime zdtStartToday = LocalDate.now( z ).atStartOfDay( z );
ZonedDateTime zdtStartTomorrow = zdtStartToday.plusDays( 1 );

By the way, the ThreeTen-Extra project has a handy Interval class for such spans of time.

Interval todayInterval = Interval.of( 
        zdtStartToday.toInstant() ,
        zdtStartTomorrow.toInstant()
    )

About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
0

Look at the exception i had in my code

Illegal instant due to time zone offset transition (daylight savings time 'gap'): 2015-03-27T00:00:00.000 (Asia/Amman)
    org.joda.time.IllegalInstantException: Illegal instant due to time zone offset transition (daylight savings time 'gap'): 2015-03-27T00:00:00.000 (Asia/Amman)

Now i solved it by using

LocalDate currentDate=new LocalDate();
someMethodSetsTheDate(currentDate.toDateTimeAtStartOfDay().toDate());

Instead of

someMethodSetsTheDate(new DateMidnight(date.getYear(), date.getMonthOfYear(), date.getDayOfMonth()).toDate());

Now my recommendation is to use .toDateTimeAtStartOfDay() to avoid similar exceptions .

Please Feel Free To Edit My Answer Thanks

shareef
  • 9,255
  • 13
  • 58
  • 89
0

Here a more simple solution that will check if the dateTime occurs at midnight local time

private boolean isAtMidnight(org.joda.time.DateTime dateTime) {
   return dateTime.toLocalDateTime().getMillisOfDay() == 0;
}
Woody
  • 809
  • 8
  • 21