0

So I have:

Date startDate which is Sun Mar 27 17:32:01 EEST 2022

and

String period which is PT240H

And I need to generate a new date based on those 2 values. I need to add that 240H period to the startDate. The 240H meaning 10 days which I need to add to startDate and I will eventually need to have a new date which should be Wed Apr 6 17:32.01 EEST 2022.

PS. I am new to Java, hopefully I don't ask stupid things.

paulalexandru
  • 9,218
  • 7
  • 66
  • 94
  • Does this help - [how to add period to date](https://stackoverflow.com/questions/58652982/how-to-add-a-period-to-java-util-date)? And if possible stay away from `java.util.Date` and use `java.time.LocalDateTime` - it is part of the modern java time API and has methods for operations with time periods which should match your use case. – Chaosfire Mar 30 '22 at 08:09
  • I recommend you don’t use `Date`. That class is poorly designed and long outdated. Instead use `ZonedDateTime` and `Duration`, both from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). The `Duration` class directly parses your string, and `ZonedDateTime` has a `plus` method that accepts a `Duration`. It will be straightforward. – Ole V.V. Mar 30 '22 at 08:14
  • If you can’t avoid getting an old-fashioned `Date`, convert to a modern `Instant` and work from there: `startDate.toInstant().plus(Duration.parse("PT240H"))`. Results in `2022-04-06T14:32:01Z` (output is in UTC). – Ole V.V. Mar 30 '22 at 08:19
  • PS A day is not always 24 hours, it could be 23 or 25 or some other length. So 240 hours does not necessarily mean exactly 10 days. – Ole V.V. Mar 30 '22 at 08:21
  • @Chaosfire Good suggestions. Only while “10 days” is a `Period`, `PT240H` (240 hours) better matches a `Duration`. We can add either to a `LocalDateTime`. Only I’d prefer to use `Instant` or `ZonedDateTime` because they define a unique point in time, just like a `Date` did in its time (despite its name). – Ole V.V. Mar 30 '22 at 08:30
  • The thing is that the result date should be in the same format as the start date. – paulalexandru Mar 30 '22 at 08:46
  • @OleV.V. Great suggestion, i wasn't aware the string can be parsed directly into `Duration`. – Chaosfire Mar 30 '22 at 08:50
  • @paulalexandru That's a question of formatting the resulting date time, it does not change the computation itself. If you work the modern API, you can use [DateTimeFormatter](https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html), if you use the older `Date`, then you need [SimpleDateFormat](https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html). – Chaosfire Mar 30 '22 at 09:05
  • By *in the same format as the start date* do you mean that ot should also be an old-fashioned `Date`, or do you mean that it should be a string in format like `Sun Mar 27 17:32:01 EEST 2022`? And @Chaosfire I recommend that we under *no circumstances whatsoever* use `SimpleDateFormat`, it is so troublesome. – Ole V.V. Mar 30 '22 at 10:51
  • It should not be a string, it should be DATE. As far as I see in code it's a DATE format which is an object which has fastTime and cdate as properties and cdate has lots of other properties like cachedYear, era, year, month, dayOfMonth, minues, fraction, zoneinfo, locale, etc. But when the object is compressed I see only that string. – paulalexandru Mar 30 '22 at 11:52
  • @OleV.V. I agree, but if OP has to work `Date`, i am not sure he has other options to format it. – Chaosfire Mar 30 '22 at 11:57
  • So far so good, i tried the thing with startDate.toInstant().plus(Duration.parse("PT240H")) and it seems to work. However it forces me to convert the type to Instant but I need date. So intelij forced me to add Date.from and hopefully it will turn it into a date of that format. – paulalexandru Mar 30 '22 at 12:01
  • @paulalexandru That’s the correct and good solution. Glad that you found it. – Ole V.V. Mar 30 '22 at 12:02
  • @paulalexandru see this - [how to convert zoned date time to Date](https://stackoverflow.com/questions/32274369/how-to-convert-zoneddatetime-to-date). – Chaosfire Mar 30 '22 at 12:05
  • 2
    @Chaosfire I seem to have understood now that the OP didn’t want a formatted string at all, so the debate is no longer relevant here. So just for the sake of completeness, had they wanted one, the better way would have been formatting a modern `ZonedDateTime` using a modern `DateTimeFormatter`. – Ole V.V. Mar 30 '22 at 12:06
  • Does this already answer the question? [Add a Java 8 ISO 8601 time duration expression to java.util.Date](https://stackoverflow.com/questions/51117076/add-a-java-8-iso-8601-time-duration-expression-to-java-util-date) – Ole V.V. Mar 30 '22 at 12:16

1 Answers1

3

tl;dr

java.util.Date.from( 
    myJavaUtilDate
    .toInstant()
    .plus( Duration.parse( "PT240H" ) ) 
)

Details

Putting together those posted Comments…

You are using terrible date-time classes that were years ago supplanted by the modern java.time classes defined in JSR 310. Avoid using Date, Calendar, and such.

If handed a java.util.Date object, immediately convert to its replacement class, java.time.Instant. Use new conversion methods added to the old classes.

Instant instant = myJavaUtilDate.toInstant() ;

Parse your input string in standard ISO 8601 format as a Duration object.

Duration d = Duration.parse( "PT240H" ) ;

Add to our Instant to produce a second Instant, per immutable objects.

Instant later = instant.plus( d ) ;

You said:

The 240H meaning 10 days

Incorrect, 240 hours is not necessarily 10 days. Adding a value of 240 hours may or may not result in a moment ten days later, if you adjust into a time zone. Some dates in some time zones vary in length, running 23, 23.5, 25, or other numbers of hours long.

And be aware that both java.util.Date and Instant represent a moment as seen in UTC, that is, with an offset of zero hours-minutes-seconds. Unfortunately, the Date#toString method dynamically applies the JVM’s current default time zone while generating its text — giving a false illusion. This confusing behavior is one of the many design flows in the legacy date-time classes.

If you must interoperate with old code not yet updated to java.time, you can convert back to Date. But I strongly recommend moving away from these legacy classes ASAP.

java.util.Date date = Date.from( someInstant ) ; 

Example code

FYI, EEST is not a time zone. Such 2-4 letter pseudo-zones indicate whether Daylight Saving Time (DST) is in effect, and hint at possible time zones. These should be used only for presentation to the user, never in your business logic, data storage, nor data exchange.

Real time zones are named in format of Continent/Region such as Africa/Casablanca and Asia/Tokyo.

The pseudo-zone EEST implies many different time zones. In this example code I use the real time zone "Europe/Bucharest". I am guessing that is your zone, given your user profile.

First we need to recreate your moment reported by Date#toString as ‘Sun Mar 27 17:32:01 EEST 2022’.

// Recreate original conditions.
LocalDate ld = LocalDate.of( 2022 , Month.MARCH , 27 );  // Sun Mar 27 17:32:01 EEST 2022
LocalTime lt = LocalTime.of( 17 , 32 , 1 );
ZoneId z = ZoneId.of( "Europe/Bucharest" );
TimeZone.setDefault( TimeZone.getTimeZone( z ) );
ZonedDateTime zdtStarting = ZonedDateTime.of( ld , lt , z );
Instant then = zdtStarting.toInstant();
java.util.Date startingPoint = Date.from( then );

Convert from legacy class to modern.

Instant instant = startingPoint.toInstant();

Add your desired 240 hours. Adjust into a time zone to obtain a ZonedDateTime, so we can better see its true meaning.

Duration duration = Duration.parse( "PT240H" );
Instant later = instant.plus( duration );
Date endingPoint = Date.from( later );
ZonedDateTime zdtLater = later.atZone( z );

Dump to console.

System.out.println( "-------|  Start  |--------------------" );
System.out.println( "zdtStarting = " + zdtStarting );
System.out.println( "startingPoint = " + startingPoint );
System.out.println( "instant = " + instant );
System.out.println( "-------|  End  |--------------------" );
System.out.println( "later = " + later );
System.out.println( "endingPoint = " + endingPoint );
System.out.println( "zdtLater = " + zdtLater );

When run.

-------|  Start  |--------------------
zdtStarting = 2022-03-27T17:32:01+03:00[Europe/Bucharest]
startingPoint = Sun Mar 27 17:32:01 EEST 2022
instant = 2022-03-27T14:32:01Z
-------|  End  |--------------------
later = 2022-04-06T14:32:01Z
endingPoint = Wed Apr 06 17:32:01 EEST 2022
zdtLater = 2022-04-06T17:32:01+03:00[Europe/Bucharest]
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • I tried this and it worked +1. But the I noticed a couple of things in the OPs question. EEST didn't work when I parsed it. Changed to EST. And the OP's expected result defaults to EDT when I print it. The OP still wanted EST (perhaps a locale issue or TZ?) – WJS Mar 30 '22 at 17:02
  • @WJS Can you post your parsing code? FYI, March 27 was the Daylight Saving Time (DST) "Spring-ahead" day in most of Europe. But I do not think that is relevant given our time-of-day here is in the afternoon. – Basil Bourque Mar 30 '22 at 23:37
  • I simply did `Date.parse` using the OP's string changing EEST to EST). And then printed the result. Then I applied your solution and printed that result. – WJS Mar 30 '22 at 23:54
  • @WJS Do you mean that `java.util.Date.parse( "Sun Mar 27 17:32:01 EEST 2022" )` throws an `IllegalArgumentException` while running `java.util.Date.parse( "Sun Mar 27 17:32:01 EST 2022" )` succeeds? I have no idea what is going on there. `EEST` is DST, while `EST` is standard time. But afternoon of 27th is in DST as far as I can tell (I am not European.) I even used Java 18 (for updated tzdata) and tried setting `TimeZone.setDefault( TimeZone.getTimeZone( "Europe/Bucharest" ) )`. – Basil Bourque Mar 31 '22 at 00:12
  • Yes the first throws an exception. But I made a mistake on the output. Both are EDT. Here is what I did and the output. `Date myJavaUtilDate = new Date(Date.parse("Sun Mar 27 17:32:01 EST 2022"));System.out.println(myJavaUtilDate);Date date = java.util.Date.from( myJavaUtilDate.toInstant().plus( Duration.parse( "PT240H" ) )); System.out.println(date); Sun Mar 27 18:32:01 EDT 2022` `Wed Apr 06 18:32:01 EDT 2022` Sorry if I wasted your time. – WJS Mar 31 '22 at 00:21
  • @WJS Not a complete waste of time. I am curious about why that particular EEST text can be *generated* by `Date` but not *parsed* by `Date`. But the upshot is that such localized values should not be used for data exchange, and the legacy date-time classes should be avoided. – Basil Bourque Mar 31 '22 at 00:28