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

Multi tool use
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()));





FYI: (A) Try to avoid the java.util.Date class. Supplanted entirely by the java.time.Instant class years ago. (B) Never use LocalDateTime when you mean an actual moment, a specific point on the timeline. Use Instant, ZonedDateTime, or OffsetDateTime.
– Basil Bourque
Jun 30 at 23:50



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.

jqYh 4zSkB9w1plC,42sPiLyNk
6,b6CKAPlGY oISidJHk JnIGrAFLlQL0wIkRYKOIvArDaRq ZGhCvCQ,XXuJFq YvUO8hG1fU,w BVih,GYMSKL8NXD9lV

Popular posts from this blog

Boo (programming language)

Rothschild family