Format of time is incorrect - java

String realTimeStr = "5.2345";
Double realTimeDbl = Double.parseDouble(realTimeStr);
long realTimeLng = (long) (realTimeDbl*1000);
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSSS", Locale.getDefault());
log("Duration: " + sdf.format(new Date(realTimeLng - TimeZone.getDefault().getRawOffset())));
Current output:
Duration: 00:00:05.0234
Desired output:
Duration: 00:00:05.2345
I also tried another method, still no good:
String realTimeStr = "1.4345";
Double realTimeDbl = Double.parseDouble(realTimeStr);
DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("HH:mm:ss.SSSS").withZone(ZoneId.of("UTC"));
Instant instant = Instant.ofEpochMilli((long)(realTimeDbl*1000));
String t = formatter.format(instant);
System.out.println("Duration: " + t);
Current output:
Duration: 00:00:01.4340
Desired output:
Duration: 00:00:01.4345
I have googled for some time. Any ideas what is causing this?

First of all, you're mistaking 2 different concepts:
A time of the day, such as 10 AM or 15:30:45
A duration, which is an amount of time, such as 1 year, 2 months and 10 days or 10 hours, 25 minutes and 30 seconds
Although both might use the same words (such as "hours" and "minutes"), they're not the same thing. A duration is not attached to a chronology (10 hours and 25 minutes relative to what?), it's just the amount of time, by itself.
SimpleDateFormat and DateTimeFormatter are designed to format dates and times of the day, but not durations. Although converting a duration to a time and "pretending" it's a time of the day to format it might work, it's not the right way.
Unfortunately, there are no built-in formatters for a duration. So you'll have to format it manually.
Another detail is that you are multiplying 1.4345 by 1000 (resulting in 1434.5), and then casting to a long(so the value is rounded to 1434) - the last digit is lost.
One way to do it is to parse the string to a double and then multiply by 1 billion to get the value as nanoseconds (I don't know if you'll work with more than 4 digits, so I'm considering nanosecond precision):
// convert the string value to a total of nanoseconds
int nanosPerSecond = 1_000_000_000;
long nanos = (long) (Double.parseDouble(realTimeStr) * nanosPerSecond);
Now we must format it manually. First I've extracted the number of hours, minutes, seconds and nanoseconds from the total nanos value:
long hours = nanos / nanosPerSecond / 3600;
nanos -= hours * 3600 * nanosPerSecond;
long minutes = nanos / nanosPerSecond / 60;
nanos -= minutes * 60 * nanosPerSecond;
long seconds = nanos / nanosPerSecond;
nanos -= seconds * nanosPerSecond;
Then I created an auxiliary method to build the output:
// auxiliary method
public void addValue(long value, StringBuilder sb) {
if (value < 10) {
sb.append("0");
}
sb.append(value);
}
And used it to join the pieces:
StringBuilder sb = new StringBuilder();
addValue(hours, sb);
sb.append(":");
addValue(minutes, sb);
sb.append(":");
addValue(seconds, sb);
sb.append(".");
addValue(nanos, sb);
// remove the extra zeroes in the end
String output = sb.toString().replaceAll("0*$", "");
System.out.println(output);
The output is:
00:00:01.4345

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 convenience methods were introduced.
Demo:
import java.time.Duration;
public class Main {
public static void main(String[] args) {
String realTimeStr = "5.2345";
Double realTimeDbl = Double.parseDouble(realTimeStr);
long nanos = (long) (realTimeDbl * 1000_000_000);
Duration duration = Duration.ofNanos(nanos);
System.out.println(duration);
// Custom format
// ####################################Java-8####################################
String formattedDuration = String.format("%02d:%02d:%02d.%d", duration.toHours() % 24,
duration.toMinutes() % 60, duration.toSeconds() % 60, (duration.toNanos() % 1000_000_000) / 100000);
System.out.println(formattedDuration);
// ##############################################################################
// ####################################Java-9####################################
formattedDuration = String.format("%02d:%02d:%02d.%d", duration.toHoursPart(), duration.toMinutesPart(),
duration.toSecondsPart(), duration.toNanosPart() / 100000);
System.out.println(formattedDuration);
// ##############################################################################
}
}
Output:
PT5.2345S
00:00:05.2345
00:00:05.2345
Learn about the modern date-time API from Trail: Date Time.
For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7.
If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

The problem resides in the format, as noticed by Joe C, probably meaning at this line:
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSSS", Locale.getDefault());
try changing it removing one "S"
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS", Locale.getDefault());
notify us if it's correct =)

package com.stackoverflow.examples;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
public class TimeStamp {
public static void main(String[] args) {
String realTimeStr = "5.2345";
Double realTimeDbl = Double.parseDouble(realTimeStr);
long realTimeLng = (long) (realTimeDbl * 1000);
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSSs", Locale.getDefault());
System.out.println("Duration: " + sdf.format(new Date(realTimeLng - TimeZone.getDefault().getRawOffset())));
}
}
I tried SSSs instead of SSSS

Related

ANDROID - How to display datetime that already passed?

I want to display the time that already passed with specific time and date.
Example :
time1 = 2017-06-18 07:00:00 //set time
curtime = 2017-06-19 07:00:01 //get the current time
TextView will just display 0 Years 0 Month 1 Days 00 Hours 00 Minutes 01 Seconds already passed_
If someone have the best keyword for me to finding my self, I appreciate it.
Ref: link1 but not enough to face my issue.
To get the difference between 2 dates, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's the ThreeTenABP (more on how to use it here).
First I parsed the strings to a LocalDateTime object, then I've got the difference between those dates. The API has created 2 different concepts of "time-difference/amount of time": a Period, a date-based amount of time (in terms of years, months and days), and a Duration, a time-based amount (in terms of seconds).
import org.threeten.bp.Duration;
import org.threeten.bp.LocalDate;
import org.threeten.bp.LocalDateTime;
import org.threeten.bp.LocalTime;
import org.threeten.bp.Period;
import org.threeten.bp.format.DateTimeFormatter;
String time1 = "2017-06-18 07:00:00"; // set time
String curtime = "2017-06-19 07:00:01"; // get the current time
// parse the strings to a date object
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime t1 = LocalDateTime.parse(time1, fmt);
LocalDateTime cur = LocalDateTime.parse(curtime, fmt);
// get the period between the dates
LocalDate startDate = t1.toLocalDate();
LocalDate endDate = cur.toLocalDate();
Period period = Period.ZERO;
if (startDate != null && endDate != null) {
period = Period.between(startDate, endDate);
}
// get the duration between the dates
LocalTime startTime = t1.toLocalTime();
LocalTime endTime = cur.toLocalTime();
startTime = startTime != null ? startTime : LocalTime.MIDNIGHT;
endTime = endTime != null ? endTime : LocalTime.MIDNIGHT;
Duration duration = Duration.between(startTime, endTime);
StringBuilder sb = new StringBuilder();
append(sb, period.getYears(), "year");
append(sb, period.getMonths(), "month");
append(sb, period.getDays(), "day");
long seconds = duration.getSeconds();
long hours = seconds / 3600;
append(sb, hours, "hour");
seconds -= (hours * 3600);
long minutes = seconds / 60;
append(sb, minutes, "minute");
seconds -= (minutes * 60);
append(sb, seconds, "second");
System.out.println(sb.toString()); // 1 day 1 second
// auxiliary method
public void append(StringBuilder sb, long value, String text) {
if (value > 0) {
if (sb.length() > 0) {
sb.append(" ");
}
sb.append(value).append(" ");
sb.append(text);
if (value > 1) {
sb.append("s"); // append "s" for plural
}
}
}
The output is:
1 day 1 second
Note that the Period class already keeps the fields (years, months and days) separated, while the Duration class keeps only the seconds (so some calculations are needed to get the correct results) - it actually has methods like toHours(), but it only converts the seconds to hours, and it doesn't separate all the fields like we want.
You can customize the append() method to the exact format you want. I just took the simple approach of printing value + text, but you can change it according to your needs.
Java new Date/Time API
For Java >= 8, there's the new java.time API. You can use this new API and the ThreeTen Extra project, which has the PeriodDuration class (a combination of both Period and Duration).
The code is basically the same as above, the only difference is the packages names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same.
import org.threeten.extra.PeriodDuration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
String time1 = "2017-06-18 07:00:00"; // set time
String curtime = "2017-06-19 07:00:01"; // get the current time
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime t1 = LocalDateTime.parse(time1, fmt);
LocalDateTime cur = LocalDateTime.parse(curtime, fmt);
PeriodDuration pd = PeriodDuration.between(t1, cur);
StringBuilder sb = new StringBuilder();
append(sb, pd.getPeriod().getYears(), "year");
append(sb, pd.getPeriod().getMonths(), "month");
append(sb, pd.getPeriod().getDays(), "day");
long seconds = pd.getDuration().getSeconds();
long hours = seconds / 3600;
append(sb, hours, "hour");
seconds -= (hours * 3600);
long minutes = seconds / 60;
append(sb, minutes, "minute");
seconds -= (minutes * 60);
append(sb, seconds, "second");
System.out.println(sb.toString()); // 1 day 1 second
Of course you can also create a Period and a Duration using the same code of org.threeten.bp's version.
Check DateUtils:
https://developer.android.com/reference/android/text/format/DateUtils.html#getRelativeTimeSpanString(long,long,long)
Should give you what you are looking for.
You need to create Date objects of Calendar objects and compare them to know how much time has passed.
Or you can use the Joda date time library to find it.
Check out
You can use java.time.Duration and java.time.Period which were introduced with Java-8 as part of JSR-310 implementation to model ISO_8601#Durations. With Java-9, some more convenience method were added.
Demo:
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("u-M-d H:m:s", Locale.ENGLISH);
LocalDateTime startDateTime = LocalDateTime.parse("2017-06-18 07:00:00", dtf);
// Use the following line for the curren date-time
// LocalDateTime endDateTime = LocalDateTime.now();
// Use the following line for a given end date-time string
LocalDateTime endDateTime = LocalDateTime.parse("2017-06-19 07:00:01", dtf);
Period period = startDateTime.toLocalDate().until(endDateTime.toLocalDate());
Duration duration = Duration.between(startDateTime, endDateTime);
// ############################ Java-8 ############################
String periodDuration = String.format("%d Years %d Months %d Days %02d Hours %02d Minutes %02d Seconds",
period.getYears(), period.getMonths(), period.getDays(), duration.toHours() % 24,
duration.toMinutes() % 60, duration.toSeconds() % 60);
System.out.println(periodDuration);
// ############################ Java-8 ############################
// ############################ Java-9 ############################
periodDuration = String.format("%d Years %d Months %d Days %02d Hours %02d Minutes %02d Seconds",
period.getYears(), period.getMonths(), period.getDays(), duration.toHoursPart(),
duration.toMinutesPart(), duration.toSecondsPart());
System.out.println(periodDuration);
// ############################ Java-8 ############################
}
}
Output:
0 Years 0 Months 1 Days 00 Hours 00 Minutes 01 Seconds
0 Years 0 Months 1 Days 00 Hours 00 Minutes 01 Seconds
Learn about the modern date-time API from Trail: Date Time.
For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7.
If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Calculate duration between two hours in Java

