Convert LocalDateTime of a particular time zone to eastern time accounting daylight savings

I have a LocalDateTime field representing a date and time, and a separate timezone string which tells its time zone.

I want to convert the time in the LocalDateTime to eastern timezone.

I found several answers explaining this, but all of them use the IANA’s naming standard of zone ids of Continent/Region for conversion. I am getting the short form notation of zone ids in the timezone field from the user which is like IST, AEST, CST, etc. Is there a way I can convert time to eastern time format using the short notations?

UPDATE: I have a limited set of time zones which can be given as input. They are as follows:

  • JST – Japan Standard Time (+09:00)
  • CST – China Standard Time (+08:00)
  • SAST – South African Standard Time (+02:00)
  • CET – Central European Time (+01:00 / +02:00)
  • GMT – Greenwich Mean Time (00:00)
  • ET – Eastern Time Zone (-05:00 / -04:00)
  • BST – British Summer Time (+01:00 / 00:00)
  • HKT – Hong Kong Time (+08:00)
  • IST – Indian Standard Time (+05:30)
  • GST – Gulf Standard Time (+04:00)
  • MSK – Moscow Standard Time (+03:00)
  • BRT – Brasília Time (-03:00)
  • NZST – New Zealand Standard Time (+12:00 / +13:00)
  • AEST – Australian Eastern Standard Time (+10:00 / +11:00)

The conversion strategy should take care of DST. So if input is 2021-01-06T10:30:00 and time zone given is IST. The method while converting this to EST should figure out if DST applies or not and do the conversion accordingly with either -05:00 or -04:00 as applicable.

Answer

Java uses IANA time zone IDs in the form region/city. So if you can map your abbreviations to those, you can get through. For the sake of giving you working code, here’s an example but I guarantee that some of the IDs are not the ones you want. You will have to define your own mapping. Some of the long time zone names in your list do not refer to unique time zones, for example Gulf Standard Time and Central European Time. There are many time zones within those regions.

private static final Map<String, String> tzSubset = Map.ofEntries(
                Map.entry("NZST", "Antarctica/McMurdo"),
                Map.entry("AEST", "Australia/Sydney"),
                Map.entry("JST", "Asia/Tokyo"),
                Map.entry("HKT", "Asia/Hong_Kong"),
                Map.entry("CST", "America/North_Dakota/New_Salem"), // not in China
                Map.entry("SGT", "Asia/Singapore"),
                Map.entry("IST", "Asia/Calcutta"),
                Map.entry("GST", "Asia/Dubai"),
                Map.entry("MSK", "Europe/Volgograd"),
                Map.entry("SAST", "Africa/Mbabane"),
                Map.entry("CET", "Africa/Ceuta"),
                Map.entry("GMT", "Etc/GMT"),
                Map.entry("BST", "Europe/Belfast"),
                Map.entry("BRT", "America/Maceio"),
                Map.entry("ET", "America/Indiana/Winamac")
        );
private static final ZoneId targetTimeZone = ZoneId.of("America/Toronto");

With the mapping and the desired time zone in place, the conversion is simple enough:

    LocalDateTime inputDateTime = LocalDateTime.of(2021, Month.JANUARY, 13, 23, 45);
    String inputTimeZone = "BST";
    
    ZoneId zone = ZoneId.of(inputTimeZone, tzSubset);
    ZonedDateTime targetDateTime = inputDateTime.atZone(zone)
            .withZoneSameInstant(targetTimeZone);
    
    System.out.format("%s in %s equals %s%n", inputDateTime, zone, targetDateTime);

Output from this example snippet is:

2021-01-13T23:45 in Europe/London equals 2021-01-13T18:45-05:00[America/Toronto]

The conversion automatically accounts for summer time (DST) if either of the two time zones involved uses it.

Edit: It seems that you are assuming that the dates and times are current, not historical? You mentioned that America/Sao_Paulo dropped summer time in 2019 — so what if you have got a LocalDateTime from 2019 or earlier? If you don’t plan to handle those correctly, you should definitely do a range check on your date time and refuse to convert it if falls outside your intended bounds. Use the isBefore and/or the isAfter method of LocalDateTime.

Link: Oracle tutorial: Date Time explaining how to use java.time.

Leave a Reply

Your email address will not be published. Required fields are marked *