Number of days between two dates in Joda-Time
Asked Answered
T

9

362

How do I find the difference in Days between two Joda-Time DateTime instances? With ‘difference in days’ I mean if start is on Monday and end is on Tuesday I expect a return value of 1 regardless of the hour/minute/seconds of the start and end dates.

Days.daysBetween(start, end).getDays() gives me 0 if start is in the evening and end in the morning.

I'm also having the same issue with other date fields so I was hoping there would be a generic way to 'ignore' the fields of lesser significance.

In other words, the months between Feb and 4 March would also be 1, as would the hours between 14:45 and 15:12 be. However the hour difference between 14:01 and 14:55 would be 0.

Tollbooth answered 27/9, 2010 at 10:21 Comment(0)
K
429

Annoyingly, the withTimeAtStartOfDay answer is wrong, but only occasionally. You want:

Days.daysBetween(start.toLocalDate(), end.toLocalDate()).getDays()

It turns out that "midnight/start of day" sometimes means 1am (daylight savings happen this way in some places), which Days.daysBetween doesn't handle properly.

// 5am on the 20th to 1pm on the 21st, October 2013, Brazil
DateTimeZone BRAZIL = DateTimeZone.forID("America/Sao_Paulo");
DateTime start = new DateTime(2013, 10, 20, 5, 0, 0, BRAZIL);
DateTime end = new DateTime(2013, 10, 21, 13, 0, 0, BRAZIL);
System.out.println(daysBetween(start.withTimeAtStartOfDay(),
                               end.withTimeAtStartOfDay()).getDays());
// prints 0
System.out.println(daysBetween(start.toLocalDate(),
                               end.toLocalDate()).getDays());
// prints 1

Going via a LocalDate sidesteps the whole issue.

Kaput answered 30/7, 2013 at 23:22 Comment(7)
Can you provide an example case with specific data where you think Days.daysBetween is incorrect?Scutari
When you say to use Instant, you're not just talking about start.toInstant(), are you?Daugherty
@PatrickM Yes, I was. On reflection, it's not clear exactly what constraints this is intended to impose, so I'll remove that last sentence. Thanks!Kaput
@chrispy daysBetween doc says it returns number of WHOLE days. In my case 2 days and 1 hour should return me 3 days. In your example it returns 2 days. Is there a way to achieve this?Misquotation
@SujitJoshi I'm afraid I don't understand your question. I suggest posting a full Stack Overflow question and pasting a link here for me :)Kaput
Beware of dates overlapping with a new year! Days between 31 dec 2016 and 5 jan 2017 gives -361 days.Thrashing
@Thrashing No, it doesn't, I just checked. I suspect you typo'd 2017.Kaput
G
195

Days Class

Using the Days class with the withTimeAtStartOfDay method should work:

Days.daysBetween(start.withTimeAtStartOfDay() , end.withTimeAtStartOfDay() ).getDays() 
Gudrun answered 27/9, 2010 at 10:28 Comment(6)
thanks! I was trying to achieve the behavior of android.text.format.DateUtils.getRelativeTimeSpanString() with joda and this was really useful.Wolverhampton
Sir, with reference to this post the method toDateMidnight() from the type DateTime is deprecated.Caudell
You should now use .withTimeAtStartOfDay() instead of .toDateMidnight()Claudclauddetta
what if the end is before the start, does it returns negative days?Trisaccharide
@akhyar: why don't you try it?Gudrun
How do I change the internal behavior of this method to be inclusive of all the dates? For instance, if the dates are the same, the number of days should be 1. Ignoring the time fieldsCerebro
I
91

you can use LocalDate:

Days.daysBetween(new LocalDate(start), new LocalDate(end)).getDays() 
Ignacioignacius answered 27/9, 2010 at 10:27 Comment(2)
Sir, with reference to this post the method toDateMidnight() from the type DateTime is deprecated.Caudell
Why use new LocalDate(date) over date.toLocalDate() ?Norinenorita
S
12

tl;dr

java.time.temporal.ChronoUnit.DAYS.between( 
    earlier.toLocalDate(), 
    later.toLocalDate() 
)

…or…

java.time.temporal.ChronoUnit.HOURS.between( 
    earlier.truncatedTo( ChronoUnit.HOURS )  , 
    later.truncatedTo( ChronoUnit.HOURS ) 
)

java.time

FYI, the Joda-Time project is now in maintenance mode, with the team advising migration to the java.time classes.

The equivalent of Joda-Time DateTime is ZonedDateTime.

ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime now = ZonedDateTime.now( z ) ;

Apparently you want to count the days by dates, meaning you want to ignore the time of day. For example, starting a minute before midnight and ending a minute after midnight should result in a single day. For this behavior, extract a LocalDate from your ZonedDateTime. The LocalDate class represents a date-only value without time-of-day and without time zone.

LocalDate localDateStart = zdtStart.toLocalDate() ;
LocalDate localDateStop = zdtStop.toLocalDate() ;

Use the ChronoUnit enum to calculate elapsed days or other units.

