Calculate duration between two hours in Java - 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.

Related

How to convert yyy/MM/ss hh:mm:ss into seconds?

Introduction
I'm trying to get the difference in seconds from two Epochs
i.e
2019-05-22 18:28:56 -> 1558542536 seconds
2019-07-22 19:00:00 -> 1563814800 seconds
The diff will be: 5,272,264‬ seconds
This date format comes from a binary file as a String
My code
public static void main(String[] args) throws ParseException
{
String regEpoch = "";
long result = 0;
//System.out.println((fecha = dateFormat.format(date)));
try(RandomAccessFile raf = new RandomAccessFile("binario2.txt", "rw")){
//user inputs a code (for now, doesn't matter if exists or not)
System.out.print("Input a code to look for: ");
String code = scan.next();
while(!code.matches("\\d+"))
{
System.out.println("[ERROR] Only digits accepted");
System.out.print("Input a code to look for: ");
code = scan.next();
}
//Gets the current date in seconds
long getSecs = (new Date().getTime())/1000;
System.out.println("Current tiem in secs: " + getSecs);
//We are "randomly accessing" a binary file. The is no problem here at all. It just works.
//Sets the pointer where I want it, again... this works fine.
raf.seek(27+(80*Integer.parseInt(code)));
//Read the String date correctly, which is 2019-05-22 18:28:56
System.out.println(raf.readUTF());
/*
//Attempt 2
System.out.println(java.time.Instant.ofEpochSecond(Long.parseLong(raf.readUTF())));
Long millis = new SimpleDateFormat("yyyy/MM/ss hh:mm:ss").parse(raf.readUTF()).getTime();
System.out.println(millis);
*/
//Let's try to convert it into seconds... No we can't due to -> Unparseable date: "2019-05-22 18:28:56"
Date dt = dateFormat.parse(raf.readUTF());
long epoch = dt.getTime();
System.out.println("Result is: " + (int)(epoch*1000));
}catch(IOException e){System.out.println("[ERROR] " + e);}
}
Problem
I have read many questions in how to turn seconds into Epoch, but what about the reverse?
Do I have to do it manually?
Is there any library I haven't heard of?
So far what I tried only gets the seconds from the Date with SimpleDateFormat but those are not what I expected...
What do I expect from this
I am currently doing homework and I have been task with calculating the price for a parking ticket and I thought, what if the car doesn't leave, let's say... in a week?
If I work only in the format of hh:mm:ss those cars who stay there a whole week will only pay for one day.
ChronoUnit
I always use ChronoUnit for calculations like this. Works fine.
package test;
import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
public class Test2 {
public static void main(String[] args) throws ParseException {
LocalDateTime date1 = LocalDateTime.parse("2019-05-22T18:58:56");
LocalDateTime date2 = LocalDateTime.parse("2019-05-23T19:00:00"); //LocalDateTime.now();
long seconds = ChronoUnit.SECONDS.between(date1, date2);
System.out.println(seconds);
}
}
Output
86464
For converting to date with SimpleDateFormat, you can see e.g. Java time since the epoch
Duration
Let java.time classes calculate a Duration.
Parse your input after adjusting to standard ISO 8601 format.
LocalDateTime ldtStart = LocalDateTime.parse( "2019-05-22 18:28:56".replace( " " , "T" ) ) ;
Time zone
Specify the time zone, to account for anomalies such as Daylight Saving a Time (DST). Days are not always 24 hours long.
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdtStart = ldtStart.atZone( z ) ;
Calculate a duration.
Duration d = Duration.between( zdtStart , zdtStop ) ;
long seconds = d.toSeconds() ; // Or `getSeconds` before Java 9.
For parking charges, you more likely want hours.
long hours = d.toHours() ;
This should work
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2019-05-22 18:28:56").getTime();

calculate time difference between two hours in timeformat hh:mm:ss java [duplicate]

This question already has answers here:
How to format a duration in java? (e.g format H:MM:SS)
(22 answers)
Comparing time is incorrect when picking 12:00
(3 answers)
Closed 4 years ago.
I am trying to calculate the difference between two hours. Time format must be hh:mm:ss! I implement this code:
public static String timeDifference(long timeDifference1) {
long timeDifference = timeDifference1 / 1000;
int h = (int) (timeDifference / (3600));
int m = (int) ((timeDifference - (h * 3600)) / 60);
int s = (int) (timeDifference - (h * 3600) - m * 60);
return String.format("%02d:%02d:%02d", h, m, s);
}
public static void main(String[] args) throws ParseException {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()) {
String timeStart = sc.next();
String timeStop = sc.next();
char lol[]=timeStop.toCharArray();
if(lol[0]=='0' && lol[1]=='0'){
lol[0]='2';
lol[1]='4';
}
String tetx=String.valueOf(lol);
timeStop=tetx;
char kk[]=timeStart.toCharArray();
if(kk[0]=='0' && kk[1]=='0'){
kk[0]='2';
kk[1]='4';
}
String hhh=String.valueOf(kk);
timeStart=hhh;
SimpleDateFormat format = new SimpleDateFormat("hh:mm:ss");
Date d1 = null;
Date d2 = null;
d1 = format.parse(timeStart);
d2 = format.parse(timeStop);
long diff;
if (d1.getTime() > d2.getTime()) {
diff = (int) (d1.getTime() - d2.getTime());
} else
diff = (int) (d2.getTime() - d1.getTime());
System.out.println(timeDifference(diff));
}
}
Input must be:
10:03:43 15:00:58
13:00:00 14:00:00
00:00:00 12:05:00
12:05:00 00:00:00
And output:
04:57:15
01:00:00
12:05:00
11:55:00
But i get
04:57:15
01:00:00
00:05:00
00:05:00
How can i fix this?
Don't reinvent the wheel. You can do all of this with the java.time package.
The logic becomes slightly less elegant once we have the requirement that a second value of 00:00:00 represents tomorrow. We need to use LocalDateTimes and potentially add a day:
private static String getDifference(final String first, final String second)
{
final LocalTime firstTime = LocalTime.parse(first, DateTimeFormatter.ISO_LOCAL_TIME);
final LocalTime secondTime = LocalTime.parse(second, DateTimeFormatter.ISO_LOCAL_TIME);
final LocalDateTime firstDateTime = LocalDateTime.of(LocalDate.now(), firstTime);
final LocalDateTime secondDateTime = LocalDateTime.of(
LocalDate.now().plusDays(second.equals("00:00:00") ? 1 : 0),
secondTime
);
final Duration diff = Duration.between(firstDateTime, secondDateTime).abs();
return String.format(
"%02d:%02d:%02d",
diff.toDaysPart() < 1 ? diff.toHoursPart() : 24,
diff.toMinutesPart(),
diff.toSecondsPart()
);
}
Call like so:
System.out.println(getDifference("12:05:00", "00:00:00"));
Sample output:
11:55:00
Please note that toMinutesPart and its sibling methods were added in JDK 9. The logic is fairly similar in JDK 8 but more verbose.
The answer by Michael is good (+1). Allow me to add that you don’t need to mention any formatter (though I also see the advantage of being explicit about the format) and you don’t need to invent an artificial and probably incorrect date to deal with the 24:00 issue.
LocalTime start = LocalTime.parse(timeStart);
LocalTime stop = LocalTime.parse(timeStop);
if (stop.isAfter(start)) { // the normal situation
System.out.println(formatDuration(Duration.between(start, stop)));
} else if (stop.equals(LocalTime.MIDNIGHT)) {
System.out.println(
formatDuration(Duration.between(start, stop).plusDays(1)));
} else {
System.out.println("End time " + timeStop + " was before start time " + timeStart);
}
I am assuming that the times are on the same date except that an end time of 00:00:00 would mean midnight at the end of the day (sometimes called 24.00 where I come from). If you need to calculate, say from 13:00 one day to 13:00 to the next day as 24 hours, just delete the second if condition and the last else block.
Feeding your example input gives the output you asked for:
04:57:15
01:00:00
12:05:00
11:55:00
As Michael mentions, the toMinutesPart and toSecondsPart methods were introduced in Java 9. For how to format the duration in earlier Java versions see my answer here.
What went wrong in your code?
To parse times on a 24 hour clock correctly (12:05:00, 13:00:00, 14:00:00, 15:00:58) you need to use uppercase HH for hour of day. Lowercase hh is for hour within AM or PM from 01 to 12 inclusive. When you don’t specify AM or PM, AM is used as default. So 10:03:43 is parsed as you expected. Funnily 15:00:58 is too even though there is no 15:00:58 AM. SimpleDateFormat just extrapolates. The trouble comes with 12:05:00 since 12:05:00 AM means 00:05:00. On my computer I got 23:55:00 (not 00:05:00, as you said you got). This is because you had first altered the start time into 24:00:00 and next calculated the time from 00:05:00 to 24:00:00, which is 23:55:00. Since you know which time is the start time and which is the end time, you probably shouldn’t swap them in the case where they seem to be in the wrong order. In your last example I got 23:55:00 too. What happens is the same except the times aren’t swapped since 00:05:00 is already before 24:00:00.
Please change hh to HH in SimpleDateFormat. This will give you result in 24 hour format. https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
You can add date to fix it:
import java.time.LocalTime;
import java.time.LocalDate;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class MyClass {
public static void main(String args[]) {
DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss");
LocalTime timeStart = LocalTime.parse("00:00:00");
LocalTime timeStop = LocalTime.parse("12:05:00");
LocalDateTime dateTime1 = LocalDateTime.of(LocalDate.now(), timeStart);
LocalDateTime dateTime2 = LocalDateTime.of(LocalDate.now(), timeStop);
executeDifference(dateTime1, dateTime2);
LocalTime timeStart2 = LocalTime.parse("12:05:00");
LocalTime timeStop2 = LocalTime.parse("00:00:00");
LocalDateTime dateTime3 = LocalDateTime.of(LocalDate.now(), timeStart2);
LocalDateTime dateTime4 = LocalDateTime.of(LocalDate.now().plusDays(1), timeStop2);
executeDifference(dateTime3, dateTime4);
}
private static void executeDifference(LocalDateTime timeStart, LocalDateTime timeStop) {
Duration duration = Duration.between(timeStart, timeStop);
durationOutput(duration);
}
private static void durationOutput(Duration duration) {
long hours = duration.toHours();
long minutes = duration.toMinutes() - (hours * 60);
long seconds = duration.getSeconds() - (hours * 3600) - (minutes * 60);
System.out.println(timeUnitsOutput(hours) + ":" + timeUnitsOutput(minutes) + ":" + timeUnitsOutput(seconds));
}
private static String timeUnitsOutput(long units) {
return (units < 10) ? ("0" + units) : String.valueOf(units);
}
}
The output will be:
12:05:00
11:55:00

Java Duration error from a day to another

I found a very simple problem using Java Duration.
LocalTime SaturdayStart = LocalTime.of(22, 30);
LocalTime SaturdayEnd = LocalTime.of(01, 00);
System.out.println(SaturdayStart);
System.out.println(SaturdayEnd);
System.out.println(Duration.between(SaturdayStart, SaturdayEnd));
The output from this code is:
22:30
01:00
PT-21H-30M
And this is the problem. Instead of 21H, I wanted the duration to be 2H-30M. What is causing the method to be unable to see the "day change" between the two times?
Remember that LocalTime just represents a single time, in one day, without a time zone.
Since it represents the time you see on the clock in one day, you can't use it to calculate differences between 22:30 today and 01:00 the next day. Your two LocalTime object represent 22:30 today, and 01:00 today respectively.
To take the day into account, you need a LocalDateTime. This represents not only a time (without a time zone), but also the date in the ISO-8601 calendar system. You can create the two LocalDateTime objects like this:
LocalDateTime start = LocalDateTime.of(LocalDate.now(), LocalTime.of(22, 30));
LocalDateTime end = start.plusDays(1).withHour(1).withMinute(0);
And then you can get the duration:
Duration d = Duration.between(start, end);
System.out.println(d);
By the way, the - characters you get in your wrong output are not delimiters for different components. They are negative signs. This is because you are subtracting 22:30 from 01:00, which is like subtracting a bigger number from a smaller number, you get a negative number.
The returned Duration interval has data, whether the StartTime occurs after EndTime or not, which can be used for further processing; like this
LocalTime SaturdayStart = LocalTime.of(22, 30);
LocalTime SaturdayEnd = LocalTime.of(01, 00);
System.out.println(SaturdayStart);
System.out.println(SaturdayEnd);
Duration interval = Duration.between(SaturdayStart, SaturdayEnd);
interval = interval.isNegative() ? interval.plusDays(1) : interval;
System.out.println(interval);
java.time.Duration is modelled on ISO-8601 standards and PT-21H-30M means a duration of 21 hours and 30 minutes where the minus sign indicates that the end time is earlier than the start time. Therefore, you can not get what you want unless you consider a date with time and the type representing both, date and time is LocalDateTime. You can choose any date and combine it with a time to get a LocalDateTime.
For any given date, if the start time is after the end time, reset the end date-time to midnight, then add one day to it and finally set its time to the end time.
Once you have the duration, you can create a formatted string by getting the hours, minutes, seconds etc. from it. With Java-9 some more convenience methods were introduced which makes it easier.
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.of(22, 30);
LocalTime endTime = LocalTime.of(01, 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("%dH-%dM-%dS", duration.toHours(), duration.toMinutes() % 60,
duration.toSeconds() % 60);
System.out.println(formattedDuration);
// ##############################################################################
// ####################################Java-9####################################
formattedDuration = String.format("%dH-%dM-%dS", duration.toHoursPart(), duration.toMinutesPart(),
duration.toSecondsPart());
System.out.println(formattedDuration);
// ##############################################################################
}
}
Output:
PT2H30M
2H-30M-0S
2H-30M-0S

