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??
I want to take two times (in seconds since epoch) and show the difference between the two in formats like:
How can I accomplish this??
Since everyone shouts "YOODAA!!!" but noone posts a concrete example, here's my contribution.
You could also do this with Joda-Time. 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(" year, ", " years, ")
.appendMonths().appendSuffix(" month, ", " months, ")
.appendWeeks().appendSuffix(" week, ", " weeks, ")
.appendDays().appendSuffix(" day, ", " days, ")
.appendHours().appendSuffix(" hour, ", " hours, ")
.appendMinutes().appendSuffix(" minute, ", " minutes, ")
.appendSeconds().appendSuffix(" second", " 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 month, 1 week, 5 days, 6 hours, 56 minutes, 24 seconds ago
(Cough, old, cough)
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" : ""));
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:
, cheers :D
EDIT: now supports months and years :P
The other Answers may be correct but are outdated. The troublesome old date-time classes in Java are now legacy, supplanted by the java.time classes.
Likewise, the Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
Instant
two times (in seconds since epoch)
In java.time, we represent moments on the timeline in UTC as Instant
. I will assume that your epoch is the same as that of java.time, the first moment of 1970 in UTC (1970-01-01T00:00:00Z
). Note that an Instant
has a resolution of nanoseconds. A convenience factory method constructs a Instant
from whole seconds, as asked in the Question.
Instant start = Instant.ofEpochSecond( … );
Instant stop = Instant.ofEpochSecond( … );
Here we use the current moment and some minutes later.
Instant start = Instant.now() ;
Instant stop = start.plusSeconds( TimeUnit.MINUTES.toSeconds( 7L ) ) ; // Seven minutes as a number of seconds.
Duration
In java.time, a span of time unattached to the timeline is represented in two ways. For years-month-days, we have Period
. For hours-minutes-seconds, we have Duration
.
Duration duration = Duration.between( start , stop );
The elapsed time is calculated with the Half-Open approach. In this approach, the beginning is inclusive while the ending is exclusive. This approach is commonly used in date-time work. I believe using this approach consistently across your code base will help to eliminate errors and misunderstandings due to ambiguities, and will ease the cognitive load of your programming.
The ISO 8601 standard defines many practical formats for representing date-time values as text. These formats are designed to avoid ambiguity, be easy to parse by machine, and be intuitive to read by humans across cultures.
The java.time classes use these formats by default when parsing & generating strings.
For a span of time unattached to the timeline, the standard defines a format of PnYnMnDTnHnMnS
where P
marks the beginning and T
separates any years-months-days from any hours-minutes-seconds. So an hour and a half is PT1H30M
.
In our example code using seven minutes:
String outputStandard = duration.toString();
PT7M
See the above example code running live at IdeOne.com.
I suggest sticking with these formats whenever possible, certainly when exchanging or serializing date-time data, but also consider using in a user interface where appropriate and your users can be trained to use them.
I recommend never using the clock-hour format (ex: 01:30 for hour-and-a-half) as that format is completely ambiguous with a time-of-day.
If you must spell out the span of time as seen in the Question, you will need to build up the text yourself.
Period
, call getYears
, getMonths
, and getDays
to retrieve each part. Duration
class lacked such getters in Java 8, but gained them in Java 9 and later: toDaysPart
, toHoursPart
, toMinutesPart
, toSecondsPart
, and toNanosPart
. Some example code, simple and basic to get you started.
int days = duration.toDaysPart() ;
int hours = duration.toHoursPart() ;
int minutes = duration.toMinutesPart() ;
int seconds = duration.toSecondsPart() ;
int nanos = duration.toNanosPart() ;
StringBuilder sb = new StringBuilder( 100 );
if( days != 0 ) {
sb.append( days + " days" ) ;
};
if( hours != 0 ) {
sb.append( ( sb.length = 0 ) ? ( "" ) : ( ", " ) ) ; // Append comma if any existing text.
sb.append( hours + " hours" ) ;
};
if( minutes != 0 ) {
sb.append( ( sb.length = 0 ) ? ( "" ) : ( ", " ) ) ; // Append comma if any existing text.
sb.append( minutes + " minutes" ) ;
};
if( seconds != 0 ) {
sb.append( ( sb.length = 0 ) ? ( "" ) : ( ", " ) ) ; // Append comma if any existing text.
sb.append( seconds + " seconds" ) ;
};
if( nanos != 0 ) {
sb.append( ( sb.length = 0 ) ? ( "" ) : ( ", " ) ) ; // Append comma if any existing text.
sb.append( nanos + " nanos" ) ;
};
String output = sb.toString();
Or perhaps you could write slicker code using DateTimeFormatterBuilder
in a manner shown with Joda-Time in the Answer by Balus C.
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.
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
, andfz more.
I'd recommend you have a look at HumanTime
some code that plays with date formatting... and time ago.
SimpleDateFormat curFormater = new SimpleDateFormat("EEE, dd MMM yyyy kk:mm:ss");
try {
Date dateObj = curFormater.parse(pubDate);
SimpleDateFormat postFormater = new SimpleDateFormat("MMMM dd, yyyy ss:mm:hh");
String newDateStr = postFormater.format(dateObj);
Log.v("THE NEW DATE IS",newDateStr);
long pubdateinmilis = dateObj.getTime();
pubDate = (String) DateUtils.getRelativeTimeSpanString(pubdateinmilis, System.currentTimeMillis(),DateUtils.HOUR_IN_MILLIS,DateUtils.FORMAT_ABBREV_RELATIVE);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
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.
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.
You can use java.time.Duration
which is modelled on ISO-8601 standards and was introduced with Java-8 as part of JSR-310 implementation. With Java-9 some more convenient methods were introduced.
Demo:
import java.time.Duration;
import java.time.Instant;
class Main {
public static void main(String[] args) {
// Test
System.out.println(getFormattedDuration(1619575035, 1619810961));
}
public static String getFormattedDuration(long start, long end) {
Instant startInstant = Instant.ofEpochSecond(start);
Instant endInstant = Instant.ofEpochSecond(end);
Duration duration = Duration.between(startInstant, endInstant);
// Custom format
// ####################################Java-8####################################
return String.format("%d days, %d hours, %d minutes, %d seconds", duration.toDays(), duration.toHours() % 24,
duration.toMinutes() % 60, duration.toSeconds() % 60);
// ##############################################################################
// ####################################Java-9####################################
// return String.format("%d days, %d hours, %d minutes, %d seconds",
// duration.toDaysPart(), duration.toHoursPart(),
// duration.toMinutesPart(), duration.toSecondsPart());
// ##############################################################################
}
}
Output:
2 days, 17 hours, 32 minutes, 6 seconds
Formatting time spans in java pops up for me frequently in ETL or DB pulls. The following code snippet is how I get the pulse of the operation.
SimpleDateFormat ymdhms=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
DecimalFormat formatter = new DecimalFormat("#,###"); /* ("#,###.00"); gives you the decimal fractions */
int counter=0;
Date beginTime0=new Date();
while (<some end condition>) {
<some time consuming operation>
/*// uncomment this section durring initial exploration of the time consumer
if(counter>100000){
System.out.println("debug exiting due to counter="+counter);
System.exit(0);
}
*/
if(0==counter%1000){
Date now = new Date();
long diffInSeconds = (now.getTime() - beginTime0.getTime()) / 1000;
long diff[] = new long[] { 0, 0, 0, 0 };
diff[3] = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds); /* sec */
diff[2] = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds; /* min */
diff[1] = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds; /* hours */
diff[0] = (diffInSeconds = (diffInSeconds / 24)); /* days */
String delta = String.format(
"%s%s%s%s"
,(diff[0]>0?String.format("%d day%s " ,diff[0],(diff[0]!=1?"s":"")):"")
,(diff[1]>0?String.format("%2d hour%s " ,diff[1],(diff[1]!=1?"s":" ")):"")
,(diff[2]>0?String.format("%2d minute%s ",diff[2],(diff[2]!=1?"s":" ")):"")
, String.format("%2d second%s ",diff[3],(diff[3]!=1?"s":" "))
);
System.out.println(String.format(
"%12s %s delta= %s"
,formatter.format(counter)
,ymdhms.format(new Date())
,delta
)
);
}
counter++;
}
I think you are looking for something like PrettyTime
PrettyTime is an OpenSource time formatting library. Completely customizable, it creates human readable, relative timestamps like those seen on Digg, Twitter, and Facebook.Its available in over 30 languages!
link:
https://github.com/ocpsoft/prettytime
Can be used in android too
For example
System.out.println(p.format(new Date(System.currentTimeMillis() + 1000*60*10)));
//prints: "10 minutes from now"
Recently I got the same requirement where I need a basic method to print duration. I was not having an option to use any third party library. So I just refined the idea of @mtim further.
public static void main(String[] args) throws IOException, ParseException {
String since = "2017-02-24T04:44:05.601Z";
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
TimeZone utc = TimeZone.getTimeZone("UTC");
dateFormat.setTimeZone(utc);
Date sinceDate = dateFormat.parse(since);
Date now = new Date();
long durationInSeconds = TimeUnit.MILLISECONDS.toSeconds(now.getTime() - sinceDate.getTime());
long SECONDS_IN_A_MINUTE = 60;
long MINUTES_IN_AN_HOUR = 60;
long HOURS_IN_A_DAY = 24;
long DAYS_IN_A_MONTH = 30;
long MONTHS_IN_A_YEAR = 12;
long sec = (durationInSeconds >= SECONDS_IN_A_MINUTE) ? durationInSeconds % SECONDS_IN_A_MINUTE : durationInSeconds;
long min = (durationInSeconds /= SECONDS_IN_A_MINUTE) >= MINUTES_IN_AN_HOUR ? durationInSeconds%MINUTES_IN_AN_HOUR : durationInSeconds;
long hrs = (durationInSeconds /= MINUTES_IN_AN_HOUR) >= HOURS_IN_A_DAY ? durationInSeconds % HOURS_IN_A_DAY : durationInSeconds;
long days = (durationInSeconds /= HOURS_IN_A_DAY) >= DAYS_IN_A_MONTH ? durationInSeconds % DAYS_IN_A_MONTH : durationInSeconds;
long months = (durationInSeconds /=DAYS_IN_A_MONTH) >= MONTHS_IN_A_YEAR ? durationInSeconds % MONTHS_IN_A_YEAR : durationInSeconds;
long years = (durationInSeconds /= MONTHS_IN_A_YEAR);
String duration = getDuration(sec,min,hrs,days,months,years);
System.out.println(duration);
}
private static String getDuration(long secs, long mins, long hrs, long days, long months, long years) {
StringBuffer sb = new StringBuffer();
String EMPTY_STRING = "";
sb.append(years > 0 ? years + (years > 1 ? " years " : " year "): EMPTY_STRING);
sb.append(months > 0 ? months + (months > 1 ? " months " : " month "): EMPTY_STRING);
sb.append(days > 0 ? days + (days > 1 ? " days " : " day "): EMPTY_STRING);
sb.append(hrs > 0 ? hrs + (hrs > 1 ? " hours " : " hour "): EMPTY_STRING);
sb.append(mins > 0 ? mins + (mins > 1 ? " mins " : " min "): EMPTY_STRING);
sb.append(secs > 0 ? secs + (secs > 1 ? " secs " : " secs "): EMPTY_STRING);
sb.append("ago");
return sb.toString();
}
The output will be time gap (duration) printed in words e.g.
1 day 2 hours 51 mins 41 secs ago
This question is old and already has an answer but i have a better solution. Use relativeSpan from date utils
dateHere.setText(DateUtils.getRelativeTimeSpanString(timeInMillis,
System.currentTimeMillis(), DateUtils.SECOND_IN_MILLIS));
it takes arguments: long/int time, current time and how you want it, _month,minute,second etc
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
OK, after a brief peruse of the API it seems that you could do the following: -
HTH
The solution of "Abduliam Rehmanius" seems pretty nice, or you can use some above library or you can create new simple things, refer the JS solution at here: http://www.datejs.com/. It's not difficult to transform into Java lang :-)
Hope my link useful for you!
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).