Java Time API converts ISO 8601 to ZonedDateTime
I'm having a hard time converting an ISO 8601 formatted string to java.time.LocalDateTime , which is in UTC.
More specifically, I'm trying to write the XMLAdapter , for which you can enter a variety of formats ISO 8601 data as a string (eg 2002-09-24
, 2011-03-22T13:30
, 2015-05-24T12:25:15Z
, 2015-07-28T11:11:15.321+05:30
), and which gives LocalDateTime UTC and vice versa.
The system stores all date and time information internally in UTC time. When a user requests a date or time, it is presented to the user based on its own ZoneId .
source to share
As the name suggests, LocalDateTime
contains date and time. For example, the first example of the date string you have in your question only contains date information, so you cannot parse it directly into LocalDateTime
. What you can do is first disassemble it in LocalDate
and set the time on that object by getting LocalDateTime
.
LocalDateTime localDateTime = LocalDate.parse("2002-09-24").atStartOfDay();
All Date and Time objects have a parse method, for example LocalDate
, which can accept a specific string format. These formats are ISO standard formats as specified in DateTimeFormatter
To format custom datetime strings to objects, Temporal
use DateTimeFormatter and provide your own template.
source to share
TL; DR
Instant.parse( "2015-05-24T12:25:15Z" )
.atZone( ZoneId.of( "America/Montreal" ) )
ZonedDateTime
vs LocalDateTime
Your question contradicts itself, with a title requesting ZonedDateTime
and a body requesting LocalDateTime
. These are two completely different beasts. One ( ZonedDateTime
) is a specific moment on the timeline, the other ( LocalDateTime
) is only a vague idea of โโpossible moments, but not a specific moment.
For example, LocalDateTime
Christmas starting this year, 2017-12-25T00:00:00
but it doesn't matter until you apply the time zone as Santa delivers first to the Kiribati Islands at midnight (the first midnight on Earth), then to New Zealand at a later midnight, then at Australia at later midnight and so on, moving west towards consecutive midnight.
Also, you seem to be confusing the question of what the input is and what the result is.
Instant
To enter a type 2015-05-24T12:25:15Z
that represents a moment on the timeline in UTC (which Z
is short for Zulu
and stands for UTC). To represent this, use the class Instant
. The class Instant
represents a moment on the timeline in UTC with nanosecond resolution (up to nine (9) decimal places).
Instant instant = Instant.parse( "2015-05-24T12:25:15Z" );
Typically, you should work in UTC for most business logic, data storage, data exchange, and database. So, for that Instant
, that's all you need.
ZonedDateTime
If you need to customize in a time zone, for example to present to the user, apply ZoneId
to get ZonedDateTime
.
Specify the name of the current time zone in the format continent/region
, for example America/Montreal
, Africa/Casablanca
or Pacific/Auckland
. Never use the 3-4 letter abbreviation, for example EST
or IST
, as they are not real time zones and not standardized or even unique (!).
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );
LocalDate
If you have a date-only value, parse it as an object LocalDate
.
LocalDate localDate = LocalDate.parse( "2002-09-24" );
To get the first moment of day for that date, specify the time zone. At any given moment, the date around the world changes by zone.
Also, don't assume the day starts on time 00:00:00
. Anomalies such as Daylight Saving Time (DST) can cause the first moment to become something like 01:00:00
. Let java.time define the first times of the day.
ZonedDateTime zdt = localDate.atStartOfDay( z );
About java.time
The java.time framework is built into Java 8 and later. These classes supersede the nasty old legacy datetime classes such as java.util.Date
, Calendar
and . SimpleDateFormat
The Joda-Time project , now in maintenance mode , advise moving to the java.time classes .
To learn more, see the Oracle Tutorial . And search Stack Overflow for many examples and explanations. Specification JSR 310 .
Where can I get the java.time classes?
- Java SE 8 and SE 9 and later
- Built in.
- Part of the standard Java API with a combined implementation.
- Java 9 adds some minor features and fixes.
- Java SE 6 and SE 7
- Most of the java.time functionality goes back to Java 6 and 7 in ThreeTen-Backport .
- Android
- The ThreeTenABP project adapts the ThreeTen-Backport (mentioned above) specifically for Android.
- See. How to use ... ThreeTenABP .
The ThreeTen-Extra project extends java.time with additional classes. This project is proof of possible future additions to java.time. Here you can find useful classes, such asInterval
,YearWeek
,YearQuarter
and longer .
source to share
public class LocalDateTimeXmlAdapter extends XmlAdapter<String, LocalDateTime> {
private static final Pattern ZONE_PATTERN = Pattern.compile("T.*(\\+|\\-|Z)");
@Override
public LocalDateTime unmarshal(String isoDateTime) throws Exception {
LocalDateTime utcDateTime;
if (ZONE_PATTERN.matcher(isoDateTime).matches()) {
OffsetDateTime offsetDateTime = OffsetDateTime.parse(isoDateTime, DateTimeFormatter.ISO_DATE_TIME);
ZoneOffset offset = offsetDateTime.getOffset();
utcDateTime = offsetDateTime.toLocalDateTime().plusSeconds(offset.getTotalSeconds());
} else {
LocalDateTime localDateTime = LocalDateTime.parse(isoDateTime, DateTimeFormatter.ISO_DATE_TIME);
ZoneId zoneId = ZoneId.systemDefault(); // TODO: Get ZoneId from userProfile
ZoneOffset offset = ZonedDateTime.now(zoneId).getOffset();
utcDateTime = localDateTime.minusSeconds(offset.getTotalSeconds());
}
return utcDateTime;
}
@Override
public String marshal(LocalDateTime utcDateTime) throws Exception {
ZoneId zoneId = ZoneId.systemDefault(); // TODO: Get ZoneId from userProfile
ZoneOffset offset = ZonedDateTime.now(zoneId).getOffset();
return utcDateTime.plusSeconds(offset.getTotalSeconds()).format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
}
}
source to share