openplanning

Hướng dẫn và ví dụ Java ZonedDateTime

  1. ZonedDateTime
  2. ZonedDateTime hỗ trợ dữ liệu lịch sử
  3. ZonedDateTime & DST
  4. ZonedDateTime methods
  5. withZoneSameInstant(ZoneId)
  6. withZoneSameLocal(ZoneId)
  7. withEarlierOffsetAtOverlap()
  8. withLaterOffsetAtOverlap()
  9. withFixedOffsetZone()

1. ZonedDateTime

ZonedDateTime là một lớp đại diện cho ngày tháng thời gian với thông tin múi giờ, nằm trong hệ thống lịch theo tiêu chuẩn ISO-8601, chẳng hạn 2007-12-03T10:15:30+01:00 Europe/Paris.
Lớp ZonedDateTime nằm trong package java.time. Giống như tất cả các lớp được cung cấp bởi Java Date Time API, ZonedDateTime là bất biến (immutable), điều này có nghĩa là tất cả các tính toán trên ZonedDateTime đều tạo ra một đối tượng ZonedDateTime mới, vì vậy nó an toàn khi được sử dụng trong môi trường multithreading.
Trước khi tiếp tục với bài viết này bạn nên tìm hiểu về các khái niệm GMT, UTCUT:
public final class ZonedDateTime
        implements Temporal, ChronoZonedDateTime<LocalDate>, Serializable {

    private final LocalDateTime dateTime;
    private final ZoneOffset offset;
    private final ZoneId zone;
}
Nhìn vào mã nguồn của lớp ZonedDateTime thấy rằng nó quản lý 3 đối tượng nội bộ. Trong đó:
  • Đối tượng LocalDateTime chứa thông tin ngày tháng và thời gian.
  • Đối tượng ZoneId là tên định danh của múi giờ, chẳng hạn Europe/Paris.
  • Đối tượng ZoneOffset chứa thông tin độ lệch múi giờ (time-zone offset). Chẳng hạn +01:30.
Ví dụ: Từ một đối tượng LocalDateTime chỉ chứa thông tin ngày tháng và thời gian, chúng ta thêm thông tin múi giờ cho nó để tạo ra một đối tượng ZonedDateTime chứa thông tin ngày tháng, thời gian và múi giờ.
ZonedDateTimeEx1.java
package org.o7planning.zoneddatetime.ex;

import java.time.LocalDateTime;
import java.time.Month;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class ZonedDateTimeEx1 {

    public static void main(String[] args) {
        // LocalDateTime:
        LocalDateTime myLocalDateTime = LocalDateTime.of(2020, Month.MAY, 15, 13, 45, 30);

        System.out.println("My LocalDateTime: " + myLocalDateTime); // 2020-05-15T13:45:30

        // UTC+7 (Ho Chi Minh Vietnam).
        ZoneId vnZoneId = ZoneId.of("Asia/Ho_Chi_Minh");

        // Add time zone information to LocalDateTime.
        ZonedDateTime vnDateTime = ZonedDateTime.of(myLocalDateTime, vnZoneId);

        System.out.println("VN DateTime: " + vnDateTime); // 2020-05-15T13:45:30+07:00[Asia/Ho_Chi_Minh]

        // Same as:
        ZonedDateTime vnDateTime2 = myLocalDateTime.atZone(vnZoneId);

        System.out.println("VN DateTime: " + vnDateTime2); // 2020-05-15T13:45:30+07:00[Asia/Ho_Chi_Minh]
    }
}
Output:
My LocalDateTime: 2020-05-15T13:45:30
VN DateTime: 2020-05-15T13:45:30+07:00[Asia/Ho_Chi_Minh]
VN DateTime: 2020-05-15T13:45:30+07:00[Asia/Ho_Chi_Minh]
Ví dụ: Lúc giao thừa năm 2020 tại Việt Nam sẽ tương đương với mấy giờ tại Nhật và Pháp. Ví dụ sau sẽ cho bạn thấy một chuyển đổi thời gian như vậy:
ZonedDateTimeEx2.java
// 2000-01-01 00:00:00
LocalDateTime localDateTime = LocalDateTime.of(2000, Month.JANUARY, 1, 0, 0, 0);

