Reputation: 2208
I have the below program and looks like ZonedDateTime is not able to parse the date string. Should I use a different date format or different library to parse?
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
class Scratch {
public static void main(String[] args) {
final String inputDate = "2022-03-12T03:59:59+0000Z";
ZonedDateTime.parse(inputDate, DateTimeFormatter.ISO_DATE_TIME).toEpochSecond();
}
}
Exception in thread "main" java.time.format.DateTimeParseException: Text '2022-03-12T03:59:59+0000Z' could not be parsed, unparsed text found at index 19
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2053)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1952)
at java.base/java.time.ZonedDateTime.parse(ZonedDateTime.java:599)
at Scratch.main(scratch_29.java:7)
Process finished with exit code 1
Upvotes: 2
Views: 1129
Reputation: 340070
Your input happens to be a screwy variation of the standard IS0 8601 format used by default with the java.time.Instant
class. Fix your input string, and parse.
Instant.parse( "2022-03-12T03:59:59+0000Z".replace( "+0000Z" , "Z" ) )
Or, reformatted:
Instant.parse
(
"2022-03-12T03:59:59+0000Z"
.replace( "+0000Z" , "Z" )
)
See this code run live at IdeOne.com.
2022-03-12T03:59:59Z
But the very best solution is to use only ISO 8601 formats when exchanging date-time values.
ZonedDateTime
inappropriate hereZonedDateTime
is the wrong class for your input. Your input has a Z
which is a standard abbreviation for an offset from UTC of zero hours-minutes-seconds. But no time zone indicated, only a mere offset. So use OffsetDateTime
or Instant
rather than ZonedDateTime
.
+0000
and Z
redundantThe +0000
also means an offset of zero hours-minutes-seconds. This is the same meaning as the Z
. So this part is redundant. I suggest you educate the publisher of your data about the standard ISO 8601 formats. No need to invent formats such as seen in your input.
If all your inputs have the same ending of +0000Z
, I suggest you clean the incoming data rather than define a formatting pattern.
String input = "2022-03-12T03:59:59+0000Z".replace( "+0000Z" , "Z" ) ;
Instant instant = Instant.parse( input ) ;
You later commented:
"2017-01-04T12:30:00-05:00" , "2017-03-20T22:05:00Z", etc. So I cannot assume all my inputs to have the same ending of +0000Z.
Both of those are standard ISO 8601 formats. Both can be parsed as OffsetDateTime
objects as-is, without alteration.
So I still maintain that the simplest approach, given your range of possible inputs, is to do the replace
string manipulation first, which has no effect if your other two formats arrive. Then parse all three variations as OffsetDateTime
objects. Sometimes programmers tend to over-think a problem, and over-engineer an elaborate solution where a simple one suffices.
Example code:
OffsetDateTime odt1 = OffsetDateTime.parse( "2022-03-12T03:59:59+0000Z".replace( "+0000Z" , "Z" ) ) ;
OffsetDateTime odt2 = OffsetDateTime.parse( "2017-01-04T12:30:00-05:00".replace( "+0000Z" , "Z" ) ) ;
OffsetDateTime odt3 = OffsetDateTime.parse( "2017-03-20T22:05:00Z".replace( "+0000Z" , "Z" ) ) ;
2022-03-12T03:59:59Z
2017-01-04T12:30-05:00
2017-03-20T22:05Z
See this code run live at IdeOne.com.
Trap for DateTimeParseException
while parsing to detect yet another unexpected format.
Of course, the best solution is to educate the publisher of your data about consistent use of ISO 8601 formats such as the latter two examples, while avoiding the screwy first example’s format.
I recommend against tracking time as a count-since-epoch. Such a count is inherently ambiguous and error-prone. Instead, use text in standard ISO 8601 format. But if you insist on a count, here it is.
To get a count of seconds since the epoch reference of 1970-01-01T00:00Z, extract a Instant
from the OffsetDateTime
, and interrogate.
long secondsSinceEpoch = odt.toInstant().getEpochSecond() ;
Upvotes: 2
Reputation: 17535
That isn't a ISO_DATE_TIME format. That would require something like 2022-03-12T03:59:59+0000
(no 'Z'). A formatter that works looks something like:
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
class Scratch {
public static void main(String[] args) {
final String inputDate = "2022-03-12T03:59:59+0000Z";
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.optionalStart()
.appendPattern(".SSS")
.optionalEnd()
.optionalStart()
.appendZoneOrOffsetId()
.optionalEnd()
.optionalStart()
.appendOffset("+HHMM", "0000")
.optionalEnd()
.optionalStart()
.appendLiteral('Z')
.optionalEnd()
.toFormatter();
long epochSecond = ZonedDateTime.parse(inputDate, formatter).toEpochSecond();
System.out.println("epochSecond is " + epochSecond);
}
}
as derived from this post. You can create that formatter in one place and use it over again.
Upvotes: 2