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

What is the most elegant way to get ISO 8601 formatted presentation of current moment, UTC? It should look like: 2010-10-12T08:50Z.

Example:

String iso8601 = DateFormat.getDateTimeInstance(DateFormat.ISO_8601).format(date);

This question is related to java

The answer is


Java 8 Native

java.time makes it simple since Java 8. And thread safe.

ZonedDateTime.now( ZoneOffset.UTC ).format( DateTimeFormatter.ISO_INSTANT )

Result: 2015-04-14T11:07:36.639Z

You may be tempted to use lighter Temporal such as Instant or LocalDateTime, but they lacks formatter support or time zone data. Only ZonedDateTime works out of the box.

By tuning or chaining the options / operations of ZonedDateTime and DateTimeFormatter, you can easily control the timezone and precision, to a certain degree:

ZonedDateTime.now( ZoneId.of( "Europe/Paris" ) )
             .truncatedTo( ChronoUnit.MINUTES )
             .format( DateTimeFormatter.ISO_DATE_TIME )

Result: 2015-04-14T11:07:00+01:00[Europe/Paris]

Refined requirements, such as removing the seconds part, must still be served by custom formats or custom post process.

.format( DateTimeFormatter.ISO_LOCAL_DATE_TIME ) // 2015-04-14T11:07:00
.format( DateTimeFormatter.ISO_LOCAL_DATE ) // 2015-04-14
.format( DateTimeFormatter.ISO_LOCAL_TIME ) // 11:07:00
.format( DateTimeFormatter.ofPattern( "yyyy-MM-dd HH:mm" ) ) // 2015-04-14 11:07

For Java 6 & 7, you may consider back-ports of java.time such as ThreeTen-Backport, which also has an Android port. Both are lighter than Joda, and has learned from Joda's experience - esp. considering that java.time is designed by Joda's author.


ISO 8601 may contains seconds see http://en.wikipedia.org/wiki/ISO_8601#Times

so the code should be

DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");

For systems where the default Time Zone is not UTC:

TimeZone tz = TimeZone.getTimeZone("UTC");
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'");
df.setTimeZone(tz);
String nowAsISO = df.format(new Date());

The SimpleDateFormat instance may be declared as a global constant if needed frequently, but beware that this class is not thread-safe. It must be synchronized if accessed concurrently by multiple threads.

EDIT: I would prefer Joda Time if doing many different Times/Date manipulations...
EDIT2: corrected: setTimeZone does not accept a String (corrected by Paul)


Joda-Time

Update: The Joda-Time project is now in maintenance mode, with the team advising migration to the java.time classes. For Java 6 & 7, see the ThreeTen-Backport project, further adapted for Android in the ThreeTenABP project.

Using the Joda-Time library…

String output = new DateTime( DateTimeZone.UTC ).toString() ;

This is thread-safe. Joda-Time creates new immutable objects rather than changing existing objects.

If you truly intended to ask for a format without seconds, resolving to minutes, then use one of the many other built-in formatters in Joda-Time.

DateTime now = new DateTime( DateTimeZone.UTC ) ;
String output = ISODateTimeFormat.dateHourMinute.print( now ) ;

java.time

For Java 8 and later, Joda-Time continues to work. But the built-in java.time framework supplants Joda-Time. So migrate your code from Joda-Time to java.time as soon as is convenient.

See my other Answer for a modern solution.


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.


If you care about performance, I created a library which outperforms standard Java parser and formatter in manipulating with ISO8601-formatted dates. DatetimeProcessor implementations are thread-safe and can be cached in a concurrent map or static fields.

<dependency>
  <groupId>com.axibase</groupId>
  <artifactId>date-processor</artifactId>
  <version>1.0.3</version>
</dependency>
import com.axibase.date.DatetimeProcessor;
import com.axibase.date.PatternResolver;
import org.junit.Before;
import org.junit.Test;

import java.time.Clock;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;

public class DateFormatTest {
    private Clock clock;

    @Before
    public void prepare() {
        clock = Clock.fixed(Instant.ofEpochMilli(1571285405300L), ZoneId.of("Europe/Berlin"));
    }

    @Test
    public void testIsoMillis(){
        final DatetimeProcessor formatter = PatternResolver.createNewFormatter("iso");
        assertThat(formatter.print(clock.millis(), ZoneOffset.UTC), is("2019-10-17T04:10:05.300Z"));
    }

    @Test
    public void testIsoMillisLocalZone(){
        final DatetimeProcessor formatter = PatternResolver.createNewFormatter("iso");
        assertThat(formatter.print(clock.millis(), clock.getZone()), is("2019-10-17T06:10:05.300+02:00"));
    }

    @Test
    public void testIsoMinutes(){
        final DatetimeProcessor formatter = PatternResolver.createNewFormatter("yyyy-MM-ddTHH:mmXXX");
        assertThat(formatter.print(clock.millis(), ZoneOffset.UTC), is("2019-10-17T04:10Z"));
    }
}


Still, joda-time does only support the extended format: "2015-12-09T00:22:42.930Z" not the basic: "20151209T002242.930Z" ...we might be better off testing a list of formats with java SimpleDateFormat.


tl;dr

Some of the other Answers are correct in recommending java.time classes but go about using unnecessary lengths for your specific needs.

Instant.now()                               // Capture the current moment in UTC with a resolution as fines nanoseconds but usually in microseconds or milliseconds.
       .truncatedTo( ChronoUnit.MINUTES )   // Lop off any seconds or fractional second, to get a value in whole minutes.
       .toString()                          // Generate a String in standard ISO 8601 format where a `T` separates the year-month-day from the hour-minute-second, and the `Z` on the end for “Zulu” means UTC.

2018-01-23T12:34Z

Instant::toString

