1

I have a system using Java 7 and I need to generate a date equivalente to Instant.now (Java 8).

For example, Instant.now().toString() generate a date like that: "2018-12-19T12:32:46.816Z"

Using java.util.Date I have this date: "2018-12-19T10:38:13.892"

    Date date = new Date(System.currentTimeMillis());
    SimpleDateFormat sdf;
    sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
    String text = sdf.format(date);
    System.out.println(text);

I don't know if I can simply concatenate a "Z" at the end of this date.

Without "Z" another system that parse this date using Instant.parse throws the error:

java.time.format.DateTimeParseException: Text '2018-12-19T10:38:13.892' could not be parsed at index 23 at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1988) at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1890) at java.base/java.time.Instant.parse(Instant.java:395)

Computered
  • 440
  • 1
  • 7
  • 21
  • 4
    Did you consider [ThreeTen Backport](https://www.threeten.org/threetenbp/)? java.time, the modern Java date and time API, has been backported to Java 6 and 7. – Ole V.V. Dec 19 '18 at 13:06
  • 1
    `java.util.Date` itself does not have a Timezone (thats where the `Z` stands for), so you have to add it. For example in the format: `sdf.setTimeZone(TimeZone.getTimeZone("UTC"));` – Glains Dec 19 '18 at 13:07
  • 1
    @Glains Actually the `Z` stands for UTC, meaning an offset-from-UTC of zero hours-minutes-seconds, **not a time zone**. A time zone is a history of past, present, and future changes to the offset used by the people of a particular region. A `java.util.Date`, like an `java.time.Instant`, represents a moment in UTC as it is simply a count since the epoch reference of the first moment of 1970 in UTC. `Date` is a count of milliseconds since 1970-01-01T00:00:00Z, `Instant` is a count of nanoseconds, **both represent a moment in UTC** by definition. – Basil Bourque Dec 19 '18 at 17:01

2 Answers2

4

Z means UTC time zone, you can set the time zone to UTC and append Z mannually:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
xingbin
  • 27,410
  • 9
  • 53
  • 103
  • This indeed might be the correct answer - when the date already is UTC. As might be the case. – Joop Eggen Dec 19 '18 at 13:23
  • 1
    @JoopEggen An old-fashioned `Date` isn’t in any particular time zone, it’s just a point in time. – Ole V.V. Dec 19 '18 at 13:28
  • @OleV.V. yes, my remark was intended to point that `Z` is the result of the UTC time zone in java >8. – Joop Eggen Dec 19 '18 at 13:54
  • 1
    Instead of a hardcoded `'Z'`, you may specify `X`, to insert the actual timezone, which will result in `Z` when `setTimeZone(TimeZone.getTimeZone("UTC"))` has been correctly specified. – Holger Dec 19 '18 at 17:13
  • **This is a *terrible* Answer,** with that format using quote marks around the `Z` meaning to ignore the `Z` which means to ignore the fact that the input is in UTC. Suggesting that we (1) Append a `Z`, (2) then ignore the `Z` by using `'Z'` in the formatting pattern, and (3) Setting UTC on the formatter to make up for having just ignored the `Z`/UTC, is just wacky and senseless. Five upvotes for this silliness?? And only two upvotes for the [correct Answer by Ole V.V.](https://stackoverflow.com/a/53852460/642706)?? – Basil Bourque Dec 19 '18 at 20:18
  • 1
    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 Dec 19 '18 at 20:21
4

ThreeTen Backport

java.time, the modern Java date and time API, has been backported. So just do as you would in Java 8:

    String text = Instant.now().toString();

Running just now I got:

2018-12-19T13:37:37.186Z

  • In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
  • In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310; see the links at the bottom).
  • On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.

The outdated SimpleDateFormat

If you don’t want to rely on an external dependency just until you move to Java 8 or higher, the (most) correct solution is this combination of pieces from the two other answers (one of them now deleted):

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXX");
    sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
    String text = sdf.format(System.currentTimeMillis());

2018-12-19T13:37:37.285Z

It doesn’t always give the exact same string as Instant.toString, but it will give a string that Instant can parse in the other system. While Instant.toString() only prints as many decimals as necessary, the above SimpleDateFormat will print three decimals also when some of them are 0.

When the time zone of the formatter is UTC, format pattern letter (uppercase) X will print Z as “time zone” (really just an offset).

Links

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161