0

I have to call a web service which is expecting a Date field but they want it in the following format YYYY-MM-DDThh:mm:ss.sssZ. How can I do this?

I tried the following

OffsetDateTime transactionTime = OffsetDateTime.now(ZoneOffset.UTC);

Date.from(transactionTime.toInstant());

but this didn't work. transactionTime is 2021-06-01T15:11:09.942843400Z, but Date.from converts it to Tue Jun 01 11:11:09 EDT 2021.

BTW, I'm using Java 11

Steve B
  • 557
  • 2
  • 7
  • 23
  • 2021-06-01T15:11:09.942843400Z (Zulu, Greenwich time) **is** 2021-06-01T11:11:09.942843400 EDT. It is the same instant at different timezones. – SJuan76 Jun 01 '21 at 15:19
  • "Date.from converts it to Tue Jun 01 11:11:09 EDT 2021" - no, `Date.from` converts it to a `Date` object, which isn't a string. If you need to format a `Date` object in a particular way, there are various approaches to that (e.g. `SimpleDateFormat`). – Jon Skeet Jun 01 '21 at 15:35
  • 1
    `java.util.Date` does not have the concept of timezone. The string, `Tue Jun 01 11:11:09 EDT 2021` represents the date-time in your timezone. Since `Date` does not have timezone information, it applies the JVM's timezone to return the value of `Date#toString`. – Arvind Kumar Avinash Jun 01 '21 at 17:15
  • A `Date` also cannot have a format. – Ole V.V. Jun 01 '21 at 18:38
  • What makes you think that you want a `Date`? That class is poorly designed and long outdated, and web services don’t consume `Date` objects directly, so you should not want one. Better to stick to your `OffsetDateTime`. – Ole V.V. Jun 01 '21 at 18:40

2 Answers2

4
Instant.now().toString()

See that code run live at IdeOne.com.

2021-06-01T15:21:16.783779Z

That format is defined in the ISO 8601 standard. The Z on end means an offset-from-UTC of zero hours-minutes-seconds. Pronounced “Zulu”.

Use java.time.Instant to represent a moment as seen in UTC.

Going the other direction, from text to object.

Instant.parse( "2021-06-01T15:21:16.783779Z" ) 

If you want only milliseconds, you can lop off any microseconds and nanoseconds by truncating.

Instant.now().truncatedTo( ChronoUnit.MILLIS ) ;

Never use the legacy Date class. Use only the java.time classes.

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

Use DateTimeFormatter to format the Date-Time object

import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH);
        OffsetDateTime transactionTime = OffsetDateTime.now(ZoneOffset.UTC);
        String formatted = transactionTime.format(dtf);
        System.out.println(formatted);
    }
}

Output:

2021-06-01T15:49:45.198Z

Learn more about the modern Date-Time API from Trail: Date Time.

What if I want to use java.util.Date?

For any reason, if you need to convert this object of OffsetDateTime to an object of java.util.Date, you can do so as follows:

Date date = Date.from(transactionTime.toInstant());

Note that a java.util.Date object is not a real Date-Time object like the modern Date-Time types; rather, it represents the number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT (or UTC). Since Date does not have timezone information, it applies the JVM's timezone to return the value of Date#toString in the format, EEE MMM dd HH:mm:ss z yyyy calculated from this milliseconds value. If you need to print the Date-Time in a different format and timezone, you will need to use a SimpleDateFormat with the desired format and the timezone set to the applicable one e.g.

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
String strDate = sdf.format(date);
System.out.println(strDate);

Output:

2021-06-01T15:49:45.198Z

Some other important notes:

  1. 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*.
  2. Most of the symbols that you have used in YYYY-MM-DDThh:mm:ss.sssZ are wrong. Check the description of the symbols from the documentation pages of DateTimeFormatter and SimpleDateFormat.

* 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.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110