Davy Jones
Davy Jones

Reputation: 13

Converting epoch millis between timezones

I get a number in epoch format. Epoch is supposed to be in UTC, but I am getting it in PST timezone. So I have to fix the value. How should I do that?

What I tried at first:

  // This number represents Tuesday, July 30, 2019 1:53:19 AM UTC, 
  // but it's supposed to represent PST.
  // The actual PST value for this date is going to be 1564476799000 
  // which is the same as Tuesday, July 30, 2019 8:53:19 AM UTC.
  // So I need to "pretend" that this value is actually PST 
  // and adjust it accordingly (including DST and friends).
  Long testDateLong = 1564451599000L;

  // These correctly assume that the instant is in UTC and adjust it to PST
  // which is not the real intention
  LocalDateTime pstL = LocalDateTime.ofInstant(Instant.ofEpochMilli(testDateLong), 
     ZoneId.of("America/Los_Angeles"));
  ZonedDateTime pstZ = ZonedDateTime.ofInstant(Instant.ofEpochMilli(testDateLong), 
     ZoneId.of("America/Los_Angeles"));

  System.out.println(pstL);
  System.out.println(pstZ);

  /*
   * Output:
   *
   * 2019-07-29T18:53:19
   * 2019-07-29T18:53:19-07:00[America/Los_Angeles]
   * 
   * Expected to see: 
   * 
   * 2019-07-30T01:53:19
   * 2019-07-30T01:53:19-07:00[America/Los_Angeles]
   * 
   */

The working solution is to format the epoch value into a string in UTC and then parse it with PST timezone, as following:

  Long testDateLong = 1564451599000L;

  DateTimeFormatter formatterUTC = DateTimeFormatter
    .ofLocalizedDateTime(FormatStyle.SHORT)
    .withZone(ZoneId.of("Etc/UTC"));

  DateTimeFormatter formatterPST = DateTimeFormatter  
    .ofLocalizedDateTime(FormatStyle.SHORT)
    .withZone(ZoneId.of("America/Los_Angeles"));

  String utcString = formatterUTC.format(Instant.ofEpochMilli(testDateLong));

  Instant instant = Instant.from(formatterPST.parse(utcString));

  System.out.println(utcString);
  System.out.println(instant);
  System.out.println(instant.toEpochMilli());

  /*
   * Output:
   *
   * 7/30/19 1:53 AM
   * 2019-07-30T08:53:00Z
   * 1564476780000
   */

However, it seems like a bad~ish solution to me (just a hunch). I wonder if there is something better than generating a string and parsing it?

Upvotes: 1

Views: 115

Answers (1)

azro
azro

Reputation: 54148

You may parse with the UTC zone, and then change the Zone

long testDateLong = 1564451599000L;
Instant ist = Instant.ofEpochMilli(testDateLong);

ZoneId zUTC = ZoneId.of("UTC");
ZoneId zLA = ZoneId.of("America/Los_Angeles");

ZonedDateTime zdt1 = LocalDateTime.ofInstant(ist, zUTC).atZone(zLA);
ZonedDateTime zdt2 = ZonedDateTime.ofInstant(ist, zUTC).withZoneSameLocal(zLA);

System.out.println(zdt1); // 2019-07-30T01:53:19-07:00[America/Los_Angeles]
System.out.println(zdt2); // 2019-07-30T01:53:19-07:00[America/Los_Angeles]

Upvotes: 1

Related Questions