2

I need to find out the number of months, weeks, days and hours left from now to a future time using Java. I can not use any third party library like Joda. How can I do that using just JDK classes?

So far, this is what I have come up with. It sort of works, except for some situations:

public class DateUtil {

public static Integer[] components(Date from, Date to) {
    Integer[] result = new Integer[4];
    //SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
    //df.setTimeZone(TimeZone.getTimeZone("EST"));

    Calendar fromCal = new GregorianCalendar();
    Calendar toCal = new GregorianCalendar();

    fromCal.setTime(from);
    toCal.setTime(to);

    int months = 0;
    do {
        fromCal.add(Calendar.MONTH, 1);
        ++months;
        //System.out.println(df.format(fromCal.getTime()));
    } while (fromCal.before(toCal));

    fromCal.add(Calendar.MONTH, -1);
    --months;

    int days = 0;
    do {
        fromCal.add(Calendar.DAY_OF_YEAR, 1);
        ++days;
    } while (fromCal.before(toCal));

    fromCal.add(Calendar.DAY_OF_YEAR, -1);
    --days;

    int hours = 0;
    do {
        fromCal.add(Calendar.HOUR_OF_DAY, 1);
        ++hours;
    } while (fromCal.before(toCal));

    fromCal.add(Calendar.HOUR_OF_DAY, -1);
    --hours;

    int minutes = 0;
    do {
        fromCal.add(Calendar.MINUTE, 1);
        ++minutes;
    } while (fromCal.before(toCal));

    result[0] = months;
    result[1] = days;
    result[2] = hours;
    result[3] = minutes;

    return result;
}

public static void main(String[] args) {
    try {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        df.setTimeZone(TimeZone.getTimeZone("EST"));

        Date from = df.parse("2014-03-29 00:00");
        Date to = df.parse("2014-05-29 00:00");
        Integer result[] = components(from, to);

        System.out.printf("Months:%02d Days:%02d Hrs:%02d Mins:%02d\n", 
                result[0], result[1], result[2], result[3]);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
}

It produces unacceptable results when you have February in the middle and start date is end of the month. For example:

From: Dec 31, 2013 To: Dec 31, 2014

The difference will produce: 12 months, 3 days.

RajV
  • 6,860
  • 8
  • 44
  • 62
  • Why can't you use Joda? – Daniel Kaplan Nov 13 '13 at 19:10
  • You could try having a look at [this example](http://stackoverflow.com/questions/18119665/geting-duration-of-2-times/18120233#18120233) and [this example](http://stackoverflow.com/questions/18974729/how-to-get-the-time-since-midnight-in-seconds/18975189#18975189) and [this example](http://stackoverflow.com/questions/13328912/java-getting-time-interval/13329218#13329218) for some ideas – MadProgrammer Nov 13 '13 at 19:15
  • I think downvote is not required for those who are new here who never knew the norms of this website. A post is expected here with some demonstration and new comers never knew this until they are down voted. – user1769790 Nov 13 '13 at 19:15
  • Please refer to and enhance your logic further. http://www.mkyong.com/java/how-to-calculate-date-time-difference-in-java/ – user1769790 Nov 13 '13 at 19:18
  • RajV, you are wrong. Mike W is absolutely correct in pointing out that you did not provide enough information in your question, he wasn't making a snarky comment. He's not a mind reader, he doesn't know how awesome you are at using Date and Calendar if you don't tell him. The solution provided by Mr. Polywhirl can be trivially modified to solve your use case. If you need help with that, ask for it. Don't call his contribution useless, it just makes you look like the kind of person that nobody wants to help. – Floegipoky Nov 13 '13 at 20:02
  • FYI, the troublesome old date-time classes such as [`java.util.Date`](https://docs.oracle.com/javase/10/docs/api/java/util/Date.html), [`java.util.Calendar`](https://docs.oracle.com/javase/10/docs/api/java/util/Calendar.html), and `java.text.SimpleDateFormat` are now [legacy](https://en.wikipedia.org/wiki/Legacy_system), supplanted by the [*java.time*](https://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes built into Java 8 and later. See [*Tutorial* by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque Apr 24 '18 at 05:16

2 Answers2

3

Why not use the Java classes Date and Calendar

These classes already have built in functionality to help you calculate difference between two Dates. Most of the Date methods seem to be deprecated so instead I would recommend Calendar. Good luck!

johnsoe
  • 664
  • 1
  • 5
  • 13
1

One of my colleagues eventually came up with the right answer. The problem with incrementally adding a month to a Calendar is that you go from Jan 31 to Feb 28 to Mar 28, instead of Mar 31. This adds inaccuracy. The solution is to add 1 month, 2 months, 3 months and so on to the original start date. Then you go from Jan 31 to feb 28 to Mar 31. Anyway, here is his solution, slightly altered by me.

public class TimeSpan {
    public int months;
    public int days;
    public int hours;
    public int minutes;
}

class DateCalculator {
    public static TimeSpan difference(Date later, Date earlier) {
        TimeSpan v = new TimeSpan();

        /* Add months until we go past the target, then go back one. */
        while (calculateOffset(earlier, v).compareTo(later) <= 0) {
            v.months++;
        }
        v.months--;

        /* Add days until we go past the target, then go back one. */
        while (calculateOffset(earlier, v).compareTo(later) <= 0) {
            v.days++;
        }
        v.days--;

        /* Add hours until we go past the target, then go back one. */
        while (calculateOffset(earlier, v).compareTo(later) <= 0) {
            v.hours++;
        }
        v.hours--;
        while (calculateOffset(earlier, v).compareTo(later) <= 0) {
            v.minutes++;
        }
        v.minutes--;

        return v;
    }

    private static Date calculateOffset(Date start, TimeSpan offset) {
        Calendar c = new GregorianCalendar();

        c.setTime(start);

        c.add(Calendar.MONTH, offset.months);
        c.add(Calendar.DAY_OF_YEAR, offset.days);
        c.add(Calendar.HOUR, offset.hours);
        c.add(Calendar.MINUTE, offset.minutes);

        return c.getTime();
    }
     public static void main(String[] args) {
            try {
                    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
                    df.setTimeZone(TimeZone.getTimeZone("EST"));

                    Date from = df.parse("2013-01-31 00:00");
                    Date to = df.parse("2014-01-31 10:20");
                    TimeSpan ts = difference(to, from);

                    System.out.printf("Months:%02d Days:%02d Hrs:%02d Mins:%02d\n",
                                    ts.months, ts.days, ts.hours, ts.minutes);
            } catch (Exception e) {
                    e.printStackTrace();
            }
    }
}
RajV
  • 6,860
  • 8
  • 44
  • 62