Java 8: Calculate difference between two ZonedDateTime - java

I'm trying to write a method to print the time difference between two ZonedDateTimes, regarding the difference between time zones.
I found some solutions but all of them were written to work with LocalDateTime.

You can use method between from ChronoUnit.
This method converts those times to same zone (zone from the first argument) and after that, invokes until method declared in Temporal interface:
static long zonedDateTimeDifference(ZonedDateTime d1, ZonedDateTime d2, ChronoUnit unit){
return unit.between(d1, d2);
}
Since both ZonedDateTime and LocalDateTime implements Temporal interface, you can write also universal method for those date-time types:
static long dateTimeDifference(Temporal d1, Temporal d2, ChronoUnit unit){
return unit.between(d1, d2);
}
But keep in mind, that invoking this method for mixed LocalDateTime and ZonedDateTime leads to DateTimeException.

tl;dr
For hours, minutes, seconds:
Duration.between( zdtA , zdtB ) // Represent a span-of-time in terms of days (24-hour chunks of time, not calendar days), hours, minutes, seconds. Internally, a count of whole seconds plus a fractional second (nanoseconds).
For years, months, days:
Period.between( // Represent a span-of-time in terms of years-months-days.
zdtA.toLocalDate() , // Extract the date-only from the date-time-zone object.
zdtB.toLocalDate()
)
Details
The Answer by Michal S is correct, showing ChronoUnit.
Duration & Period
Another route is the Duration and Period classes. Use the first for shorter spans of time (hours, minutes, seconds), the second for longer (years, months, days).
Duration d = Duration.between( zdtA , zdtB );
Produce a String in standard ISO 8601 format by calling toString. The format is PnYnMnDTnHnMnS where the P marks the beginning and T separates the two portions.
String output = d.toString();
In Java 9 and later, call the to…Part methods to get the individual components. Discussed in another Answer of mine.
Example code
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdtStart = ZonedDateTime.now( z );
ZonedDateTime zdtStop = zdtStart.plusHours( 3 ).plusMinutes( 7 );
Duration d = Duration.between( zdtStart , zdtStop );
2016-12-11T03:07:50.639-05:00[America/Montreal]/2016-12-11T06:14:50.639-05:00[America/Montreal]
PT3H7M
See live code in IdeOne.com.
Interval & LocalDateRange
The ThreeTen-Extra project adds functionality to the java.time classes. One of its handy classes is Interval to represent a span of time as a pair of points on the timeline. Another is LocalDateRange, for a pair of LocalDate objects. In contrast, the Period & Duration classes each represent a span of time as not attached to the timeline.
The factory method for Interval takes a pair of Instant objects.
Interval interval = Interval.of( zdtStart.toInstant() , zdtStop.toInstant() );
You can obtain a Duration from an Interval.
Duration d = interval.toDuration();
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 the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, 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 Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
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.

This gives you minutes between two ZonedDateTimes.
int minutes = (int) (end.toEpochSecond() - start.toEpochSecond()) / 60;

Related

Convert microseconds to milliseconds without loss of precision and format as date-time in Java