System.out.println("LocalDateTime: " + localDateTime); // 2000-01-01T00:00
System.out.println();

// UTC+7 (Ho Chi Minh Vietnam).
ZoneId vnZoneId = ZoneId.of("Asia/Ho_Chi_Minh");
// Add time zone to it!
ZonedDateTime vnDateTime = ZonedDateTime.of(localDateTime, vnZoneId);

System.out.println("Vietnam: " + vnDateTime); // 2000-01-01T00:00+07:00[Asia/Ho_Chi_Minh]

// UTC+9 (Tokyo Japan).
ZoneId jpZoneId = ZoneId.of("Asia/Tokyo");
ZonedDateTime jpDateTime = vnDateTime.withZoneSameInstant(jpZoneId);

System.out.println("Japan: " + jpDateTime); // 2000-01-01T02:00+09:00[Asia/Tokyo]

// UTC+1 (Paris France).
ZoneId frZoneId = ZoneId.of("Europe/Paris");
ZonedDateTime frDateTime = vnDateTime.withZoneSameInstant(frZoneId);

System.out.println("France: " + frDateTime); // 1999-12-31T18:00+01:00[Europe/Paris]
Output:
LocalDateTime: 2000-01-01T00:00

Vietnam: 2000-01-01T00:00+07:00[Asia/Ho_Chi_Minh]
Japan: 2000-01-01T02:00+09:00[Asia/Tokyo]
France: 1999-12-31T18:00+01:00[Europe/Paris]
Ví dụ: Lúc 12 giờ ngày 1 tháng 1 năm 2020 bạn bay từ Việt Nam tới Nhật Bản, thời gian bay là 6 giờ 15 phút. Câu hỏi là bạn sẽ tới Nhật Bản vào lúc mấy giờ?
ZonedDateTime_flight_ex1.java
// 2020-01-01 12:00:00
LocalDateTime localDateTime = LocalDateTime.of(2020, Month.JANUARY, 1, 12, 0, 0);

System.out.println("LocalDateTime: " + localDateTime); // 2020-01-01T12:00
System.out.println();

// UTC+7 (Ho Chi Minh Vietnam).
ZoneId vnZoneId = ZoneId.of("Asia/Ho_Chi_Minh");
// Add time zone to it!
ZonedDateTime vnDateTime = ZonedDateTime.of(localDateTime, vnZoneId);

System.out.println("Depart from Vietnam at: " + vnDateTime); // 2020-01-01T12:00+07:00[Asia/Ho_Chi_Minh]

// UTC+9 (Tokyo Japan).
ZoneId jpZoneId = ZoneId.of("Asia/Tokyo");
ZonedDateTime jpDateTime = vnDateTime.withZoneSameInstant(jpZoneId).plusHours(6).plusMinutes(15);

System.out.println("Arrive to Japan at: " + jpDateTime); // 2020-01-01T20:15+09:00[Asia/Tokyo]
Output:
LocalDateTime: 2020-01-01T12:00

Depart from Vietnam at: 2020-01-01T12:00+07:00[Asia/Ho_Chi_Minh]
Arrive to Japan at: 2020-01-01T20:15+09:00[Asia/Tokyo]

2. ZonedDateTime hỗ trợ dữ liệu lịch sử

Múi giờ của một khu vực địa lý có thể thay đổi một chút do mục đích của quốc gia và vị trí địa lý. Điều tuyệt vời là ZonedDateTime lưu trữ các dữ liệu lịch sử đó. Chẳng hạn, từ năm 1960 đến trước ngày 13 tháng 6 năm 1975, miền nam Việt Nam sử dụng múi giờ UTC+8, sau đó được chuyển sang múi giờ UTC+7 để thống nhất với miền bắc Việt Nam.
Để đơn giản hãy xem ví dụ dưới đây:
ZonedDateTime_history_ex1.java
package org.o7planning.zoneddatetime.ex;

import java.time.ZoneId;
import java.time.ZonedDateTime;

public class ZonedDateTime_history_ex1 {

    public static void main(String[] args) {
        // Time-zone Ho Chi Minh City (Vietnam).
        ZoneId hcmZoneId = ZoneId.of("Asia/Ho_Chi_Minh");

        // 1975-06-12 (UTC+8)
        ZonedDateTime zdt1 = ZonedDateTime.of(1975, 6, 12, 0, 0, 0, 0, hcmZoneId);
        System.out.println("zdt1: " + zdt1); // 1975-06-12T00:00+08:00[Asia/Ho_Chi_Minh]

        // 1975-06-13 (UTC+7)
        ZonedDateTime zdt2 = ZonedDateTime.of(1975, 6, 13, 0, 0, 0, 0, hcmZoneId);
        System.out.println("zdt2: " + zdt2); // 1975-06-13T00:00+07:00[Asia/Ho_Chi_Minh]
    }
}
Output:
zdt1: 1975-06-12T00:00+08:00[Asia/Ho_Chi_Minh]
zdt2: 1975-06-13T00:00+07:00[Asia/Ho_Chi_Minh]

3. ZonedDateTime & DST

Hiện nay hầu hết các tiểu bang tại Hoa Kỳ áp dụng giờ tiết kiệm ánh sáng ban ngày (Daylight Saving Time - DST). Cụ thể là từ lúc 2 giờ ngày chủ nhật thứ hai của tháng 3 tới 2 giờ ngày chủ nhật đầu tiên của tháng 11, các đồng hồ sẽ được đặt sớm hơn 1 giờ.

United States

European Union
Year
DST Begins at 2 a.m.
DST Ends at 2 a.m.
Summertime period begins at 1 a.m. UT
Summertime period ends at 1 a.m. UT
2017
March 12
November 5
March 26
October 29
2018
March 11
November 4
March 25
October 28
2019
March 10
November 3
March 31
October 27
2020
March 8
November 1
March 29
October 25
2021
March 14
November 7
March 28
October 31
2022
March 13
November 6
March 27
October 30
2023
March 12
November 5
March 26
October 29
2024
March 10
November 3
March 31
October 27
Năm 2021 tại Hoa Kỳ, DST bắt đầu từ lúc 2 giờ ngày 14 tháng 3 và kết thúc lúc 2 giờ sáng ngày 7 tháng 11. Chúng ta hãy xem Java 8 Date Time API giải quyết DST như thế nào.
Chúng ta sẽ tạo một đối tượng ZonedDateTime đại diện cho thời điểm 1 giờ 30 phút sáng ngày 14 tháng 3 năm 2021 miền trung Hoa Kỳ. Sau đó cộng thêm 1 giờ cho nó và xem điều gì xẩy ra.
ZonedDateTime_dst_ex1.java
package org.o7planning.zoneddatetime.ex;

import java.time.ZoneId;
import java.time.ZonedDateTime;

public class ZonedDateTime_dst_ex1 {

    public static void main(String[] args) {
        // US/Central
        ZoneId uscZoneId = ZoneId.of("US/Central");

        //
        // Year 2021 in America:
        // DST begin at March 14 to November 7 (2021-03-14 02:00 --> 2021-11-07 02:00)
        //

        // 2021-03-14 (UTC-6)
        ZonedDateTime zdt1 = ZonedDateTime.of(2021, 3, 14, 1, 30, 0, 0, uscZoneId);
        System.out.println("zdt1: " + zdt1); // 2021-03-14T01:30-06:00[US/Central]

        // Add 1 Hour to zdt1
        ZonedDateTime zdt2 = zdt1.plusHours(1);
        System.out.println("zdt2: " + zdt2); // 2021-03-14T03:30-05:00[US/Central]
    }
}
Output:
zdt1: 2021-03-14T01:30-06:00[US/Central]
zdt2: 2021-03-14T03:30-05:00[US/Central]
Flight from Vietnam to France:
Ví dụ: Giả sử lúc 12 giờ ngày 1 tháng 5 năm 2021 bạn bay từ Việt Nam tới Pháp, thời gian bay là 13 giờ 6 phút. Vậy bạn sẽ tới Pháp lúc mấy giờ?
Chú ý: Năm 2021, DST tại pháp bắt đầu từ lúc 1 giờ sáng ngày 28 tháng 3 và kết thúc vào lúc 1 giờ sáng ngày 31 tháng 10. Múi giờ mặc định của Pháp là UTC+1, trong thời gian DST nó sử dụng múi giờ UTC+2.
ZonedDateTime_flight_ex2.java
// 2020-01-01 12:00:00
LocalDateTime localDateTime = LocalDateTime.of(2021, Month.MAY, 1, 12, 0, 0);
 
// UTC+7 (Ho Chi Minh Vietnam).
ZoneId vnZoneId = ZoneId.of("Asia/Ho_Chi_Minh");
// Add time zone to it!
ZonedDateTime vnDateTime = ZonedDateTime.of(localDateTime, vnZoneId);

System.out.println("Depart from Vietnam at: " + vnDateTime); // 2021-05-01T12:00+07:00[Asia/Ho_Chi_Minh]

// Europe/Paris: Default offset: +1. DST offset: +2
ZoneId frZoneId = ZoneId.of("Europe/Paris");
ZonedDateTime frDateTime = vnDateTime.withZoneSameInstant(frZoneId).plusHours(13).plusMinutes(6);

System.out.println("Arrive to France at: " + frDateTime); // 2021-05-01T20:06+02:00[Europe/Paris]
Output:
Depart from Vietnam at: 2021-05-01T12:00+07:00[Asia/Ho_Chi_Minh]
Arrive to France at: 2021-05-01T20:06+02:00[Europe/Paris]
Ví dụ trên cho thấy kết quả bạn sẽ tới Pháp vào lúc 20:06 ngày 1 tháng 5 năm 2021 theo giờ DST.

4. ZonedDateTime methods

Lớp ZonedLocalDate không cung cấp bất kỳ một constructor nào để tạo đối tượng, thay vào đó bạn có thể sử dụng một trong các phương thức nhà máy tĩnh sau:
public static ZonedDateTime now()  

public static ZonedDateTime now(ZoneId zone)  

public static ZonedDateTime now(Clock clock)  

public static ZonedDateTime of(LocalDate date, LocalTime time, ZoneId zone)  

public static ZonedDateTime of(LocalDateTime localDateTime, ZoneId zone)

public static ZonedDateTime of(int year, int month, int dayOfMonth,
                               int hour, int minute, int second,
                               int nanoOfSecond, ZoneId zone)

public static ZonedDateTime ofLocal(LocalDateTime localDateTime,
                               ZoneId zone, ZoneOffset preferredOffset)  

public static ZonedDateTime ofInstant(Instant instant, ZoneId zone)

public static ZonedDateTime ofInstant(LocalDateTime localDateTime,
                               ZoneOffset offset, ZoneId zone)  

public static ZonedDateTime ofStrict(LocalDateTime localDateTime, ZoneOffset offset, ZoneId zone)  

public static ZonedDateTime from(TemporalAccessor temporal)  

public static ZonedDateTime parse(CharSequence text)  

public static ZonedDateTime parse(CharSequence text, DateTimeFormatter formatter)
Hầu hết các phương thức của lớp ZonedDateTime giống với các phương thức của lớp LocalDateTime, chẳng hạn danh sách các phương thức dưới đây. Bạn có thể xem thêm bài viết về LocalDateTime để có thêm nhiều ví dụ:
// ----------------------------------------------------
// getX(..) methods
// ----------------------------------------------------

