3

I have a start date and end date. the duration between the 2 dates should be in the form of years, months and days. I am new to java. When I run the below method the out I get is 0 years, 12 months 1 days. Please suggest an alternative to get accurate difference in years, months and days.

import java.sql.Date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public class Duration {

    private String getAssignmentDuration(java.util.Date oldDate, java.util.Date newDate) {
        Calendar c1 = Calendar.getInstance();
        Calendar c2 = Calendar.getInstance();
        if (oldDate.compareTo(newDate) > 0) {
            c1.setTime(newDate);
            c2.setTime(oldDate);
        } else {
            System.out.println("invalid");
            return "Invalid selection";

        }
        int year = 0;
        int month = 0;
        int days = 0;
        boolean doneMonth = false;
        boolean doneYears = false;
        while (c1.before(c2)) {
            //log.debug("Still in Loop");
            if (!doneYears) {
                c1.add(Calendar.YEAR, 1);
                year++;
            }
            if (c1.after(c2) || doneYears) {
                if (!doneYears) {
                    doneYears = true;
                    year--;
                    c1.add(Calendar.YEAR, -1);
                }   
                if (!doneMonth) {
                    c1.add(Calendar.MONTH, 1);
                    month++;
                }
                if (c1.after(c2) || doneMonth) {
                    if (!doneMonth) {
                        doneMonth = true;
                        month--;
                        c1.add(Calendar.MONTH, -1);
                    }

                    c1.add(Calendar.DATE, 1);
                    days++;
                    if (c1.after(c2)) {
                        days--;
                    }
                    // this will not be executed
                    if (days == 31 || month==12) {
                        break;
                    }
                }
            }
        }
        System.out.println(year + " years, " + month + " months, " + days + " days");
        return year + " years, " + month + " months, " + days + " days";

    }


    public static void main(String[] args) {
        Duration d1= new Duration();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
        java.util.Date oldDate = null;
        try {
            oldDate = sdf.parse("2012/08/29");
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        java.util.Date newDate = null;
        try {
            newDate = sdf.parse("2013/08/31");
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        d1.getAssignmentDuration(oldDate, newDate);
    }

}
messivanio
  • 2,263
  • 18
  • 24
Vidya
  • 119
  • 2
  • 2
  • 5
  • 2
    [What have you tried?](http://mattgemmell.com/2008/12/08/what-have-you-tried/) – Alastair McCormack Oct 26 '12 at 09:56
  • 2
    it is possible duplicate of below link http://stackoverflow.com/questions/3491679/how-to-calculate-difference-between-two-dates-using-java – sunleo Oct 26 '12 at 09:59
  • 1
    @Fuzzyfelt he already posted the code segment that he tried. then what is the purpose of your question ? – sunil Oct 26 '12 at 10:45
  • @sunil in my opinion the OP has made no effort to debug the code and is looking for someone to give them the solution – Alastair McCormack Oct 26 '12 at 11:30
  • FYI, the troublesome old date-time classes such as [`java.util.Date`](https://docs.oracle.com/javase/8/docs/api/java/util/Date.html), [`java.util.Calendar`](https://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html), and `java.text.SimpleTextFormat` are now [legacy](https://en.wikipedia.org/wiki/Legacy_system), supplanted by the [java.time](https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html) classes. See [Tutorial by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque May 05 '17 at 02:58

7 Answers7

15
 public static String getDateDifferenceInDDMMYYYY(Date from, Date to) {
        Calendar fromDate=Calendar.getInstance();
        Calendar toDate=Calendar.getInstance();
        fromDate.setTime(from);
        toDate.setTime(to);
        int increment = 0;
        int year,month,day;
        System.out.println(fromDate.getActualMaximum(Calendar.DAY_OF_MONTH));
        if (fromDate.get(Calendar.DAY_OF_MONTH) > toDate.get(Calendar.DAY_OF_MONTH)) {
            increment =fromDate.getActualMaximum(Calendar.DAY_OF_MONTH);
        }
         System.out.println("increment"+increment);
// DAY CALCULATION
        if (increment != 0) {
            day = (toDate.get(Calendar.DAY_OF_MONTH) + increment) - fromDate.get(Calendar.DAY_OF_MONTH);
            increment = 1;
        } else {
            day = toDate.get(Calendar.DAY_OF_MONTH) - fromDate.get(Calendar.DAY_OF_MONTH);
        }

// MONTH CALCULATION
        if ((fromDate.get(Calendar.MONTH) + increment) > toDate.get(Calendar.MONTH)) {
            month = (toDate.get(Calendar.MONTH) + 12) - (fromDate.get(Calendar.MONTH) + increment);
            increment = 1;
        } else {
            month = (toDate.get(Calendar.MONTH)) - (fromDate.get(Calendar.MONTH) + increment);
            increment = 0;
        }

// YEAR CALCULATION
        year = toDate.get(Calendar.YEAR) - (fromDate.get(Calendar.YEAR) + increment);
     return   year+"\tYears\t\t"+month+"\tMonths\t\t"+day+"\tDays";
    }

    public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(1999,01,8);
       /*  Calendar calendar1 = Calendar.getInstance();
        calendar1.set(2012,01,23);*/
        System.out.println(getDateDifferenceInDDMMYYYY(calendar.getTime(),new Date()));
    }
user2640848
  • 151
  • 1
  • 2
  • Adding an explanation would be nice. – Steve P. Aug 01 '13 at 06:47
  • Nice answer. It gives the difference in years, months and days, accounting for when the days wrap over a month boundary, or the months wrap over a year boundary. Useful if you want to say 'X expires in 1 year, 2 months and 19 days' – Relefant Nov 13 '13 at 21:32
  • Thanks this saved my time. +1 from me. – Suraj Oct 10 '18 at 09:24
4

Joda Time has a concept of time Interval that you can use, like:

Interval interval = new Interval(oldDate.getTime(), newDate.getTime());

Then using a Period object, like:

Period period = interval.toPeriod().normalizedStandard(PeriodType.yearMonthDay());

PeriodFormatter formatter = new PeriodFormatterBuilder()
            .appendYears()
            .appendSuffix(" year ", " years ")
            .appendSeparator(" and ")
            .appendMonths()
            .appendSuffix(" month ", " months ")
            .appendSeparator(" and ")
            .appendDays()
            .appendSuffix(" day ", " days ")
            .toFormatter();
System.out.println(formatter.print(period));

You will easily be able to print your diference in years and months.

Probably you changes something while posting the question, because to fix your code (note that I didn't tested if your code will work with all sort of ranges), you only need to properly initialize the Calendar objects and the reverse the invalid selection check:

Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
if (oldDate.compareTo(newDate) < 0) {
    c2.setTime(newDate);
    c1.setTime(oldDate);
} else {
    System.out.println("invalid");
    return "Invalid selection";
}
dan
  • 13,132
  • 3
  • 38
  • 49
  • Thanks a lot. Is there a way to obtain the duration without using joda or milli seconds approach? Milliseconds might not provide accurate duration in some locales. Hence i dont wanna use it. Could you please provide a modification in the code that i have used to provide accurate duration. – Vidya Oct 26 '12 at 10:52
  • @user1776304 If you need to perform the transformation in a specified locale settings, you can use: `Interval(long startInstant, long endInstant, DateTimeZone zone)`. I suggest you should use the joda approach, to fix your code see my updated answer. – dan Oct 26 '12 at 11:16
  • Even with the fix the output is o years, 12 months, 1 days.. Please help. Thanks. – Vidya Oct 26 '12 at 11:28
  • @Vidya probably, you are running a different code then what is posted, since I just tested and it's printing: 1 years, 0 months, 2 days – dan Oct 26 '12 at 11:32
  • Yes sorry am debugging a different code where in the oldDate is 2012/08/31 and newDate is 2013/08/29. The duration is shown wrong. There is variation in days. – Vidya Oct 26 '12 at 11:57
  • @Vidya The issue is because you are comparing at first at the year level. Since in this new case the difference is less then an year, but the years are different you count the year difference. – dan Oct 26 '12 at 12:04
  • ok thanks.So Is there a different way to compute it other than using joda? – Vidya Oct 26 '12 at 12:37
  • @Vidya sure there are, have a look here: http://stackoverflow.com/a/4710304, but in the end if you would like to be accurate, you will have to implement what Joda time implemented. – dan Oct 26 '12 at 12:59
4

tl;dr

Period.between( 
    LocalDate.of( 2017 , Month.JANUARY , 23 ) , 
    LocalDate.of( 2017 , Month.MARCH , 27 ) 
)

Call:

.getYears()
.getMonths()
.getDays()

Avoid legacy date-time classes

You are use troublesome old date-time classes, now legacy, supplanted by java.time classes.

Using java.time

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.

Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

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

today.toString(): 2017-05-05

For our example, we create another LocalDate.

LocalDate earlier = today.minusMonths( 2 ).minusWeeks( 3 ).minusDays( 2 ) ;

earlier.toString(): 2017-02-10

To represent a span of time unattached to the timeline in the granularity of years-month-days, use the Period class.

Period p = Period.between( earlier , today ) ;
int years = p.getYears();
int months = p.getMonths();
int days = p.getDays();

See this code run live at IdeOne.com.

ISO 8601

The ISO 8601 standard defines formats for textual representations of date-time values. For durations of years-months-days, the pattern is PnYnMnDTnHnMnS where P marks the beginning and T separates the years-months-days portion from the hours-minutes-seconds portion.

The java.time classes use the standard formats by default when parsing/generating strings. The Period class generates this particular pattern in its toString method.

String output = p.toString() ;

p.toString(): P2M25D

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

Assume you have Date date1, date2 and they are initialized where date1>date2.

long diff = date1.getTime() - date2.getTime(); //this is going to give you the difference in milliseconds

Date result = new Date(diff);
Format frmt = new SimpleDateFormat("yy MM dd HH:mm:ss");
return frmt.format(result).toString();//or if you want system.out.println(...);
cнŝdk
  • 31,391
  • 7
  • 56
  • 78
smttsp
  • 4,011
  • 3
  • 33
  • 62
  • I think on code line 3, you mean `new Date(diff)` and not `new Date(time)`... But your answer seems like the correct one... +1 – reverse_engineer Aug 01 '13 at 07:30
  • Well, nice answer but the `getTime()` method returns the time in milliseconds and not in seconds. – cнŝdk Jan 07 '15 at 13:45
  • i upvoted this, and used in my application, but had to subtract 1970 from the resulting years, since getTime() gives the Unix time, which is milliseconds since the start of 01/01/1970, if I am not mistaken – hello_earth Sep 11 '17 at 07:28
1
    long diff = today.getTimeInMillis() - birth.getTimeInMillis();


    // Calculate difference in seconds
    long Seconds = diff / 1000;

    // Calculate difference in minutes
    long Minutes = diff / (60 * 1000);

    // Calculate difference in hours
    long Hours = diff / (60 * 60 * 1000);

    // Calculate difference in days
    long Days = diff / (24 * 60 * 60 * 1000);

    long Months = diff / (24 * 60 * 60 * 12 * 1000);

    //lblTsec, lblTmint, lblthours,lblTdays;
    System.out.println("Seconds : " + Seconds + "");
    System.out.println("Minutes : " + Minutes + "");
    System.out.println("Hours : " + Hours + "");
    System.out.println("Days : " + Days + "");
Bhushankumar Lilapara
  • 780
  • 1
  • 13
  • 26
0
public static long[] differenceBetweenDates(Date fromDate, Date toDate) {
    Calendar startDate = Calendar.getInstance();
    startDate.setTime(fromDate);
    long years = 0;
    long months = 0;
    long days = 0;
    Calendar endDate = Calendar.getInstance();
    endDate.setTime(toDate);
    Calendar tmpdate = Calendar.getInstance();
    tmpdate.setTime(startDate.getTime());

    tmpdate.add(Calendar.YEAR, 1);
    while (tmpdate.compareTo(endDate) <= 0) {
        startDate.add(Calendar.YEAR, 1);
        tmpdate.add(Calendar.YEAR, 1);
        years++;
    }
    tmpdate.setTime(startDate.getTime());
    tmpdate.add(Calendar.MONTH, 1);
    while (tmpdate.compareTo(endDate) <= 0) {
        startDate.add(Calendar.MONTH, 1);
        tmpdate.add(Calendar.MONTH, 1);
        months++;
    }
    tmpdate.setTime(startDate.getTime());
    tmpdate.add(Calendar.DATE, 1);
    while (tmpdate.compareTo(endDate) <= 0) {
        startDate.add(Calendar.DATE, 1);
        tmpdate.add(Calendar.DATE, 1);
        days++;
    }
    return new long[]{days, months, years};
}
0

Simply you could calculate difference between two dates milliseconds and divide by seconds, minutes, hours, days and month

suppose you want to get difference between years try this,

public int findDiff(Date fromDate, Date toDate) {

    if(fromDate == null || toDate == null) {
        return -1;
    }

    long diff = toDate.getTime() - fromDate.getTime();

    int diffInYears = (int) (diff / (60 * 60 * 1000 * 24 * 30.41666666 * 12));
    return diffInYears;
}

suppose you want difference between months remove 12(means months) from the divider. likewise you can get days, hours, minutes..

Thirumaran
  • 459
  • 1
  • 6
  • 12