Add a Java 8 ISO 8601 time duration expression to java.util.Date

Multi tool use
Add a Java 8 ISO 8601 time duration expression to java.util.Date
I have an expression like "PT20.345S"
, "P2DT3H4M"
etc as described here https://docs.oracle.com/javase/8/docs/api/java/time/Duration.html#parse-java.lang.CharSequence-
"PT20.345S"
"P2DT3H4M"
How can I parse this, add it to the current time and get a java.util.Date
object?
java.util.Date
Neither works:
Date d1 = Date.from(LocalDateTime.now().plus(Duration.parse(_expression)));
Date d2 = Date.from(Duration.parse(_expression).addTo(LocalDateTime.now()));
java.util.Date
java.time.Instant
LocalDateTime
Instant
ZonedDateTime
OffsetDateTime
2 Answers
2
Duration amountToAdd = Duration.parse("PT20.345S"); // Represent a span of time. Here, about twenty and a third seconds.
Instant now = Instant.now() ; // Capture the current moment in UTC.
Instant otherMoment = now.plus(amountToAdd); // Add the span-of-time to the current moment, for a moment in the future (or in the past if the duration is negative).
String output = otherMoment.toString(): // Generate a String in standard ISO 8601 format.
2018-06-30T19:34:47Z
Convert from modern java.time class to legacy class.
Date date1 = Date.from(otherMoment);
System.out.println(date1);
Running just now in Europe/Copenhagen time zone I got:
Sat Jun 30 21:34:47 CEST 2018
If I use your other example duration string, P2DT3H4M
, I got:
P2DT3H4M
Tue Jul 03 00:38:26 CEST 2018
Or if you’re into one-liners:
Date date1 = Date.from(Instant.now().plus(Duration.parse("PT20.345S")));
The java.util.Date
class is long outdated, so ideally you shouldn’t want to have one. If you need one anyway, typically for a legacy API that you cannot change or don’t want to change just now, you are thinking correctly when doing as much of the logic as possible using java.time
, the modern Java date and time API, and converting to Date
only in the end. Date
’s closest cousin in the modern world is Instant
, and direct conversions between Instant
and Date
exist, which is why I am using this class. An Instant
is also lovely independent of zone offsets and time zones.
java.util.Date
java.time
Date
Date
Instant
Instant
Date
Instant
In your code, the first solution should work if you convert the LocalDateTime
to Instant
with ZoneOffset
(example UTC, or default of your system using ZoneOffset.systemDefault()
) like below:
LocalDateTime
Instant
ZoneOffset
ZoneOffset.systemDefault()
Date d1 = Date.from(LocalDateTime.now().plus(Duration.parse(_expression)).toInstant(OffsetDateTime.now().getOffset());
However, LocalDateTime
is wrongly used in this case, because it does not represent a moment, is not a point on the timeline
LocalDateTime
From javadoc:
This class does not store or represent a time-zone. Instead, it is a description of the date, as used for birthdays, combined with the local time as seen on a wall clock. It cannot represent an instant on the time-line without additional information such as an offset or time-zone.
But, an Instant is a moment on the timeline in UTC
This class models a single instantaneous point on the time-line. This might be used to record event time-stamps in the application.
So, if you use an Instant, you know exactly what moment in time is being referred to, regardless of time zones. Since you are going to handle the business logic like adding amount of time to current time and convert to Date, this is a handy class to be used.
Date date1 = Date.from(Instant.now().plus(Duration.parse("PT20.345S")));
Thank you! But why
ZoneOffset.systemDefault()
returns a ZoneId object? It's one of the reasons I am avoiding the new api...– fedd
Jun 30 at 18:12
ZoneOffset.systemDefault()
The goal is to get the Date object plus the specified amount of time. If I use ZoneOffset.UTC, will I achieve it or I need to look how to get a ZoneOffset for the default time zone?
– fedd
Jun 30 at 18:14
Firstly, sorry I didn't check
ZoneOffset.systemDefault()
return ZoneId instead. Then you may use OffsetDateTime.now().getOffset()
to get the default system offset (Reference: stackoverflow.com/questions/41427384/…)– Nguyen Phung
Jun 30 at 18:18
ZoneOffset.systemDefault()
OffsetDateTime.now().getOffset()
LocalDateTime
is exactly the wrong class to be using here. It does not represent a moment, is not a point on the timeline. See the correct Answer by Ole V.V.– Basil Bourque
Jun 30 at 23:55
LocalDateTime
@fedd This:
OffsetDateTime.now().getOffset()
has the same effect as this: ZoneOffset.systemDefault()
. I suggest the second: shorter and your intent is more obvious to the reader. FYI: An offset-from-UTC is merely a number of hours-minutes-seconds, nothing more. A time zone is history of past, present, and future changes in the offset used by the people of a particular region. For example, most of the people in the west coast of North America, America/Los_Angeles
, use an offset of -08:00
(eight hours behind UTC) for half the year, and an offset of -07:00
the other half of the year.– Basil Bourque
Jul 1 at 5:46
OffsetDateTime.now().getOffset()
ZoneOffset.systemDefault()
America/Los_Angeles
-08:00
-07:00
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
FYI: (A) Try to avoid the
java.util.Date
class. Supplanted entirely by thejava.time.Instant
class years ago. (B) Never useLocalDateTime
when you mean an actual moment, a specific point on the timeline. UseInstant
,ZonedDateTime
, orOffsetDateTime
.– Basil Bourque
Jun 30 at 23:50