Java Duration error from a day to another - java

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

Related

Why does GregorianCalendar set method give slightly and inconsistent wrong times?

In NetBeans, I run the code below.
The output from one run is
Intended time = 1970-0-1 0:0:0.000
GC time in ms = 102
Reformated GC time = 1970-01-01 00:00:00.102
Deprecated Date ms = 0
Deprecated time = 1970-01-01 00:00:00.000
The output from another run is
Intended time = 1970-0-1 0:0:0.000
GC time in ms = 575
Reformated GC time = 1970-01-01 00:00:00.575
Deprecated Date ms = 0
Deprecated time = 1970-01-01 00:00:00.000
Q1: Why is the Reformatted time (from GregorianCalendar set(...) method) have extra milliseconds - Deprecated - using new Date(...) does not!
Q2: Why does the number of ms vary from run to run?
public class TestGregorianCalendar {
public static void main(String[] args){
String timeZoneString = "GMT+00";
GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone(timeZoneString));
int year = 1970;
int month = 0; // Jan
int day = 1;
int hour = 0;
int min = 0;
int sec = 0;
calendar.set(year, month, day, hour, min, sec);
long ms;
Date date;
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
df.setTimeZone(TimeZone.getTimeZone(timeZoneString));
System.out.println("Intended time = "+year+"-"+month+"-"+day
+" "+hour+":"+min+":"+sec+".000");
calendar.set(year, month, day, hour, min, sec);
ms = calendar.getTimeInMillis();
System.out.println("GC time in ms = "+Long.toString(ms));
date = new Date(ms);
System.out.println("Reformated GC time = "+df.format(date));
Date deprecatedDate = new Date(year-1900, month, day, hour+1, min, sec);
System.out.println("Deprecated Date ms = "+Long.toString(deprecatedDate.getTime()));
System.out.println("Deprecated time = "+df.format(deprecatedDate));
}
}
Grateful for insight!
java.time
I recommend that you use java.time, the modern Java date and time API, for your date and time work.
OffsetDateTime dateTime = OffsetDateTime.of(1970, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC);
System.out.println(dateTime);
long ms = dateTime.toInstant().toEpochMilli();
System.out.println(ms);
Output:
1970-01-01T00:00Z
0
There are no extra milliseconds, or they would gave been printed twice, once in each of the output lines. java.time sanely numbers months the same way humans do, so I have given January as 1. The last 0 in the argument list to OffsetDateTIme.of() is nanosecond of second and ensures that the fraction of second will be 0.
If you want formatted output:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSS");
System.out.println(dateTime.format(formatter));
1970-01-01 00:00:00.000
What went wrong in your code?
Mark Rotteveel already in the comment has answered both of your questions. new GregorianCalendar(TimeZone.getTimeZone(timeZoneString)) created a GregorianCalendar representing the current moment in the specified time zone, with millisecond precision. calendar.set(year, month, day, hour, min, sec) sets the mentioned fields to those values. It does not change other fields such as era and millisecond (of second). So the millisecond value that you get reflects the time of the second the GregorianCalendar object was created, which obviously is not the same each time. This explains the apparently random variations. This is just one of very many confusing sides of GregorianCalendar. I recommend that you don’t use that class.
new Date(year-1900, month, day, hour+1, min, sec) — whoa, using the constructor that has been deprecated since February 1997 because it works unreliably across time zones — creates a new Date object from those values alone without looking at the clock, so here the millisecond of second is 0.
Link
Oracle tutorial: Date Time explaining how to use java.time.
Instant.EPOCH
Instant.EPOCH is the constant for the 1970-01-01T00:00:00Z epoch instant.
import java.time.Instant;
public class Main {
public static void main(String[] args) {
Instant instant = Instant.EPOCH;
System.out.println(instant);
}
}
Output:
1970-01-01T00:00:00Z
In case you need a date-time string representing the instant into a different pattern, you can convert it into OffsetDateTime using Instant#atOffset and then format the same using a DateTimeFormatter instantiated with the desired pattern.
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
Instant instant = Instant.EPOCH;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSS");
String formatted = formatter.format(instant.atOffset(ZoneOffset.UTC));
System.out.println(formatted);
}
}
Output:
1970-01-01 00:00:00.000
The date-time API of java.util and their formatting API, SimpleDateFormat are outdated and error-prone. I suggest you should stop using them completely and switch to the modern date-time API. Learn more about the modern date-time API at Trail: Date Time.

How to get the end of day as a OffsetDateTime in the format 2019-12-29 05:59:59.9999990 +00:00?