public int getYear()  
public int getMonthValue()
public Month getMonth()
public int getDayOfMonth()  
public int getDayOfYear()  
public DayOfWeek getDayOfWeek()  
public int getHour()  
public int getMinute()  
public int getSecond()  
public int getNano()  
// Inherited from TemporalAccessor interface
public int get(TemporalField field)  
// Inherited from TemporalAccessor interface
public long getLong(TemporalField field)  

// ----------------------------------------------------
// withX(..) methods
// ----------------------------------------------------

public ZonedDateTime withYear(int year)  
public ZonedDateTime withMonth(int month)
public ZonedDateTime withDayOfMonth(int dayOfMonth)  
public ZonedDateTime withDayOfYear(int dayOfYear)  
public ZonedDateTime withHour(int hour)  
public ZonedDateTime withMinute(int minute)
public ZonedDateTime withSecond(int second)  
public ZonedDateTime withNano(int nanoOfSecond)
// Inherited from TemporalAccessor interface
public ZonedDateTime with(TemporalAdjuster adjuster)
// Inherited from Temporal interface
public ZonedDateTime with(TemporalField field, long newValue)  
// ----------------------------------------------------
// plusX(..) methods
// ----------------------------------------------------

public ZonedDateTime plusYears(long years)
public ZonedDateTime plusMonths(long months)
public ZonedDateTime plusWeeks(long weeks)  
public ZonedDateTime plusDays(long days)  
public ZonedDateTime plusHours(long hours)  
public ZonedDateTime plusMinutes(long minutes)
public ZonedDateTime plusSeconds(long seconds)  
public ZonedDateTime plusNanos(long nanos)  
// Inherited from Temporal interface
public ZonedDateTime plus(TemporalAmount amountToAdd)
// Inherited from TemporalAccessor interface
public ZonedDateTime plus(long amountToAdd, TemporalUnit unit)

// ----------------------------------------------------
// minusX(..) methods
// ----------------------------------------------------

public ZonedDateTime minusYears(long years)  
public ZonedDateTime minusMonths(long months)  
public ZonedDateTime minusWeeks(long weeks)
public ZonedDateTime minusDays(long days)  
public ZonedDateTime minusHours(long hours)
public ZonedDateTime minusMinutes(long minutes)  
public ZonedDateTime minusSeconds(long seconds)  
public ZonedDateTime minusNanos(long nanos)  
// Inherited from TemporalAccessor interface
public ZonedDateTime minus(TemporalAmount amountToSubtract)
// Inherited from TemporalAccessor interface
public ZonedDateTime minus(long amountToSubtract, TemporalUnit unit)  

// ----------------------------------------------------
// isSupported(..) methods
// ----------------------------------------------------

// Inherited from TemporalAccessor interface
public boolean isSupported(TemporalField field)

// Inherited from Tempral interface
public boolean isSupported(TemporalUnit unit)  

// ----------------------------------------------------
// ----------------------------------------------------

// Inherited from TemporalAccessor interface
public ValueRange range(TemporalField field)  

// Inherited from TemporalAccessor interface
public <R> R query(TemporalQuery<R> query)  

// Inherited from Temporal interface
public long until(Temporal endExclusive, TemporalUnit unit)  

// Inherited from ChronoZonedDateTime<LocalDate> interface
public String format(DateTimeFormatter formatter)  

public ZonedDateTime truncatedTo(TemporalUnit unit)
Các phương thức khác:
// Inherited from ChronoZonedDateTime<LocalDate> interface
public ZoneId getZone()

// Inherited from ChronoZonedDateTime<LocalDate> interface
public ZoneOffset getOffset()  

// Owner
public OffsetDateTime toOffsetDateTime()

// Inherited from ChronoZonedDateTime<LocalDate> interface
public LocalDateTime toLocalDateTime()  

// Inherited from ChronoZonedDateTime<LocalDate> interface
public LocalDate toLocalDate()  

// Inherited from ChronoZonedDateTime<LocalDate> interface
public LocalTime toLocalTime()  

// Owner
public ZonedDateTime withFixedOffsetZone()  

// Inherited from ChronoZonedDateTime<LocalDate> interface
public ZonedDateTime withEarlierOffsetAtOverlap()  

// Inherited from ChronoZonedDateTime<LocalDate> interface
public ZonedDateTime withLaterOffsetAtOverlap()

// Inherited from ChronoZonedDateTime<LocalDate> interface
public ZonedDateTime withZoneSameLocal(ZoneId zone)

// Inherited from ChronoZonedDateTime<LocalDate> interface
public ZonedDateTime withZoneSameInstant(ZoneId zone)

5. withZoneSameInstant(ZoneId)

// Inherited from ChronoZonedDateTime<LocalDate> interface
public ZonedDateTime withZoneSameInstant(ZoneId zone)
Trả về bản sao của ZonedDateTime với múi giờ mới và giữ lại khoảng khắc (instant) trên dòng thời gian. Chẳng hạn, lúc 12 giờ tại Việt Nam sẽ được đổi thành 14 giờ theo múi giờ Nhật Bản.
ZonedDateTime_withZoneSameInstant_ex1.java
package org.o7planning.zoneddatetime.ex;

import java.time.LocalDateTime;
import java.time.Month;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class ZonedDateTime_withZoneSameInstant_ex1 {

    public static void main(String[] args) {
        // 2020-01-01 12:00:00
        LocalDateTime localDateTime = LocalDateTime.of(2020, Month.JANUARY, 1, 12, 0, 0);
        
        // Ho Chi Minh City Vietnam. UTC+7
        ZonedDateTime vnDateTime = ZonedDateTime.of(localDateTime, ZoneId.of("Asia/Ho_Chi_Minh"));
        System.out.println("VN Datetime: " + vnDateTime); // 2020-01-01T12:00+07:00[Asia/Ho_Chi_Minh]
        
        // Tokyo Japan. UTC+9
        ZonedDateTime  jpDateTime = vnDateTime.withZoneSameInstant(ZoneId.of("Asia/Tokyo"));
        
        System.out.println("JP Datetime: " + jpDateTime); // 2020-01-01T14:00+09:00[Asia/Tokyo]
    }
}
Output:
VN Datetime: 2020-01-01T12:00+07:00[Asia/Ho_Chi_Minh]
JP Datetime: 2020-01-01T14:00+09:00[Asia/Tokyo]

6. withZoneSameLocal(ZoneId)

// Inherited from ChronoZonedDateTime<LocalDate> interface
public ZonedDateTime withZoneSameLocal(ZoneId zoneId)
Trả về một bản sao của ZonedDateTime này với múi giờ mới và giữ lại thông tin ngày giờ địa phương nếu có thể.
Ví dụ:
ZonedDateTime_withZoneSameLocal_ex1.java
package org.o7planning.zoneddatetime.ex;

import java.time.LocalDateTime;
import java.time.Month;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class ZonedDateTime_withZoneSameLocal_ex1 {

    public static void main(String[] args) {
        // 2020-01-01 00:00:00
        LocalDateTime localDateTime = LocalDateTime.of(2020, Month.JANUARY, 1, 0, 0, 0);
        
        // Ho Chi Minh City Vietnam.
        ZonedDateTime vnDateTime = ZonedDateTime.of(localDateTime, ZoneId.of("Asia/Ho_Chi_Minh"));
        System.out.println("VN Datetime: " + vnDateTime);
        
        // Chicago US:
        // Same Local Date Time as VN:
        ZonedDateTime chicagoDt = vnDateTime.withZoneSameLocal(ZoneId.of("America/Chicago"));
        
        System.out.println("Chicago Datetime: " + chicagoDt);
    }
}

7. withEarlierOffsetAtOverlap()

// Inherited from ChronoZonedDateTime<LocalDate> interface
public ZonedDateTime withEarlierOffsetAtOverlap()

United States

