views:

5663

answers:

12

I want to take two times (in seconds since epoch) and show the difference between the two in formats like:

  • 2 minutes
  • 1 hour, 15 minutes
  • 3 hours, 9 minutes
  • 1 minute ago
  • 1 hour, 2 minutes ago

How can I accomplish this??

+2  A: 

I'm not an expert in Java, but you can do t1-t2=t3(in seconds) then divide that by 60, would give you minutes, by another 60 would give you seconds. Then it's just a matter of figuring out how many divisions you need.

Hope it helps.

TuxMeister
+2  A: 

You can also try JODA if the simple solution is unacceptable. It deals with Durations nicely.

duffymo
And it supports formatting output. I'm doing exactly that in an app I made.
Chris Dennett
+1  A: 

I always start with Joda Time. Working with dates and times in Java is always "fun" but Joda Time takes the strain off.

They have Interval and Duration classes which do half of what you are looking for. Not sure if they have a function for outputing in readable format though. I'll keep looking.

HTH

Urf
A: 

The Calendar class can handle most date related math. You will have to get the result of compareTo and output the format yourself though. There isn't a standard library that does exactly what you're looking for, though there might be a 3rd party library that does.

Ben S
A: 
long time1, time2;
time1 = System.currentMillis();

.. drink coffee

time2 = System.currentMillis();

long difference = time2 - time1 // millies between time1 and time2

java.util.Date differneceDate = new Date(difference);

To create a string like "2 Minutes" you should use DateFormatter/DateFormat. You can find more details on this in the the Java API spec (java.sun.com).

Timo
A difference in two dates doesn't make a valid date - if your two times are 12 hours apart, "12 noon, 1 January 1970" is not the duration.
Paul Tomblin
The difference I used is a long. The Date may be used to convert the diffence (long) into a human readable string.
Timo
No, this is wrong. Imagine time1 and time2 are only 1ms apart. Calling new Date(1L); will give you a date that's 1ms past midnight Jan 1, 1970 GMT, which is obviously meaningless.
Outlaw Programmer
Ahh, ok. You are right!
Timo
+7  A: 

I'd recommend you have a look at HumanTime

Peter Lindholm
HumanTime is buggy:long time = 82735786;System.out.println(TimeUnit.HOURS.convert(time, TimeUnit.MILLISECONDS));System.out.println(HumanTime.approximately(time));Results in:22 and1d 23h respectively It's actually 22.9821628 hours.
Jeremy
A: 

OK, after a brief peruse of the API it seems that you could do the following: -

  1. create some ReadableInstants representing start time and end time.
  2. Use Hours.hoursBetween to get the number of hours
  3. use Minutes.minutesBetween to get the number of minutes
  4. use mod 60 on the minutes to get the remaining minutes
  5. et voila!

HTH

Urf
+9  A: 
    Date start = new Date(1167627600000L); // JANUARY_1_2007
    Date end = new Date(1175400000000L); // APRIL_1_2007


    long diffInSeconds = (end.getTime() - start.getTime()) / 1000;

    long diff[] = new long[] { 0, 0, 0, 0 };
    /* sec */diff[3] = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds);
    /* min */diff[2] = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds;
    /* hours */diff[1] = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds;
    /* days */diff[0] = (diffInSeconds = (diffInSeconds / 24));

    System.out.println(String.format(
        "%d day%s, %d hour%s, %d minute%s, %d second%s ago",
        diff[0],
        diff[0] > 1 ? "s" : "",
        diff[1],
        diff[1] > 1 ? "s" : "",
        diff[2],
        diff[2] > 1 ? "s" : "",
        diff[3],
        diff[3] > 1 ? "s" : ""));