Format of time is incorrect

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

Java Date is giving incorrect time difference, jumps 1 hour ahead

My time difference is showing an incorrect output, I'm trying to calculate the time difference between startTime and endTime.
Date time1, time2;
long difference;
SimpleDateFormat df = new SimpleDateFormat("HH:mm");
public Time(String startTime, String endTime)
{
this.startTime = startTime;
this.endTime = endTime;
time1 = new Time("16:30", "18:00"); //example
try
{
time1 = df.parse(startTime);
time2 = df.parse(endTime);
}
catch(Exception e) {
System.out.println("invalid time");
}
}
public String getDifference()
{
difference = (time2.getTime() - time1.getTime());
return df.format(difference); //output = 02:30, should be 01:30
}
I know that Joda-Time could make this easier, but I'm supposed not to use any other library.
It calculates the difference correctly as 5400000 milliseconds (1.5 hours), but formats it as 02:30, due to, I think, the time zone.
Add this line in your constructor to set the date format to the UTC time zone, and it should output 01:30 as you expect:
df.setTimeZone(java.util.TimeZone.getTimeZone("UTC"));
Time is the number of milliseconds since a moment called epoch. In your code, you calculate the difference between to moments, and then interpret the result as a timestamp, but it isn't.
The calculated result is the difference between two timestamps in milliseconds. If you want that printed in hours and minutes, do something like:
public String getDifference() {
difference = (time2.getTime() - time1.getTime()) / 1000L;
long hours = difference/3600;
difference %= 3600;
long minutes = difference/60;
difference %= 60;
long seconds = difference;
return String.format("%d:%02d:%02d", hours, minutes, seconds);
}
The date-time API of java.util 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.
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.
Demo:
import java.time.Duration;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("H:m", Locale.ENGLISH);
LocalTime begin = LocalTime.parse("16:30", dtf);
LocalTime end = LocalTime.parse("18:00", dtf);
Duration duration = Duration.between(begin, end);
System.out.println(duration);
// Custom format
// ##########################################Java-8##########################################
System.out.println(String.format("%d:%d", duration.toHours(), duration.toMinutes() % 60));
// ##########################################################################################
// ##########################################Java-9##########################################
System.out.println(String.format("%d:%d", duration.toHoursPart(), duration.toMinutesPart()));
// ##########################################################################################
}
}
Output:
PT1H30M
1:30
1:30
Learn about the modern date-time API from Trail: Date Time.

Categories

Resources