views:

6941

answers:

8

I have...


Date start = new Date()

...
...
...

Date stop = new Date()

I'd like to get the years, months, days, hours, minutes and seconds ellapsed between these two dates.

--

I'll refine the question.

I just want to get the elapsed time, as an absolute measure, that is without taking into account leap years, the days of each month, etc.

Thus I think it's impossible to get the years and months elapsed, all I can get is days, hours, minutes and seconds.

More specifically I want to tell that a certain task lasted for e.g.

20 sec
13 min, 4 sec
2 h, 10 min, 2 sec
4 d, 4 h, 2 min, 2 sec

So please forgive my lack of precision.

+6  A: 

Not so easy with the standard Date API.

You might want to look at Joda Time, or JSR-310 instead.

I'm not an expert in Joda, but I think the code would be:

Interval interval = new Interval(d1.getTime(), d2.getTime());
Period period = interval.toPeriod();
System.out.printf(
    "%d years, %d months, %d days, %d hours, %d minutes, %d seconds%n", 
    period.getYears(), period.getMonths(), period.getDays(),
    period.getHours(), period.getMinutes(), period.getSeconds());
toolkit
+2  A: 

Hmm, if I get what you're asking, you want to know that if:

start = Jan 1, 2001, 10:00:00.000 am and

stop = Jan 6, 2003, 12:01:00.000 pm

you want an answer of 2 years, 0 months, 5 days, 2 hours, 1 minute

Unfortunately, this is a specious answer. What if the dates were Jan 2, and Jan 31? Would that be 29 days? Ok, but Feb 2 to Mar 2 is 28 (29) days, but would be listed as 1 month?

The length of time in anything other than seconds or possibly days is variable without knowing the context since months and years are of different lengths. The difference between 2 dates should be in static units, which are easily computable from stop.getTime() - start.getTime() (which is the difference in millisecs)

Bill James
yeap, I see what you mean... I guess at most the difference should be in days, hours, min, seccond...
opensas
You could do weeks as well - always 7 days.
Skip Head
However, days are not always 24 hours, due to daylight savings time...
Michael Borgwardt
+7  A: 

You can do all of this with division and mod.

long l1 = start.getTime();
long l2 = stop.getTime();
long diff = l2 - l1;

long secondInMillis = 1000;
long minuteInMillis = secondInMillis * 60;
long hourInMillis = minuteInMillis * 60;
long dayInMillis = hourInMillis * 24;
long yearInMillis = dayInMillis * 365;

long elapsedYears = diff / yearInMillis;
diff = diff % yearInMillis;
long elapsedDays = diff / dayInMillis;
diff = diff % dayInMillis;
long elapsedHours = diff / hourInMillis;
diff = diff % hourInMillis;
long elapsedMinutes = diff / minuteInMillis;
diff = diff % minuteInMillis;
long elapsedSeconds = diff / secondInMillis;

That should give you all of the information you requested.

EDIT: Since people seem to be confused, no, this does not take things like leap years or daylight savings time switches into account. It is pure elapsed time, which is what opensas asked for.

Sebastian Celis
What about leap years?
toolkit
That doesn't matter. He isn't trying to figure out a date given a difference. He is trying to figure out a difference given two dates. The first is harder to do. The second is simple. Whether there are leap years or not the same amount of time has passed between the two timestamps.
Sebastian Celis
So Jan 1 2008 -> Jan 1 2009 is 1 year, 1 day?
Stephen
It just depends on how you look at it. If 1 year is equal to 365 days then yes. Read the question again. opensas is very clear that he wants an absolute measure of time ignoring things like leap years. As such, I believe this is the solution to the stated problem.
Sebastian Celis
It ain't that simple for leap years. You should at least put a caveat in order not to mislead people.
starblue
@starblue I thought that was obvious from the answer, but I went ahead and clarified it anyway.
Sebastian Celis
+3  A: 

Regarding JodaTime I just got it going; thanks to the responder who suggested it. Here's a more condensed version of the Joda code suggested:

Period period = new Period(d1.getTime(), d2.getTime());
System.out.printf(
    "%d years, %d months, %d days, %d hours, %d minutes, %d seconds%n", 
    period.getYears(), period.getMonths(), period.getDays(),
    period.getHours(), period.getMinutes(), period.getSeconds());

(not sure if this is helping the original question but certainly searchers).

Fletch
A: 

There is no point creating a Date object as all this does is wrap System.currentTimeMillis(). The getTime() function just unwraps the Date object. I suggest you just use this function to obtain a long.

If you only need second accuracy, this is fine. However if you want sub-millisecond accuracy use System.nanoTime() to get the elapse time.

Peter Lawrey
+1  A: 

Apart from the aforementioned great JodaTime API which I do recommend, the best standard Java alternative you can have is the java.util.Calendar. It is cumbersome to work with it (this is an understatement .. look at the single-line JodaTime examples here), but you can calculate the elapsed time with it as well. Important key is that you should use the Calendar#add() in a loop to get the elapsed value for years, months and days to take leap days, years and centuries into account. You should not calculate them back from the (milli)seconds.

Here's a basic example:

import java.util.Calendar;

public class Test {

    public static void main(String[] args) throws Exception {
        Calendar start = Calendar.getInstance();
        start.set(1978, 2, 26, 12, 35, 0); // Just an example.
        Calendar end = Calendar.getInstance();

        Integer[] elapsed = new Integer[6];
        Calendar clone = (Calendar) start.clone(); // Otherwise changes are been reflected.
        elapsed[0] = elapsed(clone, end, Calendar.YEAR);
        clone.add(Calendar.YEAR, elapsed[0]);
        elapsed[1] = elapsed(clone, end, Calendar.MONTH);
        clone.add(Calendar.MONTH, elapsed[1]);
        elapsed[2] = elapsed(clone, end, Calendar.DATE);
        clone.add(Calendar.DATE, elapsed[2]);
        elapsed[3] = (int) (end.getTimeInMillis() - clone.getTimeInMillis()) / 3600000;
        clone.add(Calendar.HOUR, elapsed[3]);
        elapsed[4] = (int) (end.getTimeInMillis() - clone.getTimeInMillis()) / 60000;
        clone.add(Calendar.MINUTE, elapsed[4]);
        elapsed[5] = (int) (end.getTimeInMillis() - clone.getTimeInMillis()) / 1000;

        System.out.format("%d years, %d months, %d days, %d hours, %d minutes, %d seconds", elapsed);
    }

    private static int elapsed(Calendar before, Calendar after, int field) {
        Calendar clone = (Calendar) before.clone(); // Otherwise changes are been reflected.
        int elapsed = -1;
        while (!clone.after(after)) {
            clone.add(field, 1);
            elapsed++;
        }
        return elapsed;
    }

}

It should print my age as of now =)

Oh, I should add, you can "convert" Date to Calendar using Calendar#setTime().

BalusC
+5  A: 

I've just discovered this quickly solution (in Groovy):

TimeDuration td = TimeCategory.minus( stop, start )
println td
pd
Don't you just love groovy? No need for a page of code to do something simple
Patrick
A: 

Well since Java 1.5 you should use TimeUnit.

Here is a simple & plain example for this. I think in groovy it might get shorter(as always).

/**
 * Formats a given {@link Date} to display a since-then timespan.
 * @param created
 * @return String with a format like "3 minutes ago"
 */
public static String getElapsedTime(Date created) {
    long duration = System.currentTimeMillis() - created.getTime();
    long seconds = TimeUnit.MILLISECONDS.toSeconds(duration);
    long days = TimeUnit.MILLISECONDS.toDays(duration);
    long hours = TimeUnit.MILLISECONDS.toHours(duration);
    long minutes = TimeUnit.MILLISECONDS.toMinutes(duration);
    if (days > 0) {
        return days + " days";
    }
    if (hours > 0) {
        return hours + " hrs";
    }
    if (minutes > 0) {
        return minutes + " minutes";
    }

    return seconds + " seconds";
}

Oh and avoid multiple returns please ;)

dhesse