Time Zones and Instant

ZonedDateTime and Instant

Servers should store time as an Instant (UTC) and convert to the user's zone only for display. India uses Asia/Kolkata (UTC+05:30) with no daylight saving; zones like America/New_York change offset during the year.

Example

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        ZoneId india = ZoneId.of("Asia/Kolkata");
        ZonedDateTime launch = ZonedDateTime.of(LocalDateTime.of(2024, 11, 20, 18, 30), india);
        System.out.println("India    : " + launch);

        DateTimeFormatter f = DateTimeFormatter.ofPattern("dd MMM HH:mm z");
        for (String zone : new String[] { "UTC", "Europe/London", "America/New_York", "Asia/Tokyo" }) {
            ZonedDateTime other = launch.withZoneSameInstant(ZoneId.of(zone));
            System.out.printf("%-17s %s%n", zone, other.format(f));
        }

        Instant instant = launch.toInstant();
        System.out.println("Instant  : " + instant);
        System.out.println("Epoch sec: " + instant.getEpochSecond());
        Instant fromDb = Instant.parse("2024-11-20T13:00:00Z");
        System.out.println("Same moment? " + instant.equals(fromDb));
        System.out.println("Back in IST: " + fromDb.atZone(india).toLocalDateTime());
    }
}

Output

India    : 2024-11-20T18:30+05:30[Asia/Kolkata]
UTC               20 Nov 13:00 UTC
Europe/London     20 Nov 13:00 GMT
America/New_York  20 Nov 08:00 EST
Asia/Tokyo        20 Nov 22:00 JST
Instant  : 2024-11-20T13:00:00Z
Epoch sec: 1732107600
Same moment? true
Back in IST: 2024-11-20T18:30

Legacy Classes

Old code and some libraries still use java.util.Date and Calendar. Convert at the edges and use java.time inside your code.

Date legacy = new Date();
Instant instant = legacy.toInstant();                 // Date -> Instant
Date back = Date.from(instant);                       // Instant -> Date

LocalDate date = instant.atZone(ZoneId.of("Asia/Kolkata")).toLocalDate();
java.sql.Date sqlDate = java.sql.Date.valueOf(date);  // for old JDBC code