How to Parse an Iso 8601-Formatted Date

Converting ISO 8601-compliant String to java.util.Date

Unfortunately, the time zone formats available to SimpleDateFormat (Java 6 and earlier) are not ISO 8601 compliant. SimpleDateFormat understands time zone strings like "GMT+01:00" or "+0100", the latter according to RFC # 822.

Even if Java 7 added support for time zone descriptors according to ISO 8601, SimpleDateFormat is still not able to properly parse a complete date string, as it has no support for optional parts.

Reformatting your input string using regexp is certainly one possibility, but the replacement rules are not as simple as in your question:

  • Some time zones are not full hours off UTC, so the string does not necessarily end with ":00".
  • ISO8601 allows only the number of hours to be included in the time zone, so "+01" is equivalent to "+01:00"
  • ISO8601 allows the usage of "Z" to indicate UTC instead of "+00:00".

The easier solution is possibly to use the data type converter in JAXB, since JAXB must be able to parse ISO8601 date string according to the XML Schema specification. javax.xml.bind.DatatypeConverter.parseDateTime("2010-01-01T12:00:00Z") will give you a Calendar object and you can simply use getTime() on it, if you need a Date object.

You could probably use Joda-Time as well, but I don't know why you should bother with that (Update 2022; maybe because the entire javax.xml.bind section is missing from Android's javax.xml package).

How to get current moment in ISO 8601 format with date, hour, and minute?

Use SimpleDateFormat to format any Date object you want:

TimeZone tz = TimeZone.getTimeZone("UTC");
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'"); // Quoted "Z" to indicate UTC, no timezone offset
df.setTimeZone(tz);
String nowAsISO = df.format(new Date());

Using a new Date() as shown above will format the current time.

How to parse a ISO 8601 to Date in Java?

Problems with your code:

  1. The pattern for parsing should match with the given date-time string. You have missed 'T' in the pattern for parsing.
  2. Also, you have used M instead of m for "Minute in hour". The symbol, M is used for "Month in year". Read the documentation carefully.

Demo with correct patterns:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Main {
public static void main(String[] args) throws ParseException {
String date = "2021-05-14T09:26:20";
SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date newDate = parser.parse(date);
System.out.println(format.format(newDate));
}
}

ONLINE DEMO

Introducing java.time, the modern Date-Time API:

Note that the java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*, released in March 2014 as part of Java SE 8 standard library.

Solution using java.time, the modern Date-Time API:

The modern Date-Time API is based on ISO 8601 and does not require using a DateTimeFormatter object explicitly as long as the Date-Time string conforms to the ISO 8601 standards.

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
public static void main(String[] args) {
String date = "2021-05-14T09:26:20";
LocalDateTime ldt = LocalDateTime.parse(date);
System.out.println(ldt);

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss", Locale.ENGLISH);
System.out.println(dtf.format(ldt));
}
}

Output:

2021-05-14T09:26:20
2023-02-14 09:02:20

ONLINE DEMO

Here, you can use y instead of u but I prefer u to y.

Learn more about the modern Date-Time API from Trail: Date Time.


* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Parse ISO8601 date string to date with UTC Timezone

If you are using Java 7 or earlier you can refer to this post.

If you are using Java 8 you could do:

    DateTimeFormatter timeFormatter = DateTimeFormatter.ISO_DATE_TIME;
TemporalAccessor accessor = timeFormatter.parse("2015-10-27T16:22:27.605-07:00");

Date date = Date.from(Instant.from(accessor));
System.out.println(date);

Update

As pointed out by @BasilBourque in the comment, TemporalAccessor is java framework level interface, and is not advisable to use in the application code and it is advisable to use concrete classes rather than the interfaces.

This interface is a framework-level interface that should not be widely used in application code. Instead, applications should create and pass around instances of concrete types, such as LocalDate. There are many reasons for this, part of which is that implementations of this interface may be in calendar systems other than ISO. See ChronoLocalDate for a fuller discussion of the issues.

There a few concrete classes available to use, like LocalDate, LocalDateTime, OffsetDateTime, ZonedDateTime and etc..

DateTimeFormatter timeFormatter = DateTimeFormatter.ISO_DATE_TIME;

OffsetDateTime offsetDateTime = OffsetDateTime.parse("2015-10-27T16:22:27.605-07:00", timeFormatter);

Date date = Date.from(Instant.from(offsetDateTime));
System.out.println(date);

How to parse ISO 8601 into date and time format using Moment js in Javascript?

With moment.js

var str = '2011-04-11T10:20:30Z';var date = moment(str);var dateComponent = date.utc().format('YYYY-MM-DD');var timeComponent = date.utc().format('HH:mm:ss');console.log(dateComponent);console.log(timeComponent);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.15.1/moment.min.js"></script>

Parsing ISO 8601 date format like 2015-06-27T13:16:37.363Z in Java

Try with this pattern (note the X at the end and the 'T' in the middle):

"yyyy-MM-dd'T'HH:mm:ss.SSSX"

From Java's SimpleDateFormat's documentation:

ISO 8601 Time zone:

...

For parsing, "Z" is parsed as the UTC time zone designator.

And, from the part where it describes the different characters:

X - Time zone - ISO 8601 time zone

EDIT

If using Android, then "X" is not supported.

You can use this pattern (note Z is a literal now):

"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"

But then you'll get the date on your current timezone and would need to convert it to UTC if needed.

how do I parse an iso 8601 date (with optional milliseconds) to a struct tm in C++?

You can use C's sscanf (http://www.cplusplus.com/reference/cstdio/sscanf/) to parse it:

const char *dateStr = "2014-11-12T19:12:14.505Z";
int y,M,d,h,m;
float s;
sscanf(dateStr, "%d-%d-%dT%d:%d:%fZ", &y, &M, &d, &h, &m, &s);

If you have std::string it can be called like this (http://www.cplusplus.com/reference/string/string/c_str/):

std::string dateStr = "2014-11-12T19:12:14.505Z";
sscanf(dateStr.c_str(), "%d-%d-%dT%d:%d:%fZ", &y, &M, &d, &h, &m, &s);

If it should handle different timezones you need to use sscanf return value - number of parsed arguments:

int tzh = 0, tzm = 0;
if (6 < sscanf(dateStr.c_str(), "%d-%d-%dT%d:%d:%f%d:%dZ", &y, &M, &d, &h, &m, &s, &tzh, &tzm)) {
if (tzh < 0) {
tzm = -tzm; // Fix the sign on minutes.
}
}

And then you can fill tm (http://www.cplusplus.com/reference/ctime/tm/) struct:

tm time = { 0 };
time.tm_year = y - 1900; // Year since 1900
time.tm_mon = M - 1; // 0-11
time.tm_mday = d; // 1-31
time.tm_hour = h; // 0-23
time.tm_min = m; // 0-59
time.tm_sec = (int)s; // 0-61 (0-60 in C++11)

It also can be done with std::get_time (http://en.cppreference.com/w/cpp/io/manip/get_time) since C++11 as @Barry mentioned in comment how do I parse an iso 8601 date (with optional milliseconds) to a struct tm in C++?

Parse date-only value in ISO 8601 format in java.time (YYYY-MM-DD)

LocalDate.parse

The java.time classes can parse ISO 8601 strings directly, with no need to specify a formatting pattern.

For a date-only value, without a time of day or time zone, use the LocalDate class.

LocalDate ld = LocalDate.parse("2016-03-21");


Related Topics



Leave a reply



Submit