European Union
Year
DST Begins at 2 a.m.
DST Ends at 2 a.m.
Summertime period begins at 1 a.m. UT
Summertime period ends at 1 a.m. UT
2017
March 12
November 5
March 26
October 29
2018
March 11
November 4
March 25
October 28
2019
March 10
November 3
March 31
October 27
2020
March 8
November 1
March 29
October 25
2021
March 14
November 7
March 28
October 31
2022
March 13
November 6
March 27
October 30
2023
March 12
November 5
March 26
October 29
2024
March 10
November 3
March 31
October 27
Trong ví dụ dưới đây về phương thức withEarlierOffsetAtOverlap() chúng ta xem xét miền trung Hoa Kỳ ngày 7 tháng 11 năm 2021. Trong hệ thống thời gian tiêu chuẩn, khoảng thời gian 1 giờ sau khi DST kết thúc là khoảng thời gian chồng chéo (overlap) giữa hai hệ thống.
ZonedDateTime_withEarlierOffsetAtOverlap_ex1.java
package org.o7planning.zoneddatetime.ex;

import java.time.LocalDateTime;
import java.time.Month;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;

public class ZonedDateTime_withEarlierOffsetAtOverlap_ex1 {

    public static void main(String[] args) {
        // Default Offset: -6. When DST ON --> Offset: -5
        ZoneId usCenterZoneId = ZoneId.of("US/Central");
        
        // (Standard Time/offset -6) 2021-11-07  Overlap time: [01:00 --> 2:00)
        LocalDateTime localDateTime = LocalDateTime.of(2021, Month.NOVEMBER, 7, 1, 30, 0);  
        
        // Create a ZonedDateTime object with Fixed Offset = -6.   
        ZonedDateTime zonedDateTime = ZonedDateTime.ofLocal(localDateTime, usCenterZoneId, ZoneOffset.ofHours(-6));
        
        System.out.println("zonedDateTime: " + zonedDateTime);

        // apply withEarlierOffsetAtOverlap()
        ZonedDateTime zonedDateTime2 = zonedDateTime.withEarlierOffsetAtOverlap();
        
        System.out.println("zonedDateTime.withEarlierOffsetAtOverlap(): " + zonedDateTime2);
    }  
}
Output:
zonedDateTime: 2021-11-07T01:30-06:00[US/Central]
zonedDateTime.withEarlierOffsetAtOverlap(): 2021-11-07T01:30-05:00[US/Central]

8. withLaterOffsetAtOverlap()

// Inherited from ChronoZonedDateTime<LocalDate> interface
public ZonedDateTime withLaterOffsetAtOverlap()
Trong ví dụ dưới đây về phương thức withLaterOffsetAtOverlap() chúng ta xem xét miền trung Hoa Kỳ ngày 7 tháng 11 năm 2021. Trong hệ thống DST, khoảng thời gian 1 giờ trước khi DST kết thúc là khoảng thời gian chồng chéo (overlap) giữa hai hệ thống.
ZonedDateTime_withLaterOffsetAtOverlap_ex1.java
package org.o7planning.zoneddatetime.ex;

import java.time.LocalDateTime;
import java.time.Month;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class ZonedDateTime_withLaterOffsetAtOverlap_ex1 {

    public static void main(String[] args) {
        // Default Offset: -6. When DST ON --> Offset: -5
        ZoneId usCenterZoneId = ZoneId.of("US/Central");  
        
        // 2021-11-07 Overlap time: [01:00 --> 2:00)
        LocalDateTime localDateTime = LocalDateTime.of(2021, Month.NOVEMBER, 7, 1, 30, 0);
        
        // Create a ZonedDateTime object.
        ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, usCenterZoneId);
        
        System.out.println("zonedDateTime: " + zonedDateTime);

        // apply withLaterOffsetAtOverlap()
        ZonedDateTime zonedDateTime2 = zonedDateTime.withLaterOffsetAtOverlap();
        
        System.out.println("zonedDateTime.withLaterOffsetAtOverlap(): " + zonedDateTime2);
    }  
}
Output:
zonedDateTime: 2021-11-07T01:30-05:00[US/Central]
zonedDateTime.withLaterOffsetAtOverlap(): 2021-11-07T01:30-06:00[US/Central]

