How do I convert a Java 8 instant to UTC?

Question I was asked today, which I thought was simple: “How do I convert a java.time.Instant to UTC?”

I knew from that javadoc that a Java 8 Instant represents “An instantaneous point on the time-line.” An instantaneous point on a time-line happens at the same time everywhere on earth. It’s the time the asteroid hits. This time is always stored in UTC. You don’t need to do anything to convert it to UTC. However, when I tried to demonstrate this by formatting the value, it got interesting.

An Instant “doesn’t have a time zone,” so you have three formatting options:

  • format it in UTC
  • add a time zone to a DateTimeFormatter, or
  • construct a ZonedDateTime and format that.

Example:

public void testInstant() {
  final Instant now = Instant.now();
  System.out.println("Instant.toString():  " + now.toString());
  
  final DateTimeFormatter formatterWithZone = 
      DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm zzz")
        .withZone(ZoneId.systemDefault());
  System.out.println("DateTimeFormatter with a zone:  " + 
      formatterWithZone.format(now));
  
  final DateTimeFormatter formatterWithoutZone = 
      DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm zzz");
  final ZonedDateTime nowWithTimeZone = 
    ZonedDateTime.ofInstant(now, ZoneId.systemDefault());
  System.out.println("DateTimeFormatter without a zone:  " + 
      formatterWithoutZone.format(nowWithTimeZone));
  
  // throws an UnsupportedTemporalTypeException
  System.out.println(formatterWithoutZone.format(now));  
}

This method will throw an UnsupportedTemporalTypeException because the last line cannot be executed. The output is:

Instant.toString():  2015-09-01T01:27:30.219Z
DateTimeFormatter with a zone:  2015-08-31 20:27 CDT
DateTimeFormatter without a zone:  2015-08-31 20:27 CDT

Conclusion

You don’t need to “convert an Instant to UTC” because it is already in UTC. However, if you want to format it in another time zone, you need to provide a time zone for that format, either by construction a ZonedDateTime object or by adding time zone to a DateTimeFormatter.