I want to calculate the time difference (duration) between two hours (HH:mm:ss) in Java. Here, I've read several topics on this subject, but my problem is a little bit different.
I'm not able to use Joda-Time, as well.
Example:
input values: 12:03:00
00:00:00
expected output: 11:57:00
Сode:
public static void main(String[] args) throws ParseException {
Scanner sc = new Scanner(System.in);
String startTime = sc.next();
String endTime = sc.next();
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
Date d1 = sdf.parse(startTime);
Date d2 = sdf.parse(endTime);
long elapsed = d2.getTime() - d1.getTime();
String hms = String.format("%02d:%02d:%02d",
TimeUnit.MILLISECONDS.toHours(elapsed),
TimeUnit.MILLISECONDS.toMinutes(elapsed) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(elapsed)),
TimeUnit.MILLISECONDS.toSeconds(elapsed) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(elapsed)));
if (elapsed > 0) {
System.out.println(hms);
} else {
elapsed = elapsed * (-1); //otherwise, print hours with '-'
String hms1 = String.format("%02d:%02d:%02d",
TimeUnit.MILLISECONDS.toHours(elapsed),
TimeUnit.MILLISECONDS.toMinutes(elapsed) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(elapsed)),
TimeUnit.MILLISECONDS.toSeconds(elapsed) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(elapsed)));
System.out.println(hms1);
}
}
Result:
expected output: 11:57:00
actual output: 12:03:00 //that's the problem
tl;dr
Duration.between(
LocalTime.parse( "12:03:00" ) ,
LocalTime.parse( "23:59:59.999999999" )
).plusNanos( 1 ).withNanos( 0 )
PT11H57M
Use a nanosecond
The modern approach uses the java.time classes.
The catch is that for time-of-day only, there is no midnight. So your 00:00 which you apparently intended for end-of-day is actually interpreted as start-of-day.
There is only the last nanosecond before the day ends. The LocalTime has a constant defined for that last nanosecond: LocalTime.MAX = 23:59:59.999999999
Since you care only about whole seconds, we can take advantage of that fractional second. If your ending time happens to be 00:00:00, substitute LocalTime.MAX. Then calculate a Duration object. You can add a single nanosecond and then truncate the resulting fractional second by setting the fractional second (the nanoseconds) to zero.
For ending times other than 00:00:00, the math still works. Adding a nanosecond gets you ….000000001 fraction of second, and Duration::withNanos will truncate that unwanted fraction.
// This code assumes the inputs are *always* in whole seconds, without any fraction-of-second.
LocalTime start = LocalTime.parse( "12:03:00" );
LocalTime stop = LocalTime.parse( "00:00:00" );
if( stop.equals( LocalTime.MIN ) ) {
stop = LocalTime.MAX ; // `23:59:59.999999999`
}
Duration d = Duration.between( start , stop );
d = d.plusNanos( 1 ).withNanos( 0 ) ;
System.out.println( "start/stop: " + start + "/" + stop );
System.out.println( "d: " + d );
See this code run live at IdeOne.com.
PT11H57M
Formatting
The output from toString is standard ISO 8601 format. The Duration class can parse such strings as well as generate them.
I strongly recommend not representing a span of time in time-of-day style, HH:MM:SS. This is ambiguous and often creates confusion when read by humans.
But if you insist on that format you must build the string yourself. The Duration class lacks a format method seen in other java.time class. Oddly, this class originally lacked methods to extract the parts, a number of days, of hours, of minutes, of seconds, and a fractional second. See this Question for discussion. Java 9 brings such methods, named to…Part.
While using Java 8, I suggest doing string manipulation of the ISO 8601 formatted output. Replace the PT with empty string. If there is an M, replace H with a colon. If there is an S, replace the M with a colon and replace the S with empty string. If no S, replace M with empty string. I believe you can find this code posted on Stack Overflow.
The basic flaw here is that you want the NEAREST distance between two times. When you are constructing your date objects, even though you only format for Hour:Minute:Second it still stores the day/month/year etc... For the dates 12:03:00 and 00:00:00 it defaults them to the same day, so the difference from (Midnight to Noon) is what your getting not (Noon to Midnight) of the next day. The solution for you would be to check if the times are less than 12 (military time) and if so add 1 to the day.
Here's How you do it:
String t1 = "12:03:00";
String t2 = "00:00:00";
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
Date d1 = sdf.parse(t1);
Date d2 = sdf.parse(t2);
Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
c1.setTime(d1);
c2.setTime(d2);
if(c2.get(Calendar.HOUR_OF_DAY) < 12) {
c2.set(Calendar.DAY_OF_YEAR, c2.get(Calendar.DAY_OF_YEAR) + 1);
}
long elapsed = c2.getTimeInMillis() - c1.getTimeInMillis();
Is this what you want to do:
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
public class HourTest {
public static void main(String[] args) throws Exception {
LocalDateTime ldt1 = LocalDateTime.parse("2015-05-04T12:07:00");
LocalDateTime ldt2 = LocalDateTime.parse("2015-05-04T00:00:00");
long seconds = Math.abs(ChronoUnit.SECONDS.between(ldt1, ldt2));
String hms = String.format("%02d:%02d:%02d", seconds / 3600, (seconds / 60) % 60, seconds % 60);
// Prints 12:07:00. I tried it.
System.out.println(hms);
}
}
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.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class Main {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
LocalTime startTime = LocalTime.parse("12:03:00");
LocalTime endTime = LocalTime.parse("00:00:00");
LocalDateTime startDateTime = today.atTime(startTime);
LocalDateTime endDateTime = today.atTime(endTime);
if (startDateTime.isAfter(endDateTime)) {
endDateTime = endDateTime.with(LocalTime.MIN).plusDays(1).with(endTime);
}
Duration duration = Duration.between(startDateTime, endDateTime);
// Default format
System.out.println(duration);
// Custom format
// ####################################Java-8####################################
String formattedDuration = String.format("%02d:%02d:%02d", duration.toHours(), duration.toMinutes() % 60,
duration.toSeconds() % 60);
System.out.println(formattedDuration);
// ##############################################################################
// ####################################Java-9####################################
formattedDuration = String.format("%02d:%02d:%02d", duration.toHoursPart(), duration.toMinutesPart(),
duration.toSecondsPart());
System.out.println(formattedDuration);
// ##############################################################################
}
}
Output:
PT11H57M
11:57:00
11:57:00
Learn about the modern date-time API from Trail: Date Time.
For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7.
If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