How can I convert incoming long time value in microseconds into milliseconds and then format that to data time stamp as below:
yyyyMMdd-HH:mm:ss.SSS
I am using Java SimpleDateFormat to format the long value to the timestamp. But, converting the microseconds to milliseconds seems problem as I am loosing the value.
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd-HH:mm:ss.SSS");
To convert microsecond to millisecond, I am using the TimeUnit:
long micro //microseconds
long milli = TimeUnit.MILLISECONDS.convert(micro, TimeUnit.MICROSECONDS);
What is the right way to convert the value without loosing any data?
I am using java SimpleDateFormat
Don’t.
Avoid the treacherous old date-time classes bundled with the earliest versions of Java. They were supplanted years ago with the java.time classes when JSR 310 was adopted.
convert incoming long time value in microseconds into milliseconds
Don’t.
The java.time classes use a resolution of nanoseconds, finer than your microseconds. So no need to throw away data.
Instant = ( whole seconds + fractional second as nanos )
Extract the number of whole seconds.
long seconds = TimeUnit.MICROSECONDS.toSeconds( micros ) ;
Get the fractional second, the amount of micros left over after subtracting for the whole seconds.
long microsRemaining =
micros
-
TimeUnit.SECONDS.toMicros( seconds )
;
Convert the remaining micros to nanos, because the Instant class we use next represents a count of whole seconds plus a count of nanoseconds (for the fractional second).
long nanos = TimeUnit.MICROSECONDS.toNanos( microsRemaining ) ;
Combine the whole seconds with the fractional second in nanos. The Instant class represents a moment in UTC as a count since the epoch reference of first moment of 1970 in UTC, 1970-01-01T00:00Z.
Instant instant = Instant.ofEpochSecond( seconds ).plusNanos( nanos ) ;
To generate a string in standard ISO 8601 format, simply call toString.
String output = instant.toString() ;
The Z on the end of the string means UTC (an offset-from-UTC of zero hours-minutes-seconds), and is pronounced Zulu.
You can produce strings in your own custom formats using the DateTimeFormatter class. Search Stack Overflow as this has been covered many many many times already.
Tip: Your desired format is so close to the ISO 8601 format, YYYY-MM-DDTHH:MM:SSZ, that I strongly suggest using the standard format rather than make up your own cousin of that.
If you wish to see this same moment through the lens of the wall-clock time used by people of a certain region (a time zone), apply a ZoneId to get a ZonedDateTime.
ZoneId z = ZoneId.of( "Africa/Tunisia" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
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 the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
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.

Get current time in milliseconds in Java (just time, not date as well)

I want to get the current time in milliseconds. I'm using System.currentTimeMillis() but this returns the date as well as the time. I simply want "15:03" in milliseconds, not the date too.
Note that I want an integer and not a formatted string. If it was 08:30, this is the equivalent to 30600 seconds, which is in turn equivalent to 30600000 milliseconds. This is the value I want
tl;dr
Duration.between( todayStart , now ).toMillis()
Details
Get the current moment in the wall-clock time used by the people of a certain region (a time zone).
ZoneId z = ZoneId.of( “Africa/Tunis” ) ;
ZonedDateTime now = ZonedDateTime.now( z ) ;
Get the first moment of the day. Do not assume this is 00:00:00. Let java.time determine.
ZonedDateTime todayStart = now.toLocalDate().atStartOfDay( z ) ;
Represent the delta between them, the span of time unattached to the timeline, as a Duration.
Duration d = Duration.between( todayStart , now ) ;
A Duration has a resolution of nanoseconds. That is finer than the milliseconds you desire. A convenience method will ignore any microseconds or nanoseconds for you.
long millisSinceStartOfToday = d.toMillis() ;
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 the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java 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 Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
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.
Use the LocalTime class:
long millis = LocalTime.now().toNanoOfDay() / 1_000_000;
Basil Bourque correctly points out that it isn’t always this simple: a Daylight Saving Time change (such as will occur in most of the US this Sunday) can mean that, for example, there may not be eight hours between midnight and 8 AM.
You can account for this by using a ZonedDateTime, which accounts for all calendar information, including DST changeovers:
ZonedDateTime now = ZonedDateTime.now();
ZonedDateTime start = now.truncatedTo(ChronoUnit.DAYS);
long millis = ChronoUnit.MILLIS.between(start, now);
Since you are interested in the millis since midnight in the GMT timezone, the easiest approach is probably:
int millis = LocalTime.now(ZoneOffset.UTC).get(ChronoField.MILLI_OF_DAY);

Java Calendar considering hours

Hy guys!
I'm writing a software to keep track of room bookings. Each room has a day of booking, a start time, an end time. The problem is I may have a booking in between two day (eg. from 18-02-2015 23:00 to 19-02-2015).
How can I automate this increasing process without asking the user to insert an end date?
I'm using Calendar for the date but for hours and minutes I just take values from two TextFields.
You could specify the amout of days a room is booked. Then you just have to add the number of days to your first Calendar object.
Working example how to add days in a simple way:
int days = 2; //default duration, placeholder
Calendar now = Calendar.getInstance();
Calendar end = (Calendar) now.clone();
end.add(Calendar.DATE, days);
The Calendar end would then be set the current time in two days.
Normally I wouldn't recommend using Object.clone(), but this answer says it is safe to do so.
There is no way to project a time span with the old Calendar-API (with just one Calendar). But if you could use the new Java 8 Date and Time API, you may use Periods und Durations. They may come in useful, if you need to determine durations for bookings.
However, I can just recommend you to look into the API, since I haven't worked with it enough to provide a useful example.
tl;dr
ZonedDateTime.of( 2015 , Month.FEBRUARY , 18 , 23 , 0 , 0 , 0 , ZoneId.of( "Europe/Paris" ) )
.plus( Duration.ofHours( 3 ) )
2015-02-19T02:00:00+01:00[Europe/Paris]
java.time
The accepted answer uses the outmoded old legacy date-time classes that have proven to be so troublesome and confusing. Now supplanted by the java.time classes.
To specify a moment on the timeline, include the time zone to give context to your date-and-time.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime start = ZonedDateTime.of( 2015 , Month.FEBRUARY , 18 , 23 , 0 , 0 , 0 , z );
Track your reserved number of hours as a Duration.
Duration duration = Duration.ofHours( 3 );
The ZonedDateTime class knows how to do math with a Duration.
ZonedDateTime zdtStop = zdtStart.plus( duration );
You say you have two data-entry fields for hours and minutes. Convert each text entry to a number. The Long class parses a string to a long primitive.
From those numbers get a Duration of hours and minutes.
Duration duration = Duration.ofHours( Long.parseLong( hoursEntry ) )
.plusMinutes( Long.parseLong( minutesEntry ) ) ;
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 the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
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 ThreeTenABP….
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.

SimpleDateFormat parse returns wrong value

I have this code:
public static String formatMinSecOrHourMinSec(final String length) {
try {
final SimpleDateFormat hhmmss = new SimpleDateFormat("HH:mm:ss", Locale.GERMAN);
final Date date = hhmmss.parse(length);
final GregorianCalendar gc0 = new GregorianCalendar(Locale.GERMAN);
gc0.setTime(date);
if(gc0.getTimeInMillis() >= 3600 * 1000){
return hhmmss.format(gc0.getTime());
}else{
final SimpleDateFormat mmss = new SimpleDateFormat("mm:ss");
return mmss.format(gc0.getTime());
}
} catch (final ParseException e) {
LOGGER.debug("Konnte die Länge nicht parsen: " + length + "\n" + e);
return length;
}
}
I estimate that it returns 01:29:00 if length is set to 01:29:00 but it returns 29:00. This is because gc0.getTimeInMillis() returns one hour less (3600 * 1000) than expected. What am I doing wrong ?
this is because java.util.Date is using your default time zone. (print time in ms from date and you will see).
To fix it try:
final SimpleDateFormat hhmmss = new SimpleDateFormat("HH:mm:ss");
hhmmss.setTimeZone(TimeZone.getTimeZone("UTC"));
tl;dr
Do not conflate a span-of-time with a time-of-day. Two different concepts deserve two different classes. A span-of-time is represented by the Duration (or Period) class.
Duration
.ofHours( 1 )
.plusMinutes( 29 )
…or…
Duration
.parse( "PT1H29M" )
Wrong classes
First, you are using inappropriate classes. Apparently you are trying to track a span-of-time but are using time-of-day to do so. A span and a time are two different concepts. Mixing the two leads to ambiguity, confusion, and errors.
Second, you are using terrible old classes that were supplanted years ago by the java.time classes. Never use SimpleDateFormat, GregorianCalendar, etc.
Span-of-time
The correct class for a span-of-time in the range of hours-minutes-seconds is Duration. For a range of years-months-days, use Period.
You can instantiate your Duration from numbers of hours and minutes.
Duration d = Duration.ofHours( 1 ).plusMinutes( 29 ) ;
Or you can parse a string in standard ISO 8601 format, PnYnMnDTnHnMnS.
Duration d = Duration.parse( "PT1H29M" ) ;
Date-Time math
You can do math with date-time values. Perhaps you want to know when is an hour and twenty-nine minutes from now.
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime now = ZonedDateTime.now( z ) ; // Capture the current moment as seen though the wall-clock time used by the people of some particular region.
ZonedDateTime later = now.plus( d ) ; // Add a span-of-time to determine a later moment (or an earlier moment if the `Duration` is negative).
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 the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
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.

How can I convert from Gregorian Calendar to Unix Time, in Java?

I am in need of a method to convert GregorianCalendar Object to Unix Time (i.e. a long). Also need a method to convert Unix Time (long) back to GregorianCalendar Object. Are there any methods out there that does this? If not, then how can I do it? Any help would be highly appreciated.
Link to GregorianCalendar Class --> http://download.oracle.com/javase/1.4.2/docs/api/java/util/GregorianCalendar.html
Thanks.
The methods getTimeInMillis() and setTimeInMillis(long) will let you get and set the time in milliseconds, which is the unix time multiplied by 1000. You will have to adjust manually since unix time does not include milliseconds - only seconds.
long unixTime = gregCal.getTimeInMillis() / 1000;
gregCal.setTimeInMillis(unixTime * 1000);
Aside: If you use dates a lot in your application, especially if you are converting dates or using multiple time zones, I would highly recommend using the JodaTime library. It is very complete and quite a bit more natural to understand than the Calendar system that comes with Java.
I believe that GregorianCalendar.getTimeInMillis() and GregorianCalendar.SetTimeInMillis() will let you get and set long values the way you want.
Check out the setTimeInMillis and getTimeInMillis functions: http://download.oracle.com/javase/6/docs/api/java/util/Calendar.html#getTimeInMillis()
Calendar.getTimeInMillis() should be what you're looking for.
tl;dr
myGregCal.toZonedDateTime().toEpochSecond() // Convert from troublesome legacy `GregorianCalendar` to modern `ZonedDateTime`.
And going the other direction…
GregorianCalendar.from( // Convert from modern `ZonedDateTime` to troublesome legacy class `GregorianCalendar`.
Instant.ofEpochSecond( yourCountOfWholeSecondsSinceEpoch ) // Moment in UTC.
.atZone( // Apply `ZoneId` to `Instant` to produce a `ZonedDateTime` object.
ZoneId.of( "Africa/Tunis" )
)
)
Avoid legacy date-time classes
The other Answers are correct and short. But, FYI, the troublesome old date-time classes such as java.util.Date, java.util.Calendar, and java.text.SimpleDateFormat are now legacy, supplanted by the java.time classes built into Java 8 & Java 9.
So here is how to convert and use the modern classes instead for your problem.
java.time
Convert from the legacy class GregorianCalendar to the modern class ZonedDateTime. Call new methods added to the old classes.
ZonedDateTime zdt = myGregCal.toZonedDateTime() ;
And going the other direction…
GregorianCalendar myGregCal = GregorianCalendar.from( zdt ) ;
If by “Unix time” you meant a count of whole seconds since the epoch reference of first moment of 1970 in UTC, 1970-01-01T00:00:00Z, then call toEpochSecond.
long secondsSinceEpoch = zdt.toEpochSecond() ;
If you meant a count of milliseconds since 1970 started in UTC, then extract an Instant. 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 = zdt.toInstant() ;
Now ask for the count of milliseconds.
long millisecondsSinceEpoch = instant.toEpochMill() ;
Keep in mind that asking for either whole seconds or milliseconds may involve data loss. The ZonedDateTime and Instant both resolve to nanoseconds. So any microseconds or nanoseconds that may be present will be ignored as you count your whole seconds or milliseconds.
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 the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Using a JDBC driver compliant with JDBC 4.2 or later, you may exchange java.time objects directly with your database. No need for strings nor java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java 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 Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
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.

Categories

Resources