How to parse "2021-11-20 01:00" formatted date to LocalDateTime
? I'm trying like:
String value = "2021-11-20 01:00";
ZonedDateTime zDate = ZonedDateTime.parse(value, DateTimeFormatter.ofPattern("yyyy-MM-ddxxx"));
But getting this strange error:
java.time.format.DateTimeParseException: Text '2021-11-20 01:00' could not be parsed: Unable to obtain ZonedDateTime from TemporalAccessor: {OffsetSeconds=3600},ISO resolved to 2021-11-20 of type java.time.format.Parsed
...Unsupported field: InstantSeconds...
Any suggestions? This time format is used by European VIES VAT ID checking system when receiving XML (SOAP) response: <requestDate>2021-11-20 01:00</requestDate>
. The same error with OffsetDateTime
..
Interesting thing is that Javadoc says "Three letters (x) outputs the hour and minute, with a colon, such as ' 01:30'". So why above pattern is not working?
Tried also this one - the same error:
ZonedDateTime zDate = ZonedDateTime.parse(value, DateTimeFormatter.ISO_OFFSET_DATE);
Complete error log:
Exception in thread "main" java.time.format.DateTimeParseException: Text '2021-11-20 01:00' could not be parsed: Unable to obtain OffsetDateTime from TemporalAccessor: {OffsetSeconds=3600},ISO resolved to 2021-11-20 of type java.time.format.Parsed
at java.base/java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:2017)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1952)
at java.base/java.time.OffsetDateTime.parse(OffsetDateTime.java:402)
at javaapplication5.JavaApplication5.checkVATatVIES(JavaApplication5.java:162)
at javaapplication5.JavaApplication5.main(JavaApplication5.java:65)
Caused by: java.time.DateTimeException: Unable to obtain OffsetDateTime from TemporalAccessor: {OffsetSeconds=3600},ISO resolved to 2021-11-20 of type java.time.format.Parsed
at java.base/java.time.OffsetDateTime.from(OffsetDateTime.java:370)
at java.base/java.time.format.Parsed.query(Parsed.java:235)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
... 3 more
Caused by: java.time.DateTimeException: Unable to obtain Instant from TemporalAccessor: {OffsetSeconds=3600},ISO resolved to 2021-11-20 of type java.time.format.Parsed
at java.base/java.time.Instant.from(Instant.java:378)
at java.base/java.time.OffsetDateTime.from(OffsetDateTime.java:365)
... 5 more
Caused by: java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: InstantSeconds
at java.base/java.time.format.Parsed.getLong(Parsed.java:203)
at java.base/java.time.Instant.from(Instant.java:373)
... 6 more
Using OpenJDK 11.
CodePudding user response:
There is no Java type consisting of only a date and a timezone. ZonedDateTime and OffsetDateTime contain, as their names imply, both a date and a time. So you need to create a formatter that will assume a default time of day:
String value = "2021-11-20 01:00";
DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
builder.appendPattern("yyyy-MM-ddxxx");
builder.parseDefaulting(ChronoField.HOUR_OF_DAY, 0);
DateTimeFormatter formatter = builder.toFormatter();
ZonedDateTime zDate = ZonedDateTime.parse(value, formatter);
Of course, the hour of day can be any value you choose: 12
to represent noon, for example. But it has to be something valid.
CodePudding user response:
tl;dr
org.threeten.extra.OffsetDate.parse( "2021-11-20 01:00" )
org.threeten.extra.OffsetDate
The java.time classes built into Java do not offer a class for the idea of a date combined with an offset. So your parse attempts make no sense.
The ThreeTen-Extra project aims at supplementing the functionality of java.time. It includes the OffsetDate
class for your particular need. Add the library to your project.
String input = "2021-11-20 01:00" ;
OffsetDate od = OffsetDate.parse( input ) ;
From that OffsetDate
object you can obtain either the LocalDate
part or the ZoneOffset
part. And you can determine other date-time values such as adding a time-of-day to get an OffsetDateTime
.
You commented:
if I make a request at 21th at 00:30 AM, I would get the response containing date of 20th.. because our time is UTC 2, and their time is UTC 1
As an aside, a tip: I suggest making a habit of using fully-formed offsets of hour with padding zero, and with minute too. While allowed by various standards, I have seen multiple libraries that fail when abbreviated. So I recommend “ 02:00” rather than “UTC 2”.
Here is some example code demonstrating the scenario you describe. We use the time zone of Africa/Brazzaville
because it has an offset of 01:00 at that moment, and we use Europe/Kaliningrad
for its offset then of 02:00.
LocalDate ld = LocalDate.of( 2021 , Month.NOVEMBER , 21 );
LocalTime lt = LocalTime.of( 0 , 30 );
ZoneId zKaliningrad = ZoneId.of( "Europe/Kaliningrad" );
ZonedDateTime zdtKaliningrad = ZonedDateTime.of( ld , lt , zKaliningrad );
ZoneId zBrazzaville = ZoneId.of( "Africa/Brazzaville" );
ZonedDateTime zdtBrazzaville = zdtKaliningrad.withZoneSameInstant( zBrazzaville );
OffsetDate od = OffsetDate.from( zdtBrazzaville );
OffsetDateTime odt = od.atTime( LocalTime.MIN );
ZonedDateTime asSeenInKaliningrad = odt.atZoneSameInstant( zKaliningrad );
When run.
zdtKaliningrad = 2021-11-21T00:30 02:00[Europe/Kaliningrad]
zdtBrazzaville = 2021-11-20T23:30 01:00[Africa/Brazzaville]
od = 2021-11-20 01:00
odt = 2021-11-20T00:00 01:00
asSeenInKaliningrad = 2021-11-20T01:00 02:00[Europe/Kaliningrad]
Personally, I question the practical value of the concept of date-with-offset, but that is beside the point of your Question.
Working in specific time zones is usually less problematic than working with mere offsets.
I would argue that it makes more sense to track a date-with-zone as a moment, the point on the timeline when the day begins, along with the named time zone rather than an offset.
String result =
LocalDate
.of( 2021 , 11 , 20 )
.atStartOfDay( ZoneId.of( "Africa/Brazzaville" ) )
.toString()
;
See this code run live at IdeOne.com.
2021-11-20T00:00 01:00[Africa/Brazzaville]
For data exchange of text representing a single day, I would recommend transmitting this string 2021-11-20T00:00 01:00[Africa/Brazzaville]
in its format that extends ISO 8601 by appending the name of the time zone in square brackets.
CodePudding user response:
You can specify ur pattern by yourself as String like this:
String str = "2021-11-20 01:00";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime date= LocalDateTime.parse(str, formatter);