4

I am trying to convert the date in milliseconds to the following ISO 8601 format:

enter image description here

But I am getting the following using SimpleDateFormat:

    /**
     * It converts the time from long to the ISO format
     * 
     * @param timestampMillis
     * @return isoDate
     */
    public String convertTimeMillisToISO8601(String timestampMillis)
    {
        long timeInLong= Long.parseLong(timestampMillis);
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
        df.setTimeZone(TimeZone.getTimeZone("UTC"));
        String isoDate = df.format(new java.util.Date(timeInLong));
        return isoDate;
    }

OUTPUT:

"ts":"2015-06-18T09:56:21+0000"

I know I can use substring to append the extra colon but Is there any better way to do so ?

sjain
  • 23,126
  • 28
  • 107
  • 185
  • 1
    Did you try `X` for the timezone? –  Apr 15 '15 at 08:17
  • based on this question and answer i think it's not supported in Java `SimpleDateFormat` http://stackoverflow.com/questions/2201925/converting-iso-8601-compliant-string-to-java-util-date – Yazan Apr 15 '15 at 08:24
  • @Tichodroma - yes, all it prints is for UTC it will print Z. – sjain Apr 15 '15 at 08:49
  • FYI, the terribly troublesome old date-time classes such as [`java.util.Date`](https://docs.oracle.com/javase/10/docs/api/java/util/Date.html), [`java.util.Calendar`](https://docs.oracle.com/javase/10/docs/api/java/util/Calendar.html), and `java.text.SimpleDateFormat` are now [legacy](https://en.wikipedia.org/wiki/Legacy_system), supplanted by the [*java.time*](https://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes built into Java 8 and later. See [*Tutorial* by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque Nov 12 '18 at 19:57

5 Answers5

8

For Java 7 and higher, you might use XXX (ISO 8601 time zone) in the date format String. According to the documentation, the result of X can be:

X    => -08
XX   => -0800
XXX  => -08:00

but for all of those, it might as well return Z!

For Java 6 and earlier, there is no X (J6 doc), and since the result of X may or may not do what you want, I strongly recommend you just insert that colon yourself.

Siguza
  • 21,155
  • 6
  • 52
  • 89
  • 2
    `X` will produce `Z` for UTC, not `+00:00`. – Bram Apr 15 '15 at 08:35
  • Yes, it says so in the documentation I liked to. It may generate the desired result, or `Z`. That's why I would really just insert the colon myself. – Siguza Apr 15 '15 at 08:47
1

You can always use a StringBuilder:

new StringBuilder(
      new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
      .format(date))
    .insert(22,':')
    .toString();
Community
  • 1
  • 1
OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
  • FYI, the terribly troublesome old date-time classes such as [`java.util.Date`](https://docs.oracle.com/javase/10/docs/api/java/util/Date.html), [`java.util.Calendar`](https://docs.oracle.com/javase/10/docs/api/java/util/Calendar.html), and `java.text.SimpleDateFormat` are now [legacy](https://en.wikipedia.org/wiki/Legacy_system), supplanted by the [*java.time*](https://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes built into Java 8 and later. See [*Tutorial* by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque Nov 12 '18 at 19:58
1

For Java 8 if you use one of the standard ISO_DATE_* format patterns then the output formatted String will be truncated when the offset is +00:00 (UTC typically just appends Z).

OffsetDateTime utcWithFractionOfSecond = ZonedDateTime.parse("2018-01-10T12:00:00.000000+00:00", DateTimeFormatter.ISO_OFFSET_DATE_TIME);

utcWithFractionOfSecond.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);     // 2018-01-10T12:00:00Z ... not what you want!

The only solution I have found is using the outputPattern (shown below) that uses lowercase `xxx' to ensure that a colon is included in the timezone offset.

I have included an example with factions-of-a-second for completeness (you can remove the SSSSSS in your case)

DateTimeFormatter inputPattern = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
DateTimeFormatter outputPattern = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSxxx");

OffsetDateTime utcWithFractionOfSecond = OffsetDateTime.parse("2018-01-10T12:00:00.000000+00:00", inputPattern);
OffsetDateTime utcNoFractionOfSecond = OffsetDateTime.parse("2018-01-10T12:00:00+00:00", inputPattern);
OffsetDateTime utcWithZ = OffsetDateTime.parse("2018-01-10T12:00:00Z", inputPattern);
OffsetDateTime utcPlus3Hours = OffsetDateTime.parse("2018-01-10T12:00:00.000000+03:00", inputPattern);|

utcWithFractionOfSecond.format(outputPattern );     // 2018-01-10T12:00:00.000000+00:00
utcNoFractionOfSecond.format(outputPattern);        // 2018-01-10T12:00:00.000000+00:00
utcWithZ.format(outputPattern);                     // 2018-01-10T12:00:00.000000+00:00
utcPlus3Hours.format(outputPattern);                // 2018-01-10T12:00:00.000000+03:00

In these examples I have used ISO_OFFSET_DATE_TIME only to create the input values for the test cases. In all cases it is the outputPattern yyyy-MM-dd'T'HH:mm:ss.SSSSSSxxx that controlling how to include a colon character in the timezone portion of your resulting formatted string.

Note that if your input data included the Zone ID like [Europe/London] then you would create your input data using ZonedDateTime instead of OffsetDateTime

Brad
  • 15,186
  • 11
  • 60
  • 74
  • The input string indicates only an offset, not a time zone. So `OffsetDateTime` class is appropriate here, not `ZonedDateTime`. – Basil Bourque Nov 12 '18 at 20:09
  • Agreed, I have updated the answer to be more specific about using `OffsetDateTime` in this particular example – Brad Nov 13 '18 at 10:32
0

Can you use Java 8?

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("YYYY-MM-dd'T'HH:mm:ssXXX");
System.out.println(formatter.format(ZonedDateTime.now()));

2015-04-15T17:24:19+09:00

Raniz
  • 10,882
  • 1
  • 32
  • 64
0

tl;dr

OffsetDateTime.parse( "2014-06-18T09:56:21+00:00" )

2014-06-18T09:56:21Z

Details

Some other answers are close, correct in using the modern java.time classes that supplanted the terrible old legacy classes (Date, Calendar, SimpleDateFormat). But they are either working too hard or chose the wrong class.

ISO 8601

Your format is in standard ISO 8601 format. The java.time classes use these standard formats by default when parsing/generating text representing their date-time values. So you need not specify any formatting pattern at all. Works by default.

OffsetDateTime

Your input indicates an offset-from-UTC of zero hours and zero minutes. So we should use the OffsetDateTime class.

String input = "2014-06-18T09:56:21+00:00";
OffsetDateTime odt = OffsetDateTime.parse( input );

Zulu time

We can generate a string in standard ISO 8601 format by merely calling toString. The Z on the end means UTC, and is pronounced “Zulu”.

odt.toString(): 2014-06-18T09:56:21Z

ZonedDateTime

If your input indicated a time zone, rather than merely an offset, we would have used ZonedDateTime class. An offset is simply a number of hours, minutes, and seconds – nothing more. A time zone is much more. A time zone is a history of past, present, and future changes to the offset used by the people of a particular region.


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.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154