65

I have a String of a date and time like this: 2011-04-15T20:08:18Z. I don't know much about date/time formats, but I think, and correct me if I'm wrong, that's its UTC format.

My question: what's the easiest way to parse this to a more normal format, in Java?

LuxuryMode
  • 33,401
  • 34
  • 117
  • 188
  • 4
    UTC is not a format, it's a timezone. It affects the value of the time, not the string representation. – Adrian Petrescu Jul 01 '11 at 03:09
  • 4
    The Z at the end (of an ISO-8601 date) means it's UTC... @Adrian is right that it's not a format. – artbristol Jul 01 '11 at 08:23
  • 9
    Actually that is the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format. It is a *very* "normal format", the most normal in that it is an officially defined international standard used by industry around the world. You'll find working with date-time to be much easier once you get used to it. How many countries around the world use the mm/dd/yyyy format with which you are familiar as an American? Let's [count them](https://en.wikipedia.org/wiki/Date_format_by_country): US, and, uh, oh… Palou & Micronesia. And Canada when dealing with the US. – Basil Bourque Dec 31 '13 at 04:55

9 Answers9

60

tl;dr

String output = 
    Instant.parse ( "2011-04-15T20:08:18Z" )
           .atZone ( ZoneId.of ( "America/Montreal" ) )
           .format ( 
               DateTimeFormatter.ofLocalizedDateTime ( FormatStyle.FULL )
                                .withLocale ( Locale.CANADA_FRENCH ) 
           )
;

vendredi 15 avril 2011 16 h 08 EDT

Details

The answer by Josh Pinter is correct, but could be even simpler.

java.time

In Java 8 and later, the bundled java.util.Date/Calendar classes are supplanted by the java.time framework defined by JSR 310. Those classes are inspired by Joda-Time but are entirely re-architected.

The java.time framework is the official successor to Joda-Time. The creators of Joda-Time have advised we should migrate to java.time as soon as is convenient. Joda-Time continues to be updated and tweaked, but further innovation will be done only in java.time and its extensions in the ThreeTen-Extra project.

The bulk of java.time functionality has been back-ported to Java 6 & 7 in the ThreeTen-Backport project, and further adapted to Android in ThreeTenABP project.

The equivalent for the Joda-Time code above is quite similar. Concepts are similar. And like Joda-Time, the java.time classes by default use ISO 8601 formats when parsing/generating textual representations of date-time values.

An Instant is a moment on the timeline in UTC with a resolution of nanoseconds (versus milliseconds used by Joda-Time & java.util.Date).

Instant instant = Instant.parse( "2011-04-15T20:08:18Z" );

Apply a time zone (ZoneId) to get a ZonedDateTime.

ZoneId zoneId = ZoneId.of( "Asia/Kolkata" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

Adjust into yet another time zone.

ZoneId zoneId_NewYork = ZoneId.of( "America/New_York" );
ZonedDateTime zdt_NewYork = zdt.withZoneSameInstant( zoneId_NewYork );

To create strings in other formats beyond those of the toString methods, use the java.time.format classes. You can specify your own formatting pattern or let java.time localize automatically. Specify a Locale for (a) the human language used in translation of name of month/day-of-week, and (b) cultural norms for period-versus-comma, order of the parts, and such.

DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL );
formatter = formatter.withLocale( Locale.US );
String output = zdt_NewYork.format( formatter );

Friday, April 15, 2011 4:08:18 PM EDT


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?

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.


Joda-Time

UPDATE: The Joda-Time project is now in maintenance mode, with the team advising migration to the java.time classes. This section left intact for history.

Pass String To Constructor

Joda-Time can take that string directly. Simply pass to a constructor on the DateTime class.

Joda-Time understands the standard ISO 8601 format of date-times, and uses that format as its default.

Example Code

Here is example code in Joda-Time 2.3 running in Java 7 on a Mac.

I show how to pass the string to a DateTime constructor, in two ways: With and without a time zone. Specifying a time zone solves many problems people encounter in doing date-time work. If left unspecified, you get the default time zone which can bring surprises when placed into production.

I also show how specify no time zone offset (UTC/GMT) using the built-in constant DateTimeZone.UTC. That's what the Z on the end, short for Zulu time, means: No time zone offset (00:00).

// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
// import org.joda.time.*;
// import org.joda.time.format.*;

// Default time zone.
DateTime dateTime = new DateTime( "2011-04-15T20:08:18Z" );

// Specified time zone.
DateTime dateTimeInKolkata = new DateTime( "2011-04-15T20:08:18Z", DateTimeZone.forID( "Asia/Kolkata" ) );
DateTime dateTimeInNewYork = new DateTime( "2011-04-15T20:08:18Z", DateTimeZone.forID( "America/New_York" ) );

// In UTC/GMT (no time zone offset).
DateTime dateTimeUtc = dateTimeInKolkata.toDateTime( DateTimeZone.UTC );

// Output in localized format.
DateTimeFormatter formatter = DateTimeFormat.shortDateTime().withLocale( Locale.US );
String output_US = formatter.print( dateTimeInNewYork );

Dump to console…

System.out.println("dateTime: " + dateTime );
System.out.println("dateTimeInKolkata: " + dateTimeInKolkata );
System.out.println("dateTimeInNewYork: " + dateTimeInNewYork );
System.out.println("dateTimeUtc: " + dateTimeUtc );
System.out.println("dateTime in US format: " + output_US );

When run…

dateTime: 2011-04-15T13:08:18.000-07:00
dateTimeInKolkata: 2011-04-16T01:38:18.000+05:30
dateTimeInNewYork: 2011-04-15T16:08:18.000-04:00
dateTimeUtc: 2011-04-15T20:08:18.000Z
dateTime in US format: 4/15/11 4:08 PM
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
44

Use JodaTime

I kept getting parsing errors using the other solutions with the Z at the end of the format.

Instead, I opted to leverage JodaTime's excellent parsing functionality and was able to do the following very easily:

String timestamp = "2011-04-15T20:08:18Z";

DateTime dateTime = ISODateTimeFormat.dateTimeParser().parseDateTime(timestamp);

This correctly recognizes the UTC timezone and allows you to then use JodaTime's extensive manipulation methods to get what you want out of it.

Hope this helps others.

Joshua Pinter
  • 45,245
  • 23
  • 243
  • 245
  • I thought the `Z` was needed (and I tested this at the time of posting). I removed the `Z` from my answer for now and giving you +1 for this since Joda time is a good answer. I didn't use Joda because he asked for the "easiest" which usually means Java-native. – Andrew White Dec 10 '13 at 03:31
  • 2
    @AndrewWhite First off, I agree with you about going Java-native but once I started digging into it, the benefits of JodaTime seemed to outweigh going native. The `Z` allows for timezones, which are incredibly important, however, it doesn't seem to "understand" the "Z" (standing for UTC timezone) in the ISO-8601 timestamp. JodaTime just does "the right thing". – Joshua Pinter Dec 10 '13 at 05:39
  • 1
    @JoshPinter No need for parser. The constructor for `DateTime` will parse an ISO 8601 string. `DateTime dateTime = new DateTime( "2011-04-15T20:08:18Z" );` See my answer for more example code. – Basil Bourque Dec 31 '13 at 17:17
  • @BasilBourque Thanks for looking into that Basil! I'll leave this here for posterity and in case there is a situation that requires the parser. – Joshua Pinter Jun 07 '15 at 15:40
  • Thanks! It works like magic!=) Used it this way: DateTime dateTime= ISODateTimeFormat.dateTimeParser().parseDateTime(dateString); dateTextView.setText(dateTime.toString("dd.MM.yyyy HH:mm")); – Svetlana Rozhkova Jan 29 '19 at 11:40
  • FYI, the [*Joda-Time*](http://www.joda.org/joda-time/) project is now in [maintenance mode](https://en.wikipedia.org/wiki/Maintenance_mode), advising migration to the [*java.time*](http://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes. See [Tutorial by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque Jul 27 '19 at 21:46
  • @BasilBourque Correct, with later versions of Java 8+: _"Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project."_ – Joshua Pinter Jul 29 '19 at 01:09
10

Already has lot of answer but just wanted to update with java 8 in case any one faced issues while parsing string date.

Generally we face two problems with dates

  1. Parsing String to Date
  2. Display Date in desired string format

DateTimeFormatter class in Java 8 can be used for both of these purpose. Below methods try to provide solution to these issues.

Method 1: Convert your UTC string to Instant. Using Instant you can create Date for any time-zone by providing time-zone string and use DateTimeFormatter to format date for display as you wish.

String dateString = "2016-07-13T18:08:50.118Z";
String tz = "America/Mexico_City";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MMM d yyyy hh:mm a");
ZoneId zoneId = ZoneId.of(tz);

Instant instant = Instant.parse(dateString);

ZonedDateTime dateTimeInTz =ZonedDateTime.ofInstant(instant, zoneId);

System.out.println(dateTimeInTz.format(dtf));

Method 2:

Use DateTimeFormatter built in constants e.g ISO_INSTANT to parse string to LocalDate. ISO_INSTANT can parse dates of pattern

yyyy-MM-dd'T'HH:mm:ssX e.g '2011-12-03T10:15:30Z'

LocalDate parsedDate
  = LocalDate.parse(dateString, DateTimeFormatter.ISO_INSTANT);

DateTimeFormatter displayFormatter = DateTimeFormatter.ofPattern("yyyy MM dd");
System.out.println(parsedDate.format(displayFormatter));

Method 3:

If your date string has much precision of time e.g it captures fraction of seconds as well as in this case 2016-07-13T18:08:50.118Z then method 1 will work but method 2 will not work. If you try to parse it will throw DateTimeException Since ISO_INSTANT formatter will not be able to parse fraction of seconds as you can see from its pattern. In this case you will have to create a custom DateTimeFormatter by providing date pattern as below.

LocalDate localDate 
= LocalDate.parse(date, DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX"));

Taken from a blog link written by me.

WitVault
  • 23,445
  • 19
  • 103
  • 133
9

The Java 7 version of SimpleDateFormat supports ISO-8601 time zones using the uppercase letter X.

String string = "2011-04-15T20:08:18Z";
DateFormat iso8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
Date date = iso8601.parse(string);

If you're stuck with Java 6 or earlier, the answer recommending JodaTime is a safe bet.

jstricker
  • 2,132
  • 1
  • 30
  • 44
  • There is a value in answers for the post-Jodatime world after Java has atoned for some of its sins. – user1445967 Jan 18 '16 at 09:32
  • FYI, the [*Joda-Time*](http://www.joda.org/joda-time/) project is now in [maintenance mode](https://en.wikipedia.org/wiki/Maintenance_mode), advising migration to the [*java.time*](http://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes. See [Tutorial by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque Jul 27 '19 at 21:47
3

You have to give the following format:

SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
Date parse = simpleDateFormat.parse( "2011-04-15T20:08:18Z" );
khmarbaise
  • 92,914
  • 28
  • 189
  • 235
  • 4
    Using a format string of "yyyy-MM-dd'T'HH:mm:ssZ" with the input provided by the asker of the question fails with a java.text.ParseException: Unparseable date: "2011-04-15T20:08:18Z" – jstricker Dec 31 '13 at 04:08
1

I had a parse error in Andrew White solution. Adding the single quote around the Z solved the issue

DateFormat m_ISO8601Local = new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ss'Z'");
Riccardo Casatta
  • 1,180
  • 12
  • 18
1

the pattern in @khmarbaise answer worked for me, here's the utility method I extracted (note that the Z is omitted from the pattern string):

/**
 * Converts an ISO-8601 formatted UTC timestamp.
 *
 * @return The parsed {@link Date}, or null.
 */
@Nullable
public static Date fromIsoUtcString(String isoUtcString) {
    DateFormat isoUtcFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault());
    isoUtcFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
    try {
        return isoUtcFormat.parse(isoUtcString);
    } catch (ParseException e) {
        e.printStackTrace();
        return null;
    }
}
HelloImKevo
  • 547
  • 6
  • 11
0

For all the older versions of JDK (6 down) it may be useful.

Getting rid of trailing 'Z' and replacing it literally with 'UTC' timezone display name - then parsing the whole string using proper simple date formatter.

String timeZuluVal = "2011-04-15T20:08:18Z";
timeZuluVal = timeZuluVal.substring( 0, timeZuluVal.length() - 2 ); // strip 'Z';
timeZuluVal += " " + TimeZone.getTimeZone( "UTC" ).getDisplayName();
DateFormat simpleDateFormat = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss zzzz" );
Date dateVal = simpleDateFormat.parse( timeZuluVal );
Mc Bton
  • 111
  • 1
  • 4
0

Joda Time

public static final String SERVER_TIME_FORMAT = "yyyy-MM-dd  HH:mm:ss";

public static DateTime getDateTimeFromUTC(String time) {
    try {
        DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(SERVER_TIME_FORMAT).withZoneUTC();

        Calendar localTime = Calendar.getInstance();
        DateTimeZone currentTimeZone = DateTimeZone.forTimeZone(localTime.getTimeZone());
        return dateTimeFormatter.parseDateTime(time).toDateTime().withZone(currentTimeZone);
    } catch (Exception e) {
        return DateTime.now();
    }
}
nAkhmedov
  • 3,522
  • 4
  • 37
  • 72
  • FYI, the [*Joda-Time*](http://www.joda.org/joda-time/) project is now in [maintenance mode](https://en.wikipedia.org/wiki/Maintenance_mode), advising migration to the [*java.time*](http://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes. See [Tutorial by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque Jul 27 '19 at 21:44