javajava-timelocaldatetime

Convert UTC datetime to local datetime using java.time


I have a UTC date-time like this (a String): 2022-11-22T17:15:00

And a ZoneID like this: "America/Tijuana"

Using java.time API, I want to get the actual datetime for that zone, which is: 2022-11-22T09:15:00 (the time is 09:15 instead of 17:15)

None of the above gives me what I'm looking for.

This is my code:

    ZoneId zonaID = ZoneId.of('America/Tijuana');
    CharSequence dateUTC = "2022-11-22T17:15:00";
    LocalDateTime dateTimeL = LocalDateTime.parse(dateUTC);
    ZonedDateTime myZDT = ZonedDateTime.now();
    ZonedDateTime myZDTFinal = myZDT.of(dateTimeL, zonaID);
    System.out.println("using toLocalDateTime: " + myZDTFinal.toLocalDateTime());
    System.out.println("using toString: " + myZDTFinal.toString());

I know that this might be a duplicated question but there's so many questions about date-times and I just haven't been able to figure out this.

Any help will be really appreciated.


Solution

  • There can be many ways to achieve the result. A simple approach would be

    1. Parse the given string into LocalDateTime.
    2. Convert it into an OffsetDateTime at UTC using LocalDateTime#atOffset.
    3. Use OffsetDateTime#atZoneSameInstant to convert the resulting OffsetDateTime into a ZonedDateTime at ZoneId.of("America/Tijuana").
    4. Get LocalDateTime out of the resulting ZonedDateTime by using ZonedDateTime#toLocalDateTime.
    5. If required, format this LocalDateTime into the desired string.
    LocalDateTime
        .parse("2022-11-22T17:15:00") // Parse the given date-time string into LocalDateTime
        .atOffset(ZoneOffset.UTC) // Convert it into a ZonedDateTime at UTC
        .atZoneSameInstant(ZoneId.of("America/Tijuana")) // Convert the result into a ZonedDateTime at another time-zome
        .toLocalDateTime() // Get the LocalDateTime out of the ZonedDateTime
        .format(DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss", Locale.ENGLISH))); // If required
    

    Demo:

    import java.time.LocalDateTime;
    import java.time.ZoneId;
    import java.time.ZoneOffset;
    import java.time.format.DateTimeFormatter;
    import java.util.Locale;
    
    public class Main {
        public static void main(String[] args) {
            LocalDateTime ldtInTijuana = LocalDateTime.parse("2022-11-22T17:15:00")
                    .atOffset(ZoneOffset.UTC)
                    .atZoneSameInstant(ZoneId.of("America/Tijuana"))
                    .toLocalDateTime();
            System.out.println(ldtInTijuana);
    
            // Custom format
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss", Locale.ENGLISH);
            String formatted = ldtInTijuana.format(formatter);
            System.out.println(formatted);
        }
    }
    

    Output:

    2022-11-22T09:15
    2022-11-22T09:15:00
    

    Note that LocalDateTime#toString removes second and fraction-of-second values if they are zero. Suppose you want to keep them (as you have posted in your question), you can use a DateTimeFormatter as shown above.

    An alternate approach:

    Alternatively, you can append Z at the end of your ISO 8601 formatted date-time string to enable Instant to parse it and then convert the Instant into a ZonedDateTime corresponding to the ZoneId.of("America/Tijuana") by using Instant#atZone. The symbol, Z refers to UTC in a date-time string.

    The rest of the steps will remain the same.

    Demo:

    public class Main {
        public static void main(String[] args) {
            String text = "2022-11-22T17:15:00";
            text = text + "Z"; // Z refers to UTC
            Instant instant = Instant.parse(text);
            LocalDateTime ldt = instant.atZone(ZoneId.of("America/Tijuana")).toLocalDateTime();
            System.out.println(ldt);
        }
    }
    

    Output:

    2022-11-22T09:15
    

    Learn more about the modern Date-Time API from Trail: Date Time.