How to format an elapsed time interval in hh:mm:ss.SSS format in Java?

I'm making a stop watch where I'm using Java's SimpleDateFormat to convert the number of milliseconds into a nice "hh:mm:ss:SSS" format. The problem is the hours field always has some random number in it. Here's the code I'm using:
public static String formatTime(long millis) {
SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss.SSS");
String strDate = sdf.format(millis);
return strDate;
}
If I take off the hh part then it works fine. Otherwise in the hh part it'll display something random like "07" even if the argument passed in (number of milliseconds) is zero.
I don't know much about the SimpleDateFormat class though. Thanks for any help.
Support for what you want to do is built in to the latest JDKs with a little known class called TimeUnit.
What you want to use is java.util.concurrent.TimeUnit to work with intervals.
SimpleDateFormat does just what it sounds like it does, it formats instances of java.util.Date, or in your case it converts the long value into the context of a java.util.Date and it doesn't know what to do with intervals which is what you apparently are working with.
You can easily do this without having to resort to external libraries like JodaTime.
import java.util.concurrent.TimeUnit;
public class Main
{
private static String formatInterval(final long l)
{
final long hr = TimeUnit.MILLISECONDS.toHours(l);
final long min = TimeUnit.MILLISECONDS.toMinutes(l - TimeUnit.HOURS.toMillis(hr));
final long sec = TimeUnit.MILLISECONDS.toSeconds(l - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min));
final long ms = TimeUnit.MILLISECONDS.toMillis(l - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min) - TimeUnit.SECONDS.toMillis(sec));
return String.format("%02d:%02d:%02d.%03d", hr, min, sec, ms);
}
public static void main(final String[] args)
{
System.out.println(formatInterval(Long.parseLong(args[0])));
}
}
The output will be formatted something like this
13:00:00.000
A shorter way to do this is to use the DurationFormatUtils class in Apache Commons Lang:
public static String formatTime(long millis) {
return DurationFormatUtils.formatDuration(millis, "HH:mm:ss.S");
}
Why not this ?
public static String GetFormattedInterval(final long ms) {
long millis = ms % 1000;
long x = ms / 1000;
long seconds = x % 60;
x /= 60;
long minutes = x % 60;
x /= 60;
long hours = x % 24;
return String.format("%02d:%02d:%02d.%03d", hours, minutes, seconds, millis);
}
Here's how I've done it, using only the standard JDK (this will work as far back as Java 1.1 by changing StringBuilder back to StringBuffer):
static public String formatMillis(long val) {
StringBuilder buf=new StringBuilder(20);
String sgn="";
if(val<0) { sgn="-"; val=Math.abs(val); }
append(buf,sgn,0,(val/3600000)); val%=3600000;
append(buf,":",2,(val/ 60000)); val%= 60000;
append(buf,":",2,(val/ 1000)); val%= 1000;
append(buf,".",3,(val ));
return buf.toString();
}
/** Append a right-aligned and zero-padded numeric value to a `StringBuilder`. */
static private void append(StringBuilder tgt, String pfx, int dgt, long val) {
tgt.append(pfx);
if(dgt>1) {
int pad=(dgt-1);
for(long xa=val; xa>9 && pad>0; xa/=10) { pad--; }
for(int xa=0; xa<pad; xa++ ) { tgt.append('0'); }
}
tgt.append(val);
}
This is the first bit of Joda work I've done where it seemed more tedious than the JDK support. A Joda implementation for the requested format (making a few assumptions about zero fields) is:
public void printDuration(long milliSecs)
{
PeriodFormatter formatter = new PeriodFormatterBuilder()
.printZeroIfSupported()
.appendHours()
.appendSeparator(":")
.minimumPrintedDigits(2)
.appendMinutes()
.appendSeparator(":")
.appendSecondsWithMillis()
.toFormatter();
System.out.println(formatter.print(new Period(milliSecs)));
}
Reviewing the other answers, I came up with this function...
public static String formatInterval(final long interval, boolean millisecs )
{
final long hr = TimeUnit.MILLISECONDS.toHours(interval);
final long min = TimeUnit.MILLISECONDS.toMinutes(interval) %60;
final long sec = TimeUnit.MILLISECONDS.toSeconds(interval) %60;
final long ms = TimeUnit.MILLISECONDS.toMillis(interval) %1000;
if( millisecs ) {
return String.format("%02d:%02d:%02d.%03d", hr, min, sec, ms);
} else {
return String.format("%02d:%02d:%02d", hr, min, sec );
}
}
Here is what's going on. When you pass milliseconds, that number is relative to Jan 1st, 1970. When you pass 0, it takes that date and converts it to your local time zone. If you are in Central time then that happens to be 7PM. If you run this then it all makes sense.
new SimpleDateFormat().format(0) => 12/31/69 7:00 PM
Edit, I think what you want to do is get elapsed time. For this I recommend using JodaTime which already does this pretty well. You do something like
PeriodFormatter formatter = new PeriodFormatterBuilder()
.appendHours()
.appendSuffix(" hour", " hours")
.appendSeparator(" and ")
.appendMinutes()
.appendSuffix(" minute", " minutes")
.appendSeparator(" and ")
.appendSeconds()
.appendSuffix(" second", " seconds")
.toFormatter();
String formattedText = formatter.print(new Period(elapsedMilliSeconds));
Here's another way to do it. Fully self-contained and fully backwards-compatible. Unlimited number of days.
private static String slf(double n) {
return String.valueOf(Double.valueOf(Math.floor(n)).longValue());
}
public static String timeSpan(long timeInMs) {
double t = Double.valueOf(timeInMs);
if(t < 1000d)
return slf(t) + "ms";
if(t < 60000d)
return slf(t / 1000d) + "s " +
slf(t % 1000d) + "ms";
if(t < 3600000d)
return slf(t / 60000d) + "m " +
slf((t % 60000d) / 1000d) + "s " +
slf(t % 1000d) + "ms";
if(t < 86400000d)
return slf(t / 3600000d) + "h " +
slf((t % 3600000d) / 60000d) + "m " +
slf((t % 60000d) / 1000d) + "s " +
slf(t % 1000d) + "ms";
return slf(t / 86400000d) + "d " +
slf((t % 86400000d) / 3600000d) + "h " +
slf((t % 3600000d) / 60000d) + "m " +
slf((t % 60000d) / 1000d) + "s " +
slf(t % 1000d) + "ms";
}
The format happens according to your local timezone, so if you pass 0, it assumes 0 GMT and then converts it in your local timezone.
tl;dr
LocalTime // Represents a time-of-day, without date and without time zone.
.ofNanoOfDay( // Convert a count of nanoseconds into a time-of-day in a generic 24-hour day, ignoring real-world anomalies such as Daylight Saving Time (DST).
Duration // Class that represents a span-of-time not attached to the timeline.
.of( milliseconds ) // Parse your count of milliseconds as a span-of-time.
.toNanos() // Extract total number of nanoseconds in this span-of-time.
) // Returns a `LocalDate` object.
.toString() // Generate text in standard ISO 8601 format for a time-of-day (*not* recommended by me).
java.time.Duration
The proper class to represent a span-of-time unattached to the timeline with a scale of hours-minutes-seconds is Duration. For a scale of years-months-days, use Period.
Duration d = Duration.of( milliseconds ) ;
ISO 8601 format
I suggest you avoid reporting a span-of-time using the time-of-day format of HH:MM:SS. I have seen the inherent ambiguity lead to misinterpretation and confusion in real-world business apps.
There is a standard for reporting such values, defined in ISO 8601: PnYnMnDTnHnMnS. The P marks the beginning while the T separates any year-month-day portion from any hour-minute-second portion.
The java.time classes use the ISO 8601 standard formats by default when parsing/generating strings. This includes the Duration class.
Duration d = Duration.ofMillis( 5_025_678L ) ;
String output = d.toString() ;
See this code run live at IdeOne.com.
PT1H23M45.678S
These ISO 8601 strings can be parsed as well as generated.
Duration d = Duration.parse( "PT1H23M45.678S" ) ;
Time-of-day format
But if you insist on use time-of-day format for your duration, you can put together such a sting by calling the to…Part methods on Duration object.
Duration d = Duration.ofMillis( 5_025_678L ) ;
String output = d.toHoursPart() + ":" + d.toMinutesPart() + ":" + d.toSecondsPart() + "." + TimeUnit.NANOSECONDS.toMillis( d.toNanosPart() ) ;
1:23:45.678
Or we could abuse the LocalTime class to create your string.
Duration d = Duration.ofMillis( 5_025_678L ) ;
long nanoOfDay = d.toNanos() ;
LocalTime localTimeBogus = LocalTime.ofNanoOfDay( nanoOfDay ) ;
String output = localTimeBogus.toString() ;
Again, you can see this code run live at IdeOne.com.
01:23:45.678
org.apache.commons.lang.time.DurationFormatUtils.formatDuration(stopWatch.getTime(), "HH:mm:ss")
What you are trying to format is a duration, not a Date-Time
You have a duration (no. of milliseconds elapsed) which is different from a Date-Time i.e. an instant on timeline. You use SimpleDateFormat to format a java.util.Date which represents an instant on the timeline. The difference can be better understood by the following examples:
This machine has been running since 2021-09-30'T'10:20:30.
This machine has been running for 3 days 4 hours 5 minutes.
The former represents an instant on timeline while the later represents a duration.
java.time
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Also, quoted below is a notice from the home page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Solution using java.time, the modern Date-Time API: I recommend you 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 convenience methods were introduced.
Demo:
import java.time.Duration;
public class Main {
public static void main(String[] args) {
// A sample input
long millis = 123456789L;
Duration duration = Duration.ofMillis(millis);
// Default format
System.out.println(duration);
// Custom format
// ####################################Java-8####################################
String formattedElapsedTime = String.format("%2d:%02d:%02d.%d", duration.toHours() % 24,
duration.toMinutes() % 60, duration.toSeconds() % 60, duration.toMillis() % 1000);
System.out.println(formattedElapsedTime);
// ##############################################################################
// ####################################Java-9####################################
formattedElapsedTime = String.format("%2d:%02d:%02d.%d", duration.toHoursPart(), duration.toMinutesPart(),
duration.toSecondsPart(), duration.toMillisPart());
System.out.println(formattedElapsedTime);
// ##############################################################################
}
}
Output:
PT34H17M36.789S
10:17:36.789
10:17:36.789
ONLINE DEMO
Learn more about the modern Date-Time API* from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project. Android 8.0 Oreo already provides support for java.time.
Using a plain Java Calendar for intervals up to one day (24 hours) see my answer to the question: How to format time intervals in Java?
Variant: Up to 24 hours
Simple formatting for elapsed time less than 24h. Over 24h the code will only display the hours within the next day and won't add the elapsed day to the hours.
public static String formatElapsedTime(long milliseconds) {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
return sdf.format(milliseconds);
}
Missing features in sample code:
Eliminate the timezone with "UTC"
Use the 24h format "HH"
Variant: Over 24 hours
public static String formatElapsedTimeOver24h(long milliseconds) {
// Compiler will take care of constant arithmetics
if (24 * 60 * 60 * 1000 > milliseconds) {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
return sdf.format(milliseconds);
} else {
SimpleDateFormat sdf = new SimpleDateFormat(":mm:ss.SSS");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
// Keep long data type
// Compiler will take care of constant arithmetics
long hours = milliseconds / (60L * 60L * 1000L);
return hours + sdf.format(milliseconds);
}
}
This one actually works, but it seems like I'm tweaking the intent of the method :-).
public static String formatTime(long millis) {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
String strDate = sdf.format(millis - 3600000);
return strDate;
}
For those of you who really knows how this works you'll probably find some caveats.
You can use formatElapsedTime or formatSameDayTime methods in DateUtils class.
This method must work in all not too old versions of Java )
public static String formatNanoSeconds(long duration) {
StringBuilder sb = new StringBuilder(20);
long quotient = duration / 1_000_000;
long remainder = quotient % 1_000;
sb.insert(0, String.format(".%03d", remainder));
quotient = quotient / 1_000;
remainder = quotient % 60;
sb.insert(0, String.format(":%02d", remainder));
quotient = quotient / 60;
remainder = quotient % 60;
sb.insert(0, String.format(":%02d", remainder));
quotient = quotient / 60;
remainder = quotient % 24;
sb.insert(0, String.format(" %02d", remainder));
quotient = quotient / 24;
sb.insert(0, String.format("%d", quotient));
return sb.toString();
}
StringBuilder.insert(), though fulfills array copy, must still work better than string concatenation.
And here's the test:
#Test
void formatNanoSeconds() {
long m = 1_000_000;
assertEquals("0 00:00:00.000", formatNanoSeconds(0));
assertEquals("0 00:00:00.000", formatNanoSeconds(1));
assertEquals("0 00:00:00.000", formatNanoSeconds(999_999));
assertEquals("0 00:00:00.001", formatNanoSeconds(1_000_000));
assertEquals("0 00:00:00.999", formatNanoSeconds(999 * m));
assertEquals("0 00:00:01.000", formatNanoSeconds(1000 * m));
assertEquals("0 00:00:59.000", formatNanoSeconds(59_000 * m));
assertEquals("0 00:01:00.000", formatNanoSeconds(60_000 * m));
assertEquals("0 00:01:01.000", formatNanoSeconds(61_000 * m));
assertEquals("0 00:59:00.000", formatNanoSeconds(59 * 60_000 * m));
assertEquals("0 01:00:00.000", formatNanoSeconds(60 * 60_000 * m));
assertEquals("0 01:01:00.000", formatNanoSeconds(61 * 60_000 * m));
assertEquals("0 23:00:00.000", formatNanoSeconds(23 * 60 * 60_000 * m));
assertEquals("1 00:00:00.000", formatNanoSeconds(24 * 60 * 60_000 * m));
assertEquals("1 01:00:00.000", formatNanoSeconds(25 * 60 * 60_000 * m));
assertEquals("125 17:28:58.819", formatNanoSeconds(
((((125L * 24 * 3600) + (17 * 3600) + (28 * 60) + 58) * 1000) + 819) * m + 1));
assertEquals("90 08:05:04.009", formatNanoSeconds(
((((90L * 24 * 3600) + (8 * 3600) + (5 * 60) + 4) * 1000) + 9) * m + 358));
}