9. withFixedOffsetZone()

Như đã biết, đối tượng ZonedDateTime là sự kết hợp của 3 đối tượng LocalDateTime, ZoneIdZoneOffset:
ZonedDateTime
public final class ZonedDateTime
        implements Temporal, ChronoZonedDateTime<LocalDate>, Serializable {

    private final LocalDateTime dateTime;
    private final ZoneOffset offset;
    private final ZoneId zone;
}
Phương thức withFixedOffsetZone() trả về một bản sao của ZonedDateTime này với đối tượng ZoneId được thay thế bởi đối tượng ZoneOffset của nó.
public ZonedDateTime withFixedOffsetZone()
(*) Lớp ZoneOffset là lớp con của lớp ZoneId.
Điều này tương đương với:
ZonedDateTime origin = ...;

ZonedDateTime copy1 = origin.withFixedOffsetZone();

// Same as:

ZonedDateTime copy2 = ZonedDateTime.of(origin.toLocalDateTime(), origin.getOffset());
Ví dụ:
ZonedDateTime_withFixedOffsetZone_ex1.java
package org.o7planning.zoneddatetime.ex;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;

public class ZonedDateTime_withFixedOffsetZone_ex1 {

    public static void main(String[] args) {
        LocalDateTime localDateTime = LocalDateTime.of(2021, 11, 7, 1, 30, 00);
        ZoneId zoneId = ZoneId.of("US/Central");
        
        ZonedDateTime origin = ZonedDateTime.ofLocal(localDateTime, zoneId, ZoneOffset.ofHours(-6));

        System.out.println("origin: " + origin);
        System.out.println("origin.getZone(): " + origin.getZone());
        System.out.println("origin.getOffset(): " + origin.getOffset());

        System.out.println(" ------------- ");

        // apply withFixedOffsetZone()
        ZonedDateTime copied = origin.withFixedOffsetZone();

        System.out.println("copied: " + copied);
        System.out.println("copied.getZone(): " + copied.getZone());
        System.out.println("copied.getOffset(): " + copied.getOffset());
    }
}
Output:
origin: 2021-11-07T01:30-06:00[US/Central]
origin.getZone(): US/Central
origin.getOffset(): -06:00
 -------------
copied: 2021-11-07T01:30-06:00
copied.getZone(): -06:00
copied.getOffset(): -06:00
Ví dụ:
ZonedDateTime_withFixedOffsetZone_ex2.java
package org.o7planning.zoneddatetime.ex;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class ZonedDateTime_withFixedOffsetZone_ex2 {

    public static void main(String[] args) {
        LocalDateTime localDateTime = LocalDateTime.of(2021, 11, 7, 1, 30, 00);
        ZoneId zoneId = ZoneId.of("Asia/Ho_Chi_Minh");

        ZonedDateTime origin = ZonedDateTime.of(localDateTime, zoneId);

        System.out.println("origin: " + origin);
        System.out.println("origin.getZone(): " + origin.getZone());
        System.out.println("origin.getOffset(): " + origin.getOffset());

        System.out.println(" ------------- ");

        // apply withFixedOffsetZone()
        ZonedDateTime copied = origin.withFixedOffsetZone();

        System.out.println("copied: " + copied);
        System.out.println("copied.getZone(): " + copied.getZone());
        System.out.println("copied.getOffset(): " + copied.getOffset());
    }
}
Output:
origin: 2021-11-07T01:30+07:00[Asia/Ho_Chi_Minh]
origin.getZone(): Asia/Ho_Chi_Minh
origin.getOffset(): +07:00
 -------------
copied: 2021-11-07T01:30+07:00
copied.getZone(): +07:00
copied.getOffset(): +07:00