java.time
classes already parsing strings in the ISO 8601 format , which is the format in which the your string is.
You said you want LocalDateTime
, but in your code you're using LocalDate
. Either way, you can get both.
Your string has date ( 2018-09-26
), time ( 10:36:40
) and offset ( -03:00
), so the best type to represent it is OffsetDateTime
.
From OffsetDateTime
you can get LocalDateTime
and LocalDate
:
OffsetDateTime odt = OffsetDateTime.parse("2018-09-26T10:36:40-03:00");
LocalDateTime datetime = odt.toLocalDateTime();
LocalDate date = odt.toLocalDate();
Your code did not work because the format passed to DateTimeFormatter
does not match the input string.
The% wrapper, for example, represents the day, followed by dash, followed by the month, dash, and year, but the string begins with the 4-digit year (see documentation for all the letters that can be used and what each one means). Not counting the dd-MM-yyyy
(in single quotation marks), which corresponds to the actual letter "Z" (and not to a specific date field).
If you want to use 'Z'
, you can parse directly to DateTimeFormatter
or LocalDate
, without needing LocalDateTime
:
String str = "2018-09-26T10:36:40-03:00";
LocalDateTime datetime = LocalDateTime.parse(str, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
LocalDate date = LocalDate.parse(str, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
Note that the API already has OffsetDateTime
ready to parse the format you have ( DateTimeFormatter
).
Just as a curiosity, you can also build your own DateTimeFormatter.ISO_OFFSET_DATE_TIME
:
DateTimeFormatter parser = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssXXX");
String str = "2018-09-26T10:36:40-03:00";
LocalDateTime datetime = LocalDateTime.parse(str, parser);
LocalDate date = LocalDate.parse(str, parser);
The difference is that DateTimeFormatter
is more flexible, because it also parses if the string has fractions of a second, while DateTimeFormatter.ISO_OFFSET_DATE_TIME
above only accepts strings in the specified format.
Note that I used parser
instead of u
for the year because y
does not work for AC (BC) dates. Since y
works for both cases (AC and DC), it is the best choice (and this field is the same as u
, by the way). See this SOen response to better understand the details.
Another difference is that DateTimeFormatter.ISO_OFFSET_DATE_TIME
does not accept invalid dates like April 31 (because this month only has 30 days) and February 29 in non-leap years. Already using DateTimeFormatter.ISO_OFFSET_DATE_TIME
, the default is to accept these dates (and make some strange adjustments). See this answer for more details on this behavior.
Just to give an example:
DateTimeFormatter parser = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssXXX");
// 31 de abril
String str = "2018-04-31T10:36:40-03:00";
System.out.println(LocalDate.parse(str, parser)); // 2018-04-30
System.out.println(LocalDate.parse(str, DateTimeFormatter.ISO_OFFSET_DATE_TIME)); // DateTimeParseException
Using ofPattern
, ofPattern
returned accepts April 31, setting it to April 30. DateTimeFormatter
throws DateTimeFormatter.ISO_OFFSET_DATE_TIME
because the date is invalid.
To use DateTimeParseException
and not accept invalid dates, simply use the suggested solution in this answer :
DateTimeFormatter parser = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssXXX")
.withResolverStyle(ResolverStyle.STRICT);
Using ofPattern
, ResolverStyle.STRICT
will only accept valid dates.