Calculating the difference between two Java date instances

I'm using Java's java.util.Date class in Scala and want to compare a Date object and the current time. I know I can calculate the delta by using getTime():
(new java.util.Date()).getTime() - oldDate.getTime()
However, this just leaves me with a long representing milliseconds. Is there any simpler, nicer way to get a time delta?
Simple diff (without lib)
/**
* Get a diff between two dates
* #param date1 the oldest date
* #param date2 the newest date
* #param timeUnit the unit in which you want the diff
* #return the diff value, in the provided unit
*/
public static long getDateDiff(Date date1, Date date2, TimeUnit timeUnit) {
long diffInMillies = date2.getTime() - date1.getTime();
return timeUnit.convert(diffInMillies,TimeUnit.MILLISECONDS);
}
And then can you call:
getDateDiff(date1,date2,TimeUnit.MINUTES);
to get the diff of the 2 dates in minutes unit.
TimeUnit is java.util.concurrent.TimeUnit, a standard Java enum going from nanos to days.
Human readable diff (without lib)
public static Map<TimeUnit,Long> computeDiff(Date date1, Date date2) {
long diffInMillies = date2.getTime() - date1.getTime();
//create the list
List<TimeUnit> units = new ArrayList<TimeUnit>(EnumSet.allOf(TimeUnit.class));
Collections.reverse(units);
//create the result map of TimeUnit and difference
Map<TimeUnit,Long> result = new LinkedHashMap<TimeUnit,Long>();
long milliesRest = diffInMillies;
for ( TimeUnit unit : units ) {
//calculate difference in millisecond
long diff = unit.convert(milliesRest,TimeUnit.MILLISECONDS);
long diffInMilliesForUnit = unit.toMillis(diff);
milliesRest = milliesRest - diffInMilliesForUnit;
//put the result in the map
result.put(unit,diff);
}
return result;
}
http://ideone.com/5dXeu6
The output is something like Map:{DAYS=1, HOURS=3, MINUTES=46, SECONDS=40, MILLISECONDS=0, MICROSECONDS=0, NANOSECONDS=0}, with the units ordered.
You just have to convert that map to a user-friendly string.
Warning
The above code snippets compute a simple diff between 2 instants. It can cause problems during a daylight saving switch, like explained in this post. This means if you compute the diff between dates with no time you may have a missing day/hour.
In my opinion the date diff is kind of subjective, especially on days. You may:
count the number of 24h elapsed time: day+1 - day = 1 day = 24h
count the number of elapsed time, taking care of daylight savings: day+1 - day = 1 = 24h (but using midnight time and daylight savings it could be 0 day and 23h)
count the number of day switches, which means day+1 1pm - day 11am = 1 day, even if the elapsed time is just 2h (or 1h if there is a daylight saving :p)
My answer is valid if your definition of date diff on days match the 1st case
With JodaTime
If you are using JodaTime you can get the diff for 2 instants (millies backed ReadableInstant) dates with:
Interval interval = new Interval(oldInstant, new Instant());
But you can also get the diff for Local dates/times:
// returns 4 because of the leap year of 366 days
new Period(LocalDate.now(), LocalDate.now().plusDays(365*5), PeriodType.years()).getYears()
// this time it returns 5
new Period(LocalDate.now(), LocalDate.now().plusDays(365*5+1), PeriodType.years()).getYears()
// And you can also use these static methods
Years.yearsBetween(LocalDate.now(), LocalDate.now().plusDays(365*5)).getYears()
The JDK Date API is horribly broken unfortunately. I recommend using Joda Time library.
Joda Time has a concept of time Interval:
Interval interval = new Interval(oldTime, new Instant());
EDIT: By the way, Joda has two concepts: Interval for representing an interval of time between two time instants (represent time between 8am and 10am), and a Duration that represents a length of time without the actual time boundaries (e.g. represent two hours!)
If you only care about time comparisions, most Date implementations (including the JDK one) implements Comparable interface which allows you to use the Comparable.compareTo()
int diffInDays = (int)( (newerDate.getTime() - olderDate.getTime())
/ (1000 * 60 * 60 * 24) )
Note that this works with UTC dates, so the difference may be a day off if you look at local dates. And getting it to work correctly with local dates requires a completely different approach due to daylight savings time.
Using the java.time framework built into Java 8+:
ZonedDateTime now = ZonedDateTime.now();
ZonedDateTime oldDate = now.minusDays(1).minusMinutes(10);
Duration duration = Duration.between(oldDate, now);
System.out.println("ISO-8601: " + duration);
System.out.println("Minutes: " + duration.toMinutes());
Output:
ISO-8601: PT24H10M
Minutes: 1450
For more info, see the Oracle Tutorial and the ISO 8601 standard.
tl;dr
Convert your obsolete java.util.Date objects to their replacement, java.time.Instant. Then calculate the elapsed time as a Duration.
Duration d =
Duration.between( // Calculate the span of time between two moments as a number of hours, minutes, and seconds.
myJavaUtilDate.toInstant() , // Convert legacy class to modern class by calling new method added to the old class.
Instant.now() // Capture the current moment in UTC. About two and a half hours later in this example.
)
;
d.toString(): PT2H34M56S
d.toMinutes(): 154
d.toMinutesPart(): 34
ISO 8601 Format: PnYnMnDTnHnMnS
The sensible standard ISO 8601 defines a concise textual representation of a span of time as a number of years, months, days, hours, etc. The standard calls such such a span a duration. The format is PnYnMnDTnHnMnS where the P means "Period", the T separates the date portion from the time portion, and in between are numbers followed by a letter.
Examples:
P3Y6M4DT12H30M5Sthree years, six months, four days, twelve hours, thirty minutes, and five seconds
PT4H30MFour and a half hours
java.time
The java.time framework built into Java 8 and later supplants the troublesome old java.util.Date/java.util.Calendar classes. The new classes are inspired by the highly successful Joda-Time framework, intended as its successor, similar in concept but re-architected. Defined by JSR 310. Extended by the ThreeTen-Extra project. See the Tutorial.
Moment
The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).
Instant instant = Instant.now() ; // Capture current moment in UTC.
Best to avoid the legacy classes such as Date/Calendar. But if you must inter-operate with old code not yet updated to java.time, convert back and forth. Call new conversion methods added to the old classes. For moving from a java.util.Date to an Instant, call Date::toInstant.
Instant instant = myJavaUtilDate.toInstant() ; // Convert from legacy `java.util.Date` class to modern `java.time.Instant` class.
Span of time
The java.time classes have split this idea of representing a span of time as a number of years, months, days, hours, minutes, seconds into two halves:
Period for years, months, days
Duration for days, hours, minutes, seconds
Here is an example.
ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime now = ZonedDateTime.now ( zoneId );
ZonedDateTime future = now.plusMinutes ( 63 );
Duration duration = Duration.between ( now , future );
Dump to console.
Both Period and Duration use the ISO 8601 standard for generating a String representation of their value.
System.out.println ( "now: " + now + " to future: " + now + " = " + duration );
now: 2015-11-26T00:46:48.016-05:00[America/Montreal] to future: 2015-11-26T00:46:48.016-05:00[America/Montreal] = PT1H3M
Java 9 adds methods to Duration to get the days part, hours part, minutes part, and seconds part.
You can get the total number of days or hours or minutes or seconds or milliseconds or nanoseconds in the entire Duration.
long totalHours = duration.toHours();
In Java 9 the Duration class gets new methods for returning the various parts of days, hours, minutes, seconds, milliseconds/nanoseconds. Call the to…Part methods: toDaysPart(), toHoursPart(), and so on.
ChronoUnit
If you only care about a simpler larger granularity of time, such as “number of days elapsed”, use the ChronoUnit enum.
long daysElapsed = ChronoUnit.DAYS.between( earlier , later );
Another example.
Instant now = Instant.now();
Instant later = now.plus( Duration.ofHours( 2 ) );
…
long minutesElapsed = ChronoUnit.MINUTES.between( now , later );
120
About java.time
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 java.time.
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?
Java SE 8 and SE 9 and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use….
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, and more.
Joda-Time
UPDATE: The Joda-Time project is now in maintenance mode, with the team advising migration to the java.time classes. I leave this section intact for history.
The Joda-Time library uses ISO 8601 for its defaults. Its Period class parses and generates these PnYnMnDTnHnMnS strings.
DateTime now = DateTime.now(); // Caveat: Ignoring the important issue of time zones.
Period period = new Period( now, now.plusHours( 4 ).plusMinutes( 30));
System.out.println( "period: " + period );
Renders:
period: PT4H30M
You need to define your problem more clearly. You could just take the number of milliseconds between the two Date objects and divide by the number of milliseconds in 24 hours, for example... but:
This won't take time zones into consideration - Date is always in UTC
This won't take daylight saving time into consideration (where there can be days which are only 23 hours long, for example)
Even within UTC, how many days are there in August 16th 11pm to August 18th 2am? It's only 27 hours, so does that mean one day? Or should it be three days because it covers three dates?
Days d = Days.daysBetween(startDate, endDate);
int days = d.getDays();
https://www.joda.org/joda-time/faq.html#datediff
A slightly simpler alternative:
System.currentTimeMillis() - oldDate.getTime()
As for "nicer": well, what exactly do you need? The problem with representing time durations as a number of hours and days etc. is that it may lead to inaccuracies and wrong expectations due to the complexity of dates (e.g. days can have 23 or 25 hours due to daylight savings time).
Using millisecond approach can cause problems in some locales.
Lets take, for example, the difference between the two dates 03/24/2007 and 03/25/2007 should be 1 day;
However, using the millisecond route, you'll get 0 days, if you run this in the UK!
/** Manual Method - YIELDS INCORRECT RESULTS - DO NOT USE**/
/* This method is used to find the no of days between the given dates */
public long calculateDays(Date dateEarly, Date dateLater) {
return (dateLater.getTime() - dateEarly.getTime()) / (24 * 60 * 60 * 1000);
}
Better way to implement this is to use java.util.Calendar
/** Using Calendar - THE CORRECT WAY**/
public static long daysBetween(Calendar startDate, Calendar endDate) {
Calendar date = (Calendar) startDate.clone();
long daysBetween = 0;
while (date.before(endDate)) {
date.add(Calendar.DAY_OF_MONTH, 1);
daysBetween++;
}
return daysBetween;
}
Since all the answers here are correct but use legacy java or 3rd party libs like joda or similar, I will just drop another way using new java.time classes in Java 8 and later. See Oracle Tutorial.
Use LocalDate and ChronoUnit:
LocalDate d1 = LocalDate.of(2017, 5, 1);
LocalDate d2 = LocalDate.of(2017, 5, 18);
long days = ChronoUnit.DAYS.between(d1, d2);
System.out.println( days );
There are many ways you can find the difference between dates & times. One of the simplest ways that I know of would be:
Calendar calendar1 = Calendar.getInstance();
Calendar calendar2 = Calendar.getInstance();
calendar1.set(2012, 04, 02);
calendar2.set(2012, 04, 04);
long milsecs1= calendar1.getTimeInMillis();
long milsecs2 = calendar2.getTimeInMillis();
long diff = milsecs2 - milsecs1;
long dsecs = diff / 1000;
long dminutes = diff / (60 * 1000);
long dhours = diff / (60 * 60 * 1000);
long ddays = diff / (24 * 60 * 60 * 1000);
System.out.println("Your Day Difference="+ddays);
The print statement is just an example - you can format it, the way you like.
If you don't want to use JodaTime or similar, the best solution is probably this:
final static long MILLIS_PER_DAY = 24 * 3600 * 1000;
long msDiff= date1.getTime() - date2.getTime();
long daysDiff = Math.round(msDiff / ((double)MILLIS_PER_DAY));
The number of ms per day is not always the same (because of daylight saving time and leap seconds), but it's very close, and at least deviations due to daylight saving time cancel out over longer periods. Therefore dividing and then rounding will give a correct result (at least as long as the local calendar used does not contain weird time jumps other than DST and leap seconds).
Note that this still assumes that date1 and date2 are set to the same time of day. For different times of day, you'd first have to define what "date difference" means, as pointed out by Jon Skeet.
Subtracting the dates in milliseconds works (as described in another post), but you have to use HOUR_OF_DAY and not HOUR when clearing the time parts of your dates:
public static final long MSPERDAY = 60 * 60 * 24 * 1000;
...
final Calendar dateStartCal = Calendar.getInstance();
dateStartCal.setTime(dateStart);
dateStartCal.set(Calendar.HOUR_OF_DAY, 0); // Crucial.
dateStartCal.set(Calendar.MINUTE, 0);
dateStartCal.set(Calendar.SECOND, 0);
dateStartCal.set(Calendar.MILLISECOND, 0);
final Calendar dateEndCal = Calendar.getInstance();
dateEndCal.setTime(dateEnd);
dateEndCal.set(Calendar.HOUR_OF_DAY, 0); // Crucial.
dateEndCal.set(Calendar.MINUTE, 0);
dateEndCal.set(Calendar.SECOND, 0);
dateEndCal.set(Calendar.MILLISECOND, 0);
final long dateDifferenceInDays = ( dateStartCal.getTimeInMillis()
- dateEndCal.getTimeInMillis()
) / MSPERDAY;
if (dateDifferenceInDays > 15) {
// Do something if difference > 15 days
}
Take a look at Joda Time, which is an improved Date/Time API for Java and should work fine with Scala.
int daysDiff = (date1.getTime() - date2.getTime()) / MILLIS_PER_DAY;
Let me show difference between Joda Interval and Days:
DateTime start = new DateTime(2012, 2, 6, 10, 44, 51, 0);
DateTime end = new DateTime(2012, 2, 6, 11, 39, 47, 1);
Interval interval = new Interval(start, end);
Period period = interval.toPeriod();
System.out.println(period.getYears() + " years, " + period.getMonths() + " months, " + period.getWeeks() + " weeks, " + period.getDays() + " days");
System.out.println(period.getHours() + " hours, " + period.getMinutes() + " minutes, " + period.getSeconds() + " seconds ");
//Result is:
//0 years, 0 months, *1 weeks, 1 days*
//0 hours, 54 minutes, 56 seconds
//Period can set PeriodType,such as PeriodType.yearMonthDay(),PeriodType.yearDayTime()...
Period p = new Period(start, end, PeriodType.yearMonthDayTime());
System.out.println(p.getYears() + " years, " + p.getMonths() + " months, " + p.getWeeks() + " weeks, " + p.getDays() + "days");
System.out.println(p.getHours() + " hours, " + p.getMinutes() + " minutes, " + p.getSeconds() + " seconds ");
//Result is:
//0 years, 0 months, *0 weeks, 8 days*
//0 hours, 54 minutes, 56 seconds
If you need a formatted return String like
"2 Days 03h 42m 07s", try this:
public String fill2(int value)
{
String ret = String.valueOf(value);
if (ret.length() < 2)
ret = "0" + ret;
return ret;
}
public String get_duration(Date date1, Date date2)
{
TimeUnit timeUnit = TimeUnit.SECONDS;
long diffInMilli = date2.getTime() - date1.getTime();
long s = timeUnit.convert(diffInMilli, TimeUnit.MILLISECONDS);
long days = s / (24 * 60 * 60);
long rest = s - (days * 24 * 60 * 60);
long hrs = rest / (60 * 60);
long rest1 = rest - (hrs * 60 * 60);
long min = rest1 / 60;
long sec = s % 60;
String dates = "";
if (days > 0) dates = days + " Days ";
dates += fill2((int) hrs) + "h ";
dates += fill2((int) min) + "m ";
dates += fill2((int) sec) + "s ";
return dates;
}
After wading through all the other answers, to keep the Java 7 Date type but be more precise/standard with the Java 8 diff approach,
public static long daysBetweenDates(Date d1, Date d2) {
Instant instant1 = d1.toInstant();
Instant instant2 = d2.toInstant();
long diff = ChronoUnit.DAYS.between(instant1, instant2);
return diff;
}
Note: startDate and endDates are -> java.util.Date
import org.joda.time.Duration;
import org.joda.time.Interval;
// Use .getTime() unless it is a joda DateTime object
Interval interval = new Interval(startDate.getTime(), endDate.getTime());
Duration period = interval.toDuration();
//gives the number of days elapsed between start and end date.
period.getStandardDays();
Similar to days, you can also get hours, minutes and seconds
period.getStandardHours();
period.getStandardMinutes();
period.getStandardSeconds();
Check example here http://www.roseindia.net/java/beginners/DateDifferent.shtml
This example give you difference in days, hours, minutes, secs and milli sec's :).
import java.util.Calendar;
import java.util.Date;
public class DateDifferent {
public static void main(String[] args) {
Date date1 = new Date(2009, 01, 10);
Date date2 = new Date(2009, 07, 01);
Calendar calendar1 = Calendar.getInstance();
Calendar calendar2 = Calendar.getInstance();
calendar1.setTime(date1);
calendar2.setTime(date2);
long milliseconds1 = calendar1.getTimeInMillis();
long milliseconds2 = calendar2.getTimeInMillis();
long diff = milliseconds2 - milliseconds1;
long diffSeconds = diff / 1000;
long diffMinutes = diff / (60 * 1000);
long diffHours = diff / (60 * 60 * 1000);
long diffDays = diff / (24 * 60 * 60 * 1000);
System.out.println("\nThe Date Different Example");
System.out.println("Time in milliseconds: " + diff + " milliseconds.");
System.out.println("Time in seconds: " + diffSeconds + " seconds.");
System.out.println("Time in minutes: " + diffMinutes + " minutes.");
System.out.println("Time in hours: " + diffHours + " hours.");
System.out.println("Time in days: " + diffDays + " days.");
}
}
Use GMT time zone to get an instance of the Calendar, set the time using the set method of Calendar class. The GMT timezone has 0 offset (not really important) and daylight saving time flag set to false.
final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
cal.set(Calendar.YEAR, 2011);
cal.set(Calendar.MONTH, 9);
cal.set(Calendar.DAY_OF_MONTH, 29);
cal.set(Calendar.HOUR, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
final Date startDate = cal.getTime();
cal.set(Calendar.YEAR, 2011);
cal.set(Calendar.MONTH, 12);
cal.set(Calendar.DAY_OF_MONTH, 21);
cal.set(Calendar.HOUR, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
final Date endDate = cal.getTime();
System.out.println((endDate.getTime() - startDate.getTime()) % (1000l * 60l * 60l * 24l));
Following code can give you the desired output:
String startDate = "Jan 01 2015";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd yyyy");
LocalDate date = LocalDate.parse(startDate, formatter);
String currentDate = "Feb 11 2015";
LocalDate date1 = LocalDate.parse(currentDate, formatter);
System.out.println(date1.toEpochDay() - date.toEpochDay());
public static String getDifferenceBtwTime(Date dateTime) {
long timeDifferenceMilliseconds = new Date().getTime() - dateTime.getTime();
long diffSeconds = timeDifferenceMilliseconds / 1000;
long diffMinutes = timeDifferenceMilliseconds / (60 * 1000);
long diffHours = timeDifferenceMilliseconds / (60 * 60 * 1000);
long diffDays = timeDifferenceMilliseconds / (60 * 60 * 1000 * 24);
long diffWeeks = timeDifferenceMilliseconds / (60 * 60 * 1000 * 24 * 7);
long diffMonths = (long) (timeDifferenceMilliseconds / (60 * 60 * 1000 * 24 * 30.41666666));
long diffYears = (long)(timeDifferenceMilliseconds / (1000 * 60 * 60 * 24 * 365));
if (diffSeconds < 1) {
return "one sec ago";
} else if (diffMinutes < 1) {
return diffSeconds + " seconds ago";
} else if (diffHours < 1) {
return diffMinutes + " minutes ago";
} else if (diffDays < 1) {
return diffHours + " hours ago";
} else if (diffWeeks < 1) {
return diffDays + " days ago";
} else if (diffMonths < 1) {
return diffWeeks + " weeks ago";
} else if (diffYears < 12) {
return diffMonths + " months ago";
} else {
return diffYears + " years ago";
}
}
Best thing to do is
(Date1-Date2)/86 400 000
That number is the number of milliseconds in a day.
One date-other date gives you difference in milliseconds.
Collect the answer in a double variable.
Here's a correct Java 7 solution in O(1) without any dependencies.
public static int countDaysBetween(Date date1, Date date2) {
Calendar c1 = removeTime(from(date1));
Calendar c2 = removeTime(from(date2));
if (c1.get(YEAR) == c2.get(YEAR)) {
return Math.abs(c1.get(DAY_OF_YEAR) - c2.get(DAY_OF_YEAR)) + 1;
}
// ensure c1 <= c2
if (c1.get(YEAR) > c2.get(YEAR)) {
Calendar c = c1;
c1 = c2;
c2 = c;
}
int y1 = c1.get(YEAR);
int y2 = c2.get(YEAR);
int d1 = c1.get(DAY_OF_YEAR);
int d2 = c2.get(DAY_OF_YEAR);
return d2 + ((y2 - y1) * 365) - d1 + countLeapYearsBetween(y1, y2) + 1;
}
private static int countLeapYearsBetween(int y1, int y2) {
if (y1 < 1 || y2 < 1) {
throw new IllegalArgumentException("Year must be > 0.");
}
// ensure y1 <= y2
if (y1 > y2) {
int i = y1;
y1 = y2;
y2 = i;
}
int diff = 0;
int firstDivisibleBy4 = y1;
if (firstDivisibleBy4 % 4 != 0) {
firstDivisibleBy4 += 4 - (y1 % 4);
}
diff = y2 - firstDivisibleBy4 - 1;
int divisibleBy4 = diff < 0 ? 0 : diff / 4 + 1;
int firstDivisibleBy100 = y1;
if (firstDivisibleBy100 % 100 != 0) {
firstDivisibleBy100 += 100 - (firstDivisibleBy100 % 100);
}
diff = y2 - firstDivisibleBy100 - 1;
int divisibleBy100 = diff < 0 ? 0 : diff / 100 + 1;
int firstDivisibleBy400 = y1;
if (firstDivisibleBy400 % 400 != 0) {
firstDivisibleBy400 += 400 - (y1 % 400);
}
diff = y2 - firstDivisibleBy400 - 1;
int divisibleBy400 = diff < 0 ? 0 : diff / 400 + 1;
return divisibleBy4 - divisibleBy100 + divisibleBy400;
}
public static Calendar from(Date date) {
Calendar c = Calendar.getInstance();
c.setTime(date);
return c;
}
public static Calendar removeTime(Calendar c) {
c.set(HOUR_OF_DAY, 0);
c.set(MINUTE, 0);
c.set(SECOND, 0);
c.set(MILLISECOND, 0);
return c;
}
That's probably the most straightforward way to do it - perhaps it's because I've been coding in Java (with its admittedly clunky date and time libraries) for a while now, but that code looks "simple and nice" to me!
Are you happy with the result being returned in milliseconds, or is part of your question that you would prefer to have it returned in some alternative format?
Not using the standard API, no. You can roll your own doing something like this:
class Duration {
private final TimeUnit unit;
private final long length;
// ...
}
Or you can use Joda:
DateTime a = ..., b = ...;
Duration d = new Duration(a, b);
Just to answer the initial question:
Put the following code in a Function like Long getAge(){}
Date dahora = new Date();
long MillisToYearsByDiv = 1000l *60l * 60l * 24l * 365l;
long javaOffsetInMillis = 1990l * MillisToYearsByDiv;
long realNowInMillis = dahora.getTime() + javaOffsetInMillis;
long realBirthDayInMillis = this.getFechaNac().getTime() + javaOffsetInMillis;
long ageInMillis = realNowInMillis - realBirthDayInMillis;
return ageInMillis / MillisToYearsByDiv;
The most important here is to work with long numbers when multiplying and dividing. And of course, the offset that Java applies in its calculus of Dates.
:)
Since the question is tagged with Scala,
import scala.concurrent.duration._
val diff = (System.currentTimeMillis() - oldDate.getTime).milliseconds
val diffSeconds = diff.toSeconds
val diffMinutes = diff.toMinutes
val diffHours = diff.toHours
val diffDays = diff.toDays
If you want to fix the issue for date ranges that cross daylight savings time boundary (e.g. one date in summer time and the other one in winter time), you can use this to get the difference in days:
public static long calculateDifferenceInDays(Date start, Date end, Locale locale) {
Calendar cal = Calendar.getInstance(locale);
cal.setTime(start);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
long startTime = cal.getTimeInMillis();
cal.setTime(end);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
long endTime = cal.getTimeInMillis();
// calculate the offset if one of the dates is in summer time and the other one in winter time
TimeZone timezone = cal.getTimeZone();
int offsetStart = timezone.getOffset(startTime);
int offsetEnd = timezone.getOffset(endTime);
int offset = offsetEnd - offsetStart;
return TimeUnit.MILLISECONDS.toDays(endTime - startTime + offset);
}

Find total hours between two Dates

I have two Date objects and I need to get the time difference so I can determine the total hours between them. They happen to be from the same day. The result I would like would have the hours and minutes.
When I use .toString() on my Date object I get this: Fri Dec 18 08:08:10 CST 2009
I've tried the following:
long diff = (this.endDate.getTime() - this.startDate.getTime()) / (60 * 60 * 1000);
But this only gives me hours, not the minutes.
I know this is a simple problem, but I can't figure it out atm.
Edits:
Final solution for those interested. Thanks to Michael Brewer-Davis
Period p = new Period(this.startDate, this.endDate);
long hours = p.getHours();
long minutes = p.getMinutes();
String format = String.format("%%0%dd", 2);
return Long.toString(hours) + ":" + String.format(format, minutes);
This should work.
long secs = (this.endDate.getTime() - this.startDate.getTime()) / 1000;
int hours = secs / 3600;
secs = secs % 3600;
int mins = secs / 60;
secs = secs % 60;
Here's how it works with Joda time:
DateTime startTime, endTime;
Period p = new Period(startTime, endTime);
int hours = p.getHours();
int minutes = p.getMinutes();
You could format with Joda's formatters, e.g., PeriodFormat, but I'd suggest using Java's. See this question for more details.
EDIT: be careful using this method to check hours between. This function don't respect days between. It get just hours between two times. 2022-07-20 11.00 and 2022-07-21 12.00 will return 1 hour, not 25 hours.
Here's simple way:
private static int hoursDifference(Date date1, Date date2) {
final int MILLI_TO_HOUR = 1000 * 60 * 60;
return (int) (date1.getTime() - date2.getTime()) / MILLI_TO_HOUR;
}
java.time.Duration
I should like to contribute the modern (java 8+) answer. The solutions using Joda-Time are fine. The Joda-Time project is in maintenance mode, so for new code we should not use it. I follow the official recommendation from the Joda-Time project and use java.time, the modern Java date and time API:
Duration dur = Duration.between(startDate, endDate);
String result = String.format("%d:%02d", dur.toHours(), dur.toMinutesPart());
System.out.println(result);
This works if startDate and endDate both have type Instant or OffsetDateTime or ZonedDateTime or LocalDateTime or LocalTime. All of the mentioned types are from java.time package. If starting with LocalDate, call either of the atStartOfDay methods.
The toMinutesPart methof was introduced in Java 9. If you are using Java 8 (ot ThreeTen Backport), search for java format duration or similar to learn how to format the duration into hours and minutes.
Two quotes from the Joda-Time home page:
Users are now asked to migrate to java.time (JSR-310).
Note that Joda-Time is considered to be a largely “finished” project.
No major enhancements are planned. If using Java SE 8, please migrate
to java.time (JSR-310).
Links
Oracle tutorial: Date Time explaining how to use java.time.
Joda-Time home page
Please follow Somaiah's suggestion in a comment, use Hours instead:
Hours hours = Hours.hoursBetween(startTime, endTime);
The call to getHours() will only return the hour section of the time difference and ignore all year, month differences so it would not be correct in some cases.
If you use Period.toStandardHours() to try to convert the time difference into hours the calculation will throw an exception if the time difference between the two dates includes difference in either year or month, since the length of month is unknown.
So the getTime() method, I presume, returns an integer.
In which case, the left set of parentheses has type int, right?
and
(60*60*1000)
is also an int.
Which means you get long diff = ((int)/(int)) so the integer division is done BEFORE you cast stuff to long. And hence you lose your minutes.
Try casting them BEFORE you divide.
for kotlin, you can use below function and get hours between two date
private val dateFormat: String = "yyyy-MM-dd # hh:mm a"
val startDate = SimpleDateFormat(dateFormat).parse("2018-10-01 # 12:33 PM")
val endDate = SimpleDateFormat(dateFormat).parse("2018-10-01 # 02:46 PM")
private fun hoursDifference(date1: Date, date2: Date): Int {
val milliToHour : Long = 1000 * 60 * 60
return ((date1.time - date2.time) / milliToHour).toInt()
}
println(hoursDifference(endDate,startDate).toString())
Output:
2
Even though there's already an accepted answer, this is what worked for me using the Joda time library.
/**
*
* #param date1
* #param date2
* #return hours between two dates rounded down
*/
public static int hoursBetween(DateTime date1, DateTime date2) {
if(date1 == null || date2 == null) return NOT_FOUND;
return Math.abs(Hours.hoursBetween(date1.toLocalDateTime(), date2.toLocalDateTime()).getHours());
}
private void getHours(Date d1, Date d2){
long diff = d2.getTime() - d1.getTime();
long diffSeconds = diff / 1000 % 60;
long diffMinutes = diff / (60 * 1000) % 60;
long diffDays = diff / (24 * 60 * 60 * 1000);
long diffHours = diff / (60 * 60 * 1000) % 24;
System.out.print(diffDays + " days, ");
System.out.print(diffHours + " hours, ");
System.out.print(diffMinutes + " minutes, ");
System.out.print(diffSeconds + " seconds.\n");
}`
//Displays:
/* 1 days, 1 hours, 1 minutes, 50 seconds. */
Here's a pure Java 8+ solution that does not involve Joda or mathematical operations
import java.time.*;
import java.time.temporal.*;
// given two java.util.Dates
Date startDate ...
Date endDate ...
// convert them to ZonedDateTime instances
ZonedDateTime start = ZonedDateTime.ofInstant(startDate.toInstant(), ZoneId.systemDefault());
ZonedDateTime end = ZonedDateTime.ofInstant(endDate.toInstant(), ZoneId.systemDefault());
// get the total duration of minutes between them
Duration total = Duration.ofMinutes(ChronoUnit.MINUTES.between(start, end));
// use the duration to determine the hours and minutes values
long hours = total.toHours();
long minutes = total.minusHours(hours).toMinutes();
Here is the simple method :-
Check your Date format,if your date not in this format then change it and pass to this method it will give you a String which is your result. Modify the method as per the requirement.
private String getDateAsTime(String datePrev) {
String daysAsTime = "";
long day = 0, diff = 0;
String outputPattern = "yyyy:MM:dd HH:mm:ss";
SimpleDateFormat outputFormat = new SimpleDateFormat(outputPattern);
Calendar c = Calendar.getInstance();
String dateCurrent = outputFormat.format(c.getTime());
try {
Date date1 = outputFormat.parse(datePrev);
Date date2 = outputFormat.parse(dateCurrent);
diff = date2.getTime() - date1.getTime();
day = TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS);
} catch (ParseException e) {
e.printStackTrace();
}
if (day == 0) {
long hour = TimeUnit.HOURS.convert(diff, TimeUnit.MILLISECONDS);
if (hour == 0)
daysAsTime = String.valueOf(TimeUnit.MINUTES.convert(diff, TimeUnit.MILLISECONDS)).concat(" minutes ago");
else
daysAsTime = String.valueOf(hour).concat(" hours ago");
} else {
daysAsTime = String.valueOf(day).concat(" days ago");
}
return daysAsTime;
}
Hope this will help,

Categories

Resources