Converting Iso 8601-Compliant String to Java.Util.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).

Converting a String to Java Date in ISO 8601 date-time format

tl;dr

OffsetDateTime.parse( "2001-05-03T00:00:00+00:00" )

Avoid legacy date-time classes

Never use SimpleDateFormat, Date, Calendar, etc. These terrible classes were supplanted years ago by the java.time classes.

ISO 8601

trying to convert a string into an ISO 8601 date-time format

String s1 = "2001-05-03T00:00:00+00:00"

Your Question is quite confused. Your input string is in standard ISO 8601 format. The T in the middle separates the year-month-day from the hour-minute-second, and the +00:00 at the end indicates an offset-from-UTC of zero hours and zero minutes, that is, UTC itself. All standard, all proper.

Perhaps you are conflating strings representing date-time values and date-time objects containing date-time values. A date-time object has no “format”; it has its own internally-defined representation of a date-time value. Only text has a format. A date-time class can parse a formatted string as input, and a date-time class can generate a formatted sting as output, but within the date-time there is no format at all.

OffsetDateTime

The java.time classes use the ISO 8601 formats by default when parsing/generating strings representing date-time values. So no need to specify a formatting pattern for such inputs.

OffsetDateTime odt = OffsetDateTime.parse( "2001-05-03T00:00:00+00:00" ) ;  

See this code run live at IdeOne.com.

odt.toString(): 2001-05-03T00:00Z

Z

There is a common abbreviation for an offset of zero: a simple Z letter, meaning UTC, and pronounced “Zulu”. Example: 2019-02-26T00:44:28Z

The Z is quite commonly used. But if for some reason you prefer the numeric +00:00, use DateTimeFormatter options.

COLON character

By the way, you mentioned the COLON character omitted from the offset: +0000. That is actually tolerated by the ISO 8601 standard. But I do not advise it. I have seen libraries and systems break on such inputs. Best to use full-length, hours and minutes, padding zeros, and the colon character: +00:00 rather than +0000, and -07:00 rather than -7.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

  • Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.

    • Java 9 adds some minor features and fixes.
  • Java SE 6 and Java SE 7

    • Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
  • Android

    • Later versions of Android bundle implementations of the java.time classes.
    • For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

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);

Java convert ISO 8601 string to Date ignoring offset

The first and most important part of the answer is: don’t convert to an old-fashioned Date. Either stick to Joda-Time or migrate to java.time, the modern Java date and time API, as already covered in the good answer by Arvind Kumar Avinash.

Since you are already using Joda-Time, I am showing you a Joda-Time solution. The trick for persuading the formatter into keeping the time and offset from the string parsed is withOffsetParsed().

    DateTimeFormatter isoFormat
= ISODateTimeFormat.dateTimeParser().withOffsetParsed();
String incomingString = "2020-09-09T09:58:00+0000";
DateTime dateTime = isoFormat.parseDateTime(incomingString);

However! If I have guessed correctly that you want to store date and time in UTC (a recommended practice), better than withOffsetParsed() is to specify UTC on the parser:

    DateTimeFormatter isoFormat
= ISODateTimeFormat.dateTimeParser().withZoneUTC();

Now you will also get the correct time if one day a string with a non-zero UTC offset comes in.

In any case we may now format your obtained DateTime into the strings you requested.

    String dateString = dateTime.toString(ISODateTimeFormat.date());
System.out.println(dateString);

String timeString = dateTime.toString(ISODateTimeFormat.hourMinuteSecond());
System.out.println(timeString);

String dateTimeString = dateTime.toString(ISODateTimeFormat.dateHourMinuteSecond());
System.out.println(dateTimeString);

Output:

2020-09-09
09:58:00
2020-09-09T09:58:00

What was wrong with using Date? First, the Date class is poorly designed and long outdated. Second, a Date was just a point in time, it didn’t have a concept of date and time of day (they tried building that into it in Java 1.0, but gave up and deprecated it in Java 1.1 in 1997). So a Date cannot hold the date and time of day in UTC for you.

What happened in your code was that you got a Date representing the correct point in time. Only when you printed that Date you were implicitly invoking its toString method. Date.toString() confusingly grabs the JVM’s time zone setting (in your case apparently North American Eastern Time) and uses it for rendering the string to be returned. So in your case the point in time was rendered as Wed Sep 09 05:58:00 EDT 2020.

In Java, Can I Convert A Date and Time To An ISO 8601 formatted String Without A Timezone?

Yes, you can use DateTimeFormatter ISO_LOCAL_DATE_TIME to format without the time zone:

String input = "12/20/2017 14:33:00";
DateTimeFormatter inputFormat = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss");
LocalDateTime date = LocalDateTime.parse(input, inputFormat);
String output = DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(date);
System.out.println(output);

Output:

2017-12-20T14:33:00

Convert Date from ISO 8601 Zulu string to java.time.Instant in Java 8

tl;dr

convert string date format into java.time.Instant

Skip the formatting pattern. Just parse.

Instant.parse( "2018-07-17T09:59:51.312Z" )

ISO 8601

Yes, you used incorrect formatting pattern as indicated in the first Answer.

But you needn't specify a formatting pattern at all. Your input string is in standard ISO 8601 format. The java.time classes use ISO 8601 formats by default when parsing/generating strings.

The Z on the end means UTC, and is pronounced “Zulu”.

Instant instant = Instant.parse( "2018-07-17T09:59:51.312Z" ) ;

About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

  • Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.

    • Java 9 adds some minor features and fixes.
  • Java SE 6 and Java SE 7

    • Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
  • Android

    • Later versions of Android bundle implementations of the java.time classes.
    • For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.



Related Topics



Leave a reply



Submit