mtim
Is there any reason diff[0] is not called days, diff[1] called minutes etc.
Peter Lawrey
This solution only works in English, and will be a real pain to internationalise. (Another minor point: it will print "0 days, 0 hours, 0 minutes, 1 second ago" for an interval of 1 second; wouldn't you want to skip the first 3 bits?")
Simon Nickerson
+1  A: 

If your time-spans cross daylight-saving (summer-time) boundaries, do you want to report the number of days?

For example, 23:00 to 23:00 the next day is always a day but may be 23, 24 or 25 hours depending on whether the you cross a daylight-savings transition.

If you care about that, make sure you factor it into your choice.

Adrian Pronk
The differences are measured in time-since-epoch, so there's no ambiguity.
Andrew Coleson
A: 

Use Apache Commons Duration Format Utils

+1  A: 

Yup awakened the dead I have, but here's my improved implementation based on @mtim posted code, as this thread comes almost on top of the searches so I am messing with the sleepy hollow,

    public static String getFriendlyTime(Date dateTime) {
    StringBuffer sb = new StringBuffer();
    Date current = Calendar.getInstance().getTime();
    long diffInSeconds = (current.getTime() - dateTime.getTime()) / 1000;

    /*long diff[] = new long[]{0, 0, 0, 0};
    /* sec *  diff[3] = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds);
    /* min *  diff[2] = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds;
    /* hours *  diff[1] = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds;
    /* days * diff[0] = (diffInSeconds = (diffInSeconds / 24));
     */
    long sec = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds);
    long min = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds;
    long hrs = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds;
    long days = (diffInSeconds = (diffInSeconds / 24)) >= 30 ? diffInSeconds % 30 : diffInSeconds;
    long months = (diffInSeconds = (diffInSeconds / 30)) >= 12 ? diffInSeconds % 12 : diffInSeconds;
    long years = (diffInSeconds = (diffInSeconds / 12));

    if (years > 0) {
        if (years == 1) {
            sb.append("a year");
        } else {
            sb.append(years + " years");
        }
        if (years <= 6 && months > 0) {
            if (months == 1) {
                sb.append(" and a month");
            } else {
                sb.append(" and " + months + " months");
            }
        }
    } else if (months > 0) {
        if (months == 1) {
            sb.append("a month");
        } else {
            sb.append(months + " months");
        }
        if (months <= 6 && days > 0) {
            if (days == 1) {
                sb.append(" and a day");
            } else {
                sb.append(" and " + days + " days");
            }
        }
    } else if (days > 0) {
        if (days == 1) {
            sb.append("a day");
        } else {
            sb.append(days + " days");
        }
        if (days <= 3 && hrs > 0) {
            if (hrs == 1) {
                sb.append(" and an hour");
            } else {
                sb.append(" and " + hrs + " hours");
            }
        }
    } else if (hrs > 0) {
        if (hrs == 1) {
            sb.append("an hour");
        } else {
            sb.append(hrs + " hours");
        }
        if (min > 1) {
            sb.append(" and " + min + " minutes");
        }
    } else if (min > 0) {
        if (min == 1) {
            sb.append("a minute");
        } else {
            sb.append(min + " minutes");
        }
        if (sec > 1) {
            sb.append(" and " + sec + " seconds");
        }
    } else {
        if (sec <= 1) {
            sb.append("about a second");
        } else {
            sb.append("about " + sec + " seconds");
        }
    }

    sb.append(" ago");


    /*String result = new String(String.format(
    "%d day%s, %d hour%s, %d minute%s, %d second%s ago",
    diff[0],
    diff[0] > 1 ? "s" : "",
    diff[1],
    diff[1] > 1 ? "s" : "",
    diff[2],
    diff[2] > 1 ? "s" : "",
    diff[3],
    diff[3] > 1 ? "s" : ""));*/
    return sb.toString();
}

It obviously can be improved. basically it tries to get the time span more friendly, there are a few limitation though i.e. it would behave strangely if the time passed (parameter) is in future, and its limited up to the days, hours and seconds only (months and years not handled, so that someone else can ;-).

sample outputs are:

  • about a second ago
  • 8 minutes and 34 seconds ago
  • an hour and 4 minutes ago
  • a day ago
  • 29 days ago
  • a year and 3 months ago

, cheers :D

EDIT: now supports months and years :P

Abduliam Rehmanius
+2  A: 

Since everyone shouts "YOODAA!!!" but noone posts a concrete example, here's my contribution.

You could also do this with JodaTime. Use Period to represent a period. To format the period in the desired human representation, use PeriodFormatter which you can build by PeriodFormatterBuilder.

Here's a kickoff example:

DateTime myBirthDate = new DateTime(1978, 3, 26, 12, 35, 0, 0);
DateTime now = new DateTime();
Period period = new Period(myBirthDate, now);

PeriodFormatter formatter = new PeriodFormatterBuilder()
    .appendYears().appendSuffix(" years, ")
    .appendMonths().appendSuffix(" months, ")
    .appendDays().appendSuffix(" days, ")
    .appendHours().appendSuffix(" hours, ")
    .appendMinutes().appendSuffix(" minutes, ")
    .appendSeconds().appendSuffix(" seconds")
    .printZeroNever()
    .toFormatter();

String elapsed = formatter.print(period);
System.out.println(elapsed + " ago");

Much more clear and concise, isn't it?

This prints by now

32 years, 1 months, 5 days, 6 hours, 56 minutes, 24 seconds ago

(Cough, old, cough)

BalusC