The jav.time.Instant class represents a moment in UTC, always in UTC.

Instant instant = Instant.now() ;

instant.toString(): 2018-01-23T12:34:56.123456Z

The Z on the end of your example string 2010-10-12T08:50Z is pronounced “Zulu” and means UTC.

Your desired format happens to comply with the ISO 8601 standard. The java.time classes use these standard formats by default when parsing/generating strings. So no need to specify a formatting pattern. Just call Instant::toString as seen above.

If you specifically want whole minutes without second or fractional second, then truncate. Specify a unit of time via ChronoUnit class.

Instant instant = Instant.now().truncatedTo( ChronoUnit.MINUTES ) ;
String output = instant.toString();  // Generate a `String` object in standard ISO 8601 format.

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.


If you don't want to include Jodatime (as nice as it is)

javax.xml.bind.DatatypeConverter.printDateTime(
    Calendar.getInstance(TimeZone.getTimeZone("UTC"))
);

which returns a string of:

2012-07-10T16:02:48.440Z

which is slightly different to the original request but is still ISO-8601.


You could use Java's SimpleDateFormat with the following pattern yyyy-MM-dd'T'HH:mm:ssXXX for ISO 8601.

Sample Code: (lists out for all the available time zones)

for (String timeZone : TimeZone.getAvailableIDs())
{
    DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
    dateFormat.setTimeZone(TimeZone.getTimeZone(timeZone));
    String formatted = dateFormat.format(new Date());
    System.out.print(formatted);

    if (formatted.endsWith("Z"))
    {
        // These time zone's have offset of '0' from GMT.
        System.out.print("\t(" + timeZone + ")");
    }

    System.out.println();
}

You could use:

TimeZone.getDefault()

for the default vm timezone. More here

You might notice the date time for few time zones that end with 'Z'. These time zones have offset of '0' from GMT.

More info can be found here.


use JodaTime

The ISO 8601 calendar system is the default implementation within Joda-Time

Here is the doc for JodaTime Formatter

Edit:

If you don't want to add or if you don't see value of adding above library you could just use in built SimpleDateFormat class to format the Date to required ISO format

as suggested by @Joachim Sauer

DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mmZ");
String nowAsString = df.format(new Date());

For Java version 7

You can follow Oracle documentation: http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html

X - is used for ISO 8601 time zone

TimeZone tz = TimeZone.getTimeZone("UTC");
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
df.setTimeZone(tz);
String nowAsISO = df.format(new Date());

System.out.println(nowAsISO);

DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
//nowAsISO = "2013-05-31T00:00:00Z";
Date finalResult = df1.parse(nowAsISO);

System.out.println(finalResult);

Here's a whole class optimized so that invoking "now()" doesn't do anything more that it has to do.

public class Iso8601Util
{
    private static TimeZone tz = TimeZone.getTimeZone("UTC");
    private static DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'");

    static
    {
        df.setTimeZone(tz);
    }

    public static String now()
    {
        return df.format(new Date());
    }
}

I did it in Android using Calendar and SimpleDateFormat. The following method returns a Calendar with the "GMT" TimeZone (This is the universal time zone). Then you can use the Calendar class to set the hour between differents time zones, using the method setTimeZone() of the Calendar class.

private static final String GMT = "GMT";
private static final String DATE_FORMAT_ISO = "yyyyMMdd'T'HHmmss";

public static Calendar isoToCalendar(final String inputDate) {
    Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone(GMT));
    try {
        SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT_ISO, Locale.US);
        dateFormat.setTimeZone(TimeZone.getTimeZone(GMT));
        Date date = dateFormat.parse(inputDate);
        calendar.setTime(date);
    } catch (ParseException e) {
        Log.e("TAG",e.getMessage());
    }
    return calendar;
}

REMEMBER: The Date class doesn't know about the TimeZone existence. By this reason, if you debug one date,you always see the date for your current timezone.


private static String getCurrentDateIso()
{
    // Returns the current date with the same format as Javascript's new Date().toJSON(), ISO 8601
    DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
    dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
    return dateFormat.format(new Date());
}

Java 8:

thisMoment = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mmX")
                              .withZone(ZoneOffset.UTC)
                              .format(Instant.now());

Pre Java 8:

thisMoment = String.format("%tFT%<tRZ",
                           Calendar.getInstance(TimeZone.getTimeZone("Z")));

From the docs:

'R'    Time formatted for the 24-hour clock as "%tH:%tM"
'F'    ISO 8601 complete date formatted as "%tY-%tm-%td".


Try This,

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSZ");
        String date=sdf.format (new Date() );

Its For ISO 8601 format


They should have added some kind of simple way to go from Date to Instant and also a method called toISO8601, which is what a lot of people are looking for. As a complement to other answers, from a java.util.Date to ISO 8601 format:

Instant.ofEpochMilli(date.getTime()).toString();

It is not really visible when using auto-completion but: java.time.Instant.toString():

A string representation of this instant using ISO-8601


As of Java 8 you can simply do:

Instant.now().toString();

From the java.time.Instant docs:

now

public static Instant now()

Obtains the current instant from the system clock.

This will query the system UTC clock to obtain the current instant.

 

toString

public String toString()

A string representation of this instant using ISO-8601 representation.

The format used is the same as DateTimeFormatter.ISO_INSTANT.


I do believe the easiest way is to first go to instant and then to string like:

String d = new Date().toInstant().toString();

Which will result in:

2017-09-08T12:56:45.331Z


DateTimeFormatter.ISO_DATE_TIME
        .withZone(ZoneOffset.UTC)
        .format(yourDateObject.toInstant())

DateFormatUtils from Apache commons-lang3 have useful constants, for example: DateFormatUtils.ISO_DATETIME_FORMAT