1

I am trying to understand why the following java.time.Clock is returning UTC time instead of the local time zone (EST).

C:\Users\Felipe>scala
Welcome to Scala 2.12.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_65).
Type in expressions for evaluation. Or try :help.

scala> import java.time._
import java.time._

scala> ZoneId.systemDefault()
res0: java.time.ZoneId = America/New_York

scala> val clock = Clock.systemDefaultZone()
clock: java.time.Clock = SystemClock[America/New_York]

scala> clock.instant
res1: java.time.Instant = 2017-07-06T16:20:04.990Z

The current time when I ran the above was 12:20pm (i.e. 4h before the UTC time shown)

2 Answers2

3

The Instant.toString() method uses DateTimeFormatter.ISO_INSTANT formatter, which in turn parses and formats the Instant in UTC.

As 2017-07-06T16:20:04.990Z is the same as 2017-07-06T12:20:04.990 in New York, the results you're getting are correct.

If you want the Instant converted to your timezone, you can do:

clock.instant().atZone(ZoneId.systemDefault())

Or you can be more specific (as the system's default timezone can be changed, even in runtime):

clock.instant().atZone(ZoneId.of("America/New_York"))

This will result in a ZonedDateTime:

2017-07-06T12:48:22.890-04:00[America/New_York]


You can also convert this to a LocalDateTime if you want:

clock.instant().atZone(ZoneId.of("America/New_York")).toLocalDateTime()

The result will be a LocalDateTime:

2017-07-06T12:49:47.688


PS: as @Andreas reminded me in the comments (and I forgot to mention), the Instant class represents just a point in time (number of nanoseconds since 1970-01-01T00:00Z) and has no timezone information, so any representation of it (including the toString() method) will be in UTC. To get the local date or time that corresponds to an Instant, you must provide a timezone, as shown above.

  • 2
    It isn't just the `toString()` method, but more the fact that `Instant` doesn't have a time zone: *The `Instant` class is designed to only represent a point in time and internally stores a value in nanoseconds from a fixed epoch of `1970-01-01Z`. As such, an Instant cannot be formatted as a date or time without providing some form of time-zone.* Hence the default format of UTC. – Andreas Jul 06 '17 at 17:00
  • 1
    @Andreas Indeed! I focused the explanation on `toString()` and forgot to mention the most important part. I've added this info to the answer, thanks a lot! –  Jul 06 '17 at 17:06
1

Instant does not have any time zone information. It is just the number of seconds/nanoseconds since epoch. LocalDateTime represents time in the local time zone, which can be obtained from clock using:

LocalDateTime.now(clock)

You can also convert an Instant to ZonedDateTime (which represents time along with timezone) using:

clock.instant().atZone(ZoneId.systemDefault())
Manu
  • 76
  • 1
  • 4
  • 4
    If you want a `ZonedDateTime`, you should also use `ZonedDateTime.now(clock)`, not `clock.instant().atZone(...)`, so the time zone of the `ZonedDateTime` is correctly taken from the `Clock`. – Andreas Jul 06 '17 at 17:11