3

I am trying to write a java block to find the number of mid-nights in a particular date range.

For example:

begin date: 05/01/2014 00:00:00 end date : 05/03/2014 00:00:00

this range has 3 mid-nights in it.

or

begin date : 05/01/2014 00:00:00 end date : 05/02/2014 23:59:59

this has only one.

It basically has to tell me how many times the time "00:00:00" occurrs in the date range. Please help me out. I tried many approaches but none work correct.

Rico2988
  • 79
  • 1
  • 7
  • Midnights are not always at 00:00 time, because of Daylight Saving Time and other anomalies. – Basil Bourque May 21 '14 at 16:48
  • possible duplicate of [Number of days between two dates in Joda Time](http://stackoverflow.com/questions/3802893/number-of-days-between-two-dates-in-joda-time) – Basil Bourque May 21 '14 at 17:04
  • yup> basil Bourque. Can't agree with all your comments more. But I do not think i will have a problem wit time zones in my project. i just wanna know how daylight saving would be a problem – Rico2988 May 21 '14 at 17:05
  • What if I can't afford to use a new library like Joda time as you suggested. – Rico2988 May 21 '14 at 17:07
  • You cannot afford to *not* add Joda-Time IMHO. The java.util.Date and .Calendar classes bundled with Java are notoriously troublesome. Avoid them. Even Sun/Oracle agrees and added the new java.time package to supplant them in Java 8. The java.time package is inspired by Joda-Time. Adding Joda-Time is the first thing I do to any new Java project. – Basil Bourque May 21 '14 at 17:11
  • As for believing you can ignore time zones and Daylight Saving Time, you have just taken your first two steps down Alice’s rabbit hole in your date-time work. – Basil Bourque May 21 '14 at 17:13
  • The day does not end at 23:59:59. You fail to account for fractional seconds. Generally the best way to account for spans of time is with the "half-open" approach where the beginning is inclusive and the ending exclusive. Search StackOverflow for more info. Joda-Time follows the Half-Open approach. – Basil Bourque May 21 '14 at 17:21

5 Answers5

3

I would just count the days (the actual dates), and add one if the earliest date has a time of 00:00:00.

begin date: 05/01/2014 00:00:00 end date : 05/03/2014 00:00:00

  • 03 - 01 = 2 days.
  • Since the begin date has a time of 00:00:00, then add one:
  • 2 + 1 = 3 midnights.

or

begin date : 05/01/2014 00:00:00 end date : 05/02/2014 23:59:59

  • 02 - 01 = 1 day.
  • Since the begin date has a time of 00:00:00, then add one:
  • 1 + 1 = 2 midnights.

Also,

begin date : 5/01/2014 23:59:59 end date : 5/02/2014 00:00:01

  • 02 - 01 = 1 day.
  • Since the begin date doesn't have a time of 00:00:00, then don't add one:
  • 1 midnight.
khriskooper
  • 767
  • 8
  • 18
  • checking against 00:00:00 is sufficient for my case. I just have to see if a patient was in hospital when clock ticked 00:00:00. – Rico2988 May 21 '14 at 16:32
  • Ah, you're right. When I code up your answer I get the right numbers. +1 =) – azurefrog May 21 '14 at 16:39
  • what happens when its across months? – tgkprog May 21 '14 at 16:47
  • 1
    Wise programmers use a decent date-time library rather than roll their own date-time code. Date-time is a notoriously tricky subject. Your time and cleverness can be put to better uses. Already you have made the mistake of ignoring time zones which define the beginning of a day. Secondly, you have made the mistake of assuming midnight is alway 00:00 time. – Basil Bourque May 21 '14 at 16:57
  • yup> basil Bourque. Can't agree with you more. But I do not think i will have a problem wit time zones in my project. i just wanna know how daylight saving would be a problem. – Rico2988 May 21 '14 at 17:04
  • I dont think zone would be an issue unless its two dates from different systems/ areas. If you made two date objects in your own JVM-app with the same or default time zone then would you need to care about zone? – tgkprog May 21 '14 at 17:26
2

One option is to use Joda-Time library:

DateTimeZone zone = DateTimeZone.forID("America/New_York");

int days = Days.daysBetween(new DateTime(startDate, zone), new DateTime(endDate, zone)).getDays();

I think this is the easiest way. The drawback is that you need one more library..

Hope this can help!

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
gipinani
  • 14,038
  • 12
  • 56
  • 85
  • Correct. But I suggest also passing a desired DateTimeZone object to which the DateTime objects should be adjusted. If omitted, the JVM's default time zone is applied. When a day starts and ends is defined by the time zone. – Basil Bourque May 21 '14 at 16:45
  • if your using latest java can use javax.time – tgkprog May 21 '14 at 16:48
  • @tgkprog I suspect you meant to say `java.time` (no 'x'). Also, instead of a mere mention of another library, why not provide your own answer with a code example? – Basil Bourque May 21 '14 at 16:50
  • As a tangent, I'll mention that in this kind of code if you need the first moment of the day, call `withTimeAtStartOfDay()`. – Basil Bourque May 21 '14 at 16:53
  • daysBetween counts the number of full days (# 24 h) within a range and not the number of midnights.... – Boeboe Feb 02 '15 at 13:06
2

The answer using Joda-Time is not correct. As @khriskooper has noted the count of midnights between

2014-05-01 00:00:00 and 2014-05-02 23:59:59

is not one but two midnights!

So here the correction using Joda-Time (not tested), but it could also be any other library which supports day-range calculations (not true for old Java-pre8). I leave out the timezone detail because I do not consider it as really relevant for the question. If OP wants he can replace LocalDateTime by DateTime and apply a timezone.

LocalDateTime ldt1 = new LocalDateTime(2014, 5, 1, 0, 0, 0);
LocalDateTime ldt2 = new LocalDateTime(2014, 5, 2, 23, 59, 59);

int days = Days.daysBetween(ldt1.toLocalDate(), ldt2.toLocalDate()).getDays();
if (ldt1.toLocalTime().equals(new LocalTime(0, 0))) {
  days++;
}
Meno Hochschild
  • 42,708
  • 7
  • 104
  • 126
0

Using Joda's DateTime library (one I would recommmend anyway), an elegant way to do so would be:

private int getNumberOfNights(DateTime start, DateTime end) {
    int nightCount = 0;
    DateTime tempEnd = new DateTime(end);

    while (tempEnd.withTimeAtStartOfDay().isAfter(start)) {
        nightCount++;
        tempEnd = tempEnd.minusDays(1);
    }

    return nightCount;
}

... or if you want to avoid a while loop:

private int getNumberOfNights(DateTime start, DateTime end) {
    int nightCount = Days.daysBetween(start, end).getDays();
    DateTime leftOver = new DateTime(end.minusDays(nightCount));

    if (leftOver.withTimeAtStartOfDay().isAfter(start)) {
        nightCount++;
    }

    return nightCount;
}
Boeboe
  • 2,070
  • 1
  • 17
  • 21
0

With Java 7

public long countDays(Date dtStart, Date dtEnd) {
    long startDay = TimeUnit.DAYS.convert(dtStart.getTime(), TimeUnit.MILLISECONDS)
    long endDay = TimeUnit.DAYS.convert(dtEnd.getTime(), TimeUnit.MILLISECONDS)

    return endDay - startDay
}
José Braz
  • 575
  • 5
  • 9
  • 1. only correct in UTC. 2. Doesn’t count midnight on the first day in even if the first time is 00:00. – Ole V.V. Oct 21 '20 at 16:24