long days = ChronoUnit.DAYS.between( localDateStart , localDateStop ) ;

Truncate

As for you asking about a more general way to do this counting where you are interested the delta of hours as hour-of-the-clock rather than complete hours as spans-of-time of sixty minutes, use the truncatedTo method.

Here is your example of 14:45 to 15:12 on same day.

ZoneId z = ZoneId.of( "America/Montreal" ); 
ZonedDateTime start = ZonedDateTime.of( 2017 , 1 , 17 , 14 , 45 , 0 , 0 , z );
ZonedDateTime stop = ZonedDateTime.of( 2017 , 1 , 17 , 15 , 12 , 0 , 0 , z );

long hours = ChronoUnit.HOURS.between( start.truncatedTo( ChronoUnit.HOURS ) , stop.truncatedTo( ChronoUnit.HOURS ) );

1

This does not work for days. Use toLocalDate() in this case.


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.

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.

Scutari answered 22/8, 2017 at 4:23 Comment(1)
Your TL;DR for days using truncate falls prey to the bug detailed in the accepted answer, namely it is off-by-one when start-of-day is at 1am. I have updated it to use the correct answer you gave further down, using toLocalDate.Kaput
N
2

The accepted answer builds two LocalDate objects, which are quite expensive if you are reading lot of data. I use this:

  public static int getDaysBetween(DateTime earlier, DateTime later)
  {
    return (int) TimeUnit.MILLISECONDS.toDays(later.getMillis()- earlier.getMillis());
  }

By calling getMillis() you use already existing variables.
MILLISECONDS.toDays() then, uses a simple arithmetic calculation, does not create any object.

Northwards answered 21/6, 2016 at 12:37 Comment(3)
This Answer works only if your definition of ‘days’ is exactly 24-hours long without regard for time zones and dates. If so, use this approach. If not, look to the other answers that address time zones.Scutari
@BasilBourque, you are right, still, i would go for a solution based on arithmetic calculation rather then building expensive objects for each method call, there are many flavours out there for such calculations, if you are reading an input from a web page, might be ok, but if you are processing a log file with hundreds of thousands of lines this just makes it very slowNorthwards
Java will optimize away the object allocation if your loop is hot. See docs.oracle.com/javase/7/docs/technotes/guides/vm/…Kaput
F
1

java.time.Period

Use the java.time.Period class to count days.

Since Java 8 calculating the difference is more intuitive using LocalDate, LocalDateTime to represent the two dates

    LocalDate now = LocalDate.now();
    LocalDate inputDate = LocalDate.of(2018, 11, 28);

    Period period = Period.between( inputDate, now);
    int diff = period.getDays();
    System.out.println("diff = " + diff);
Footplate answered 28/11, 2018 at 4:13 Comment(0)
A
0

(KOTLIN) For Difference between a constant date and current date (Joda)

You can use Days.daysBetween(jodaDate1,jodaDate2)

Here is an example:

        val dateTime: DateTime = DateTime.parse("14/09/2020",
            DateTimeFormat.forPattern("dd/MM/yyyy"))
        val currentDate = DateTime.now()
        //To calculate the days in between
        val dayCount = Days.daysBetween(dateTime,currentDate).days
        //Set Value to TextView 
        binding.daysCount.text = dayCount.toString()
Appellate answered 25/1, 2022 at 5:9 Comment(0)
I
-1
DateTime  dt  = new DateTime(laterDate);        

DateTime newDate = dt.minus( new  DateTime ( previousDate ).getMillis());

System.out.println("No of days : " + newDate.getDayOfYear() - 1 );    
Invert answered 9/11, 2018 at 14:59 Comment(0)
F
-12
public static int getDifferenceIndays(long timestamp1, long timestamp2) {
    final int SECONDS = 60;
    final int MINUTES = 60;
    final int HOURS = 24;
    final int MILLIES = 1000;
    long temp;
    if (timestamp1 < timestamp2) {
        temp = timestamp1;
        timestamp1 = timestamp2;
        timestamp2 = temp;
    }
    Calendar startDate = Calendar.getInstance(TimeZone.getDefault());
    Calendar endDate = Calendar.getInstance(TimeZone.getDefault());
    endDate.setTimeInMillis(timestamp1);
    startDate.setTimeInMillis(timestamp2);
    if ((timestamp1 - timestamp2) < 1 * HOURS * MINUTES * SECONDS * MILLIES) {
        int day1 = endDate.get(Calendar.DAY_OF_MONTH);
        int day2 = startDate.get(Calendar.DAY_OF_MONTH);
        if (day1 == day2) {
            return 0;
        } else {
            return 1;
        }
    }
    int diffDays = 0;
    startDate.add(Calendar.DAY_OF_MONTH, diffDays);
    while (startDate.before(endDate)) {
        startDate.add(Calendar.DAY_OF_MONTH, 1);
        diffDays++;
    }
    return diffDays;
}
Fickle answered 24/12, 2014 at 17:38 Comment(1)
the question is specifically looking for joda-time.Socioeconomic

© 2022 - 2024 — McMap. All rights reserved.