简体   繁体   中英

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-

How can I parse this, add it to the current time and get a java.util.Date object?

Neither works:

Date d1 = Date.from(LocalDateTime.now().plus(Duration.parse(_expression)));
Date d2 = Date.from(Duration.parse(_expression).addTo(LocalDateTime.now()));
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:

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.

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:

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

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")));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM