5

Given a LocalTime in a given ZoneId, how can I find the adjusted LocalTime on UTC?

I am looking for something similar to .atZone from LocalDateTime, but couldn't find anything.

I suspect I can use it with atOffset, but I don't really understand how to use it.

So for example:

LocalTime: 15:00
ZoneId: America/Sao_Paulo (GMT -3)
Output: 18:00
Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
Matheus208
  • 1,289
  • 2
  • 13
  • 26

2 Answers2

11

You need to give a date too. In case the zone has summer time (DST), for example, this is needed to apply the correct offset (I don’t know whether São Paulo uses summer time, but Java requires a date always).

And still this takes one more step than what you might have expected, but it’s straightforward enough once you know how. For the case of demonstration I have assumed you meant 15:00 today, which you hardly did, but I trust you to fill in the desired date yourself.

    LocalTime time = LocalTime.of(15, 0);
    LocalTime utcTime = LocalDateTime.of(LocalDate.now(), time)
            .atZone(ZoneId.of("America/Sao_Paulo"))
            .withZoneSameInstant(ZoneOffset.UTC)
            .toLocalTime();
    System.out.println(utcTime);

This prints the result you also asked for

18:00
Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • 2
    Yes, São Paulo has summer time. And I'm not sure if the call to `toOffsetDateTime` is needed (maybe you could just use `ZonedDateTime.withZoneSameInstant` but I'm not in front of a computer to test). Anyway, +1 to you! –  Jun 07 '17 at 15:22
  • 2
    Thanks, @Hugo, for the slight simplification (I had looked for **at**Zone, in this case it’s **with**Zone). – Ole V.V. Jun 07 '17 at 15:32
  • 1
    I was hoping to avoid `LocalDateTime`, but I was not considering DST! Thanks for this, it looks like it is the correct way to go. – Matheus208 Jun 07 '17 at 16:29
  • 1
    @OleV.V. I've found in [javadoc](https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html) a good description of methods names: `with` - the immutable equivalent of a setter (so it returns the same type) / `at` - combines this object with another (so it returns a different type) –  Jun 08 '17 at 14:12
7

A ZoneId does not make sense because the date is missing but you can use a ZoneOffset this way:

LocalTime time = LocalTime.of(15, 0);
ZoneOffset offset = ZoneOffset.ofHours(-3);
LocalTime utc =
    OffsetTime.of(time, offset).withOffsetSameInstant(ZoneOffset.UTC).toLocalTime();
System.out.println(utc); // 18:00
Meno Hochschild
  • 42,708
  • 7
  • 104
  • 126
  • 1
    Thank you for the informative answer! However, @Ole V.V.'s answer made me realise I had a concept flaw in my logic (I wasn't taking into account DST). That's why I upvoted both answers, but I had to accepted theirs. – Matheus208 Jun 08 '17 at 14:44
  • @Matheus208 I agree with you that using a global type like `Instant` or `ZonedDateTime` is generally the better choice. My answer was mainly based on the impression that you don't have a chance to determine the instant context. Theoretically, my answer could be enhanced by determining the offset dependent on an instant (which requires a date, too): `ZoneId.of("America/Sao_Paulo").getRules().getOffset(instant)` But this is even more coding than what Ole has given you. – Meno Hochschild Jun 08 '17 at 16:02