Supposing the time zone is CST. I have a webservice that returns a java.util.Date as "2020-03-14". I want to convert it to OffsetDateTime in the format "2020-03-14 05:59:59.9999990 +00:00". The below code does not have the time information.
Date endDate = someService.getEndDate();
Instant instant = Instant.ofEpochMilli(endDate.getTime());
OffsetDateTime offsetEndDt = OffsetDateTime.ofInstant(instant, ZoneOffset.UTC);
The value of offsetEndDt is 2020-03-14T05:00Z
An OffsetDateTime does not have any format itself, it holds the information about the date and the time. If you create an OffsetDateTime just from a date it will get the default time information of 0 hours, minutes, seconds and nanos.
You can output it in various formats using a DateTimeFormatter and create a new instance of OffsetDateTime adding temporal units to an existing one like this:
public static void main(String[] args) {
// example OffsetDateTime
OffsetDateTime offsetEndDt = OffsetDateTime.of(2020, 3, 14, 0, 0, 0, 0,
ZoneOffset.UTC);
// define a formatter for the output
DateTimeFormatter myFormatter = DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss.nnnnnnnnn xxx");
// print it using the previously defined formatter
System.out.println(offsetEndDt.format(myFormatter));
// create a new OffsetDateTime with time information
OffsetDateTime realEndOfDay = offsetEndDt
.withHour(23)
.withMinute(59)
.withSecond(59)
.withNano(999999000);
// print that, too
System.out.println(realEndOfDay.format(myFormatter));
}
It produces the following output using the pattern your example desired output has:
2020-03-14T00:00:00.000000000 +00:00
2020-03-14T23:59:59.999999000 +00:00
First allow me to suggest that you represent the end of your interval NOT as one microsecond before the next day begins, but AS the first moment of the next day exclusive. So a point in time is inside your interval if it is strictly before your end time. This is philosophically more correct. And it rules out the possibility of falsely excluding a point in time within the last 999 nanoseconds of the day from your interval.
// Construct an example java.util.Date for the demonstration
Instant exampleInstant = LocalDate.of(2020, Month.MARCH, 14)
.atStartOfDay(ZoneId.systemDefault())
.toInstant();
Date enddt = Date.from(exampleInstant);
System.out.println("Example java.util.Date: " + enddt);
OffsetDateTime edt = enddt.toInstant()
.atZone(ZoneId.systemDefault())
.plusDays(1)
.truncatedTo(ChronoUnit.DAYS)
.toOffsetDateTime();
System.out.println("End: " + edt);
As one interpretation of EST (of several possible) I have run this code in America/Atikokan time zone (America/Winnipeg gave me EDT). The output was:
Example java.util.Date: Sat Mar 14 00:00:00 EST 2020
End: 2020-03-15T00:00-05:00
If you insist on getting the time 1 microsecond before the new day starts, subtract a microsecond:
OffsetDateTime edt = enddt.toInstant()
.atZone(ZoneId.systemDefault())
.plusDays(1)
.truncatedTo(ChronoUnit.DAYS)
.minus(1, ChronoUnit.MICROS)
.toOffsetDateTime();
End: 2020-03-14T23:59:59.999999-05:00
The below lines of code worked.
Date enddt = someService.getEndDate();
Calendar cal = Calendar.getInstance();
cal.setTime(enddt);
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH);
int day = cal.get(Calendar.DAY_OF_MONTH);
OffsetDateTime edt = OffsetDateTime.of(year,month+1,day,23,59,59,999999000,OffsetDateTime.now().toZonedDateTime().getOffset());

How to manipulate Instant to add two days and string based time? [duplicate]

I have two java.time.Instant objects
Instant dt1;
Instant dt2;
I want to get time (only hours and minutes without date) from dt2 and set it to dt1. What is the best way to to this? Using
dt2.get(ChronoField.HOUR_OF_DAY)
throws java.time.temporal.UnsupportedTemporalTypeException
You have to interpret the Instant at some time zone to get ZonedDateTime. As an Instant measures the ellapsed seconds and nano seconds from epoch 1970-01-01T00:00:00Z you should use UTC to get the same time as the Instant would print. (Z ≙ Zulu Time ≙ UTC)
Getting the time
Instant instant;
// get overall time
LocalTime time = instant.atZone(ZoneOffset.UTC).toLocalTime();
// get hour
int hour = instant.atZone(ZoneOffset.UTC).getHour();
// get minute
int minute = instant.atZone(ZoneOffset.UTC).getMinute();
// get second
int second = instant.atZone(ZoneOffset.UTC).getSecond();
// get nano
int nano = instant.atZone(ZoneOffset.UTC).getNano();
There are also methods to get days, month and year (getX).
Setting the time
Instants are immutable so you can only "set" the time by creating a copy of your instant with the given time change.
instant = instant.atZone(ZoneOffset.UTC)
.withHour(hour)
.withMinute(minute)
.withSecond(second)
.withNano(nano)
.toInstant();
There are also methods to alter days, month and year (withX) as well as methods to add (plusX) or subtract (minusX) time or date values.
To set the time to a value given as a string use: .with(LocalTime.parse("12:45:30"))
Instant does not have any hour / minute. Please read the documentation of Instant class : https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html
If you use System Timezone to convert the Instant , you can use something like this :
LocalDateTime ldt1 = LocalDateTime.ofInstant(dt1, ZoneId.systemDefault());
LocalDateTime ldt2 = LocalDateTime.ofInstant(dt2, ZoneId.systemDefault());
ldt1 = ldt1
.withHour(ldt2.getHour())
.withMinute(ldt2.getMinute())
.withSecond(ldt2.getSecond());
dt1 = ldt1.atZone(ZoneId.systemDefault()).toInstant();
Convert first the Instant to LocalDateTime, and use UTC as its timezone, then you can get its hours.
import java.time.*
LocalDateTime.ofInstant(Instant.now(), ZoneOffset.UTC).getHour()
While the upper answer is a good, I used it but in Kotlin. Thankyou #frido
while (startDate.isBefore(endDate)) {
val year: Int = startDate.atZone(ZoneOffset.UTC).year
val month: Int = startDate.atZone(ZoneOffset.UTC).monthValue
val day: Int = startDate.atZone(ZoneOffset.UTC).dayOfMonth
System.out.printf("%d.%d.%d\n", day, month, year)
startDate = startDate.atZone(ZoneOffset.UTC).withDayOfMonth(
day + 1
).toInstant()
}

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.

Time difference - strange result

I have very simple code which calculates difference between two times:
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;
public class JavaApplication8 {
private static final SimpleDateFormat timeFormat = new SimpleDateFormat("hh:mm:ss.SSS");
public static void main(String[] args) throws InterruptedException {
Date start = GregorianCalendar.getInstance().getTime();
Thread.sleep(100);
Date end = GregorianCalendar.getInstance().getTime();
long diff = end.getTime() - start.getTime();
System.out.println(timeFormat.format(diff));
}
}
but it prints 01:00:00.100 instead of 00:00:00.100, why?
Other way to solve this. Actually time diff that you having is not millisecs of current time. Its is just time diff, so make a simple division of that u can have hours:mins:secs.
And its quite fast.
Date start = GregorianCalendar.getInstance().getTime();
Thread.sleep(100);
Date end = GregorianCalendar.getInstance().getTime();
long longVal = end.getTime() - start.getTime();
long hours = longVal / 3600000;
long mins = (longVal % 3600) / 60000;
long secs = longVal % 60000;
System.out.println(hours + " " + mins + " " + secs);
You have mixed up two concepts:
You are measuring a time interval (difference between TWO points in time)
You are printing a date (ONE single point in time)
The two are not compatible, you will always get such strange effects. In your case, as pointed out on the other comments, the time zone gets mixed in. The concept of time zones exists only for dates (point in time), but makes no sense for intervals.
You can use the Jodatime library or the JSR 310: Date and Time API (coming with Java 8 I think).
With Jodatime you can explicitely construct a interval:
DateTime start = new DateTime(2004, 12, 25, 0, 0, 0, 0);
DateTime end = new DateTime(2005, 1, 1, 0, 0, 0, 0);
Period period = new Period(start, end);
and then format it with a PeriodFormatter
PeriodFormatter daysHoursMinutes = new PeriodFormatterBuilder()
.appendDays()
.appendSuffix(" day", " days")
.appendSeparator(" and ")
.appendMinutes()
.appendSuffix(" minute", " minutes")
.appendSeparator(" and ")
.appendSeconds()
.appendSuffix(" second", " seconds")
.toFormatter();
System.out.println(daysHoursMinutes.print(period));
By separating the concepts of ONE point in time and the time between TWO points in time, you can make sure that there aren't any other surprises (e.g. leap seconds).
It's a timezone issue. DateFormat.format() will by default format the date in your default time zone, which seem to be UTC+1.
You should set the timezone for timeFormat to UTC:
timeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(timeFormat.format(diff));
Also, you should use HH instead of hh in your DateFormat. hh is for 12-hour clock.
new SimpleDateFormat("HH:mm:ss.SSS");
Update :
But there is some other major issue. Currently you are trying to format a duration, which you should not do. Java Date API, do not have any concept of period or duration.
The value which you get from formatting is nothing but the number of milliseconds (equivalent to the difference) from epoch. It's returning a Date object, instead. Although the result might seem correct, but technically, the difference between two dates denotes a period or duration, which is not the same as Date (which denotes a particular instant of time).
You should consider moving to Joda Time for this task, which has classes representing these concepts like Period, Instant, and Duration.
Because your time zone is GMT+1.
If you read the documentation, you'll find what getTime() does:
Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
represented by this Date object.
So 100 ms means January 1, 1970, 00:00:00.100 GMT, which is January 1, 1970, 01:00:00.100 GMT+1.
You can simply set the time zone you want your time converted to:
timeFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
And you want 24h-style format: HH:mm:ss.SSS, otherwise it will show 12 instead of 00 hours.
EDIT: as jarnbjo said: you're trying to apply a date formatter to an interval of time, which obviously won't work as you expect. There's no such time interval formatters in the Java API. You'll have to write your own.

Categories

Resources