openplanning

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

  1. ZoneId
  2. Type1: Region-based ZoneId
  3. Type2: Offset-based ZoneId
  4. Type3: UTC, GMT, UT ZoneId
  5. ZoneId methods
  6. systemDefault()
  7. of(String)
  8. of(String, Map<String, String>)
  9. ofOffset(String, ZoneOffset)
  10. from(TemporalAccessor)
  11. getAvailableZoneIds()
  12. getRules()
  13. normalized()

1. ZoneId

Lớp ZoneId được sử dụng để định danh một múi giờ và cung cấp các quy tắc chuyển đổi giữa LocalDateTimeInstant. Về mặt quy tắc độ lệch (offset rules), ZoneId được chia làm 2 loại:
  • ZoneId với độ lệch múi giờ (time zone offset) cố định, chẳng hạn "UTC+07", "GMT-05:40", "UT-03", "+05:50".
  • ZoneId với độ lệch múi giờ không cố định, chẳng hạn "Europe/Paris", độ lệch múi giờ của nó phụ thuộc vào thời điểm trên dòng thời gian hoặc phụ thuộc vào ngày trong năm.
Ví dụ: ZoneId.of("Asia/Ho_Chi_Minh") là định danh múi giờ của miền nam Việt Nam. Trong giai đoạn từ năm 1960 đến trước ngày 13 tháng 6 năm 1975 độ lệch múi giờ của ZoneId này là +8, nhưng sau chuyển thành +7 để thống nhất với miền bắc Việt Nam.
ZoneId
public abstract class ZoneId implements Serializable {
     public abstract String getId();  
     public abstract ZoneRules getRules();
     ...
}
Mặc dù ZoneId là một lớp trừu tượng, nhưng nó cung cấp một vài phương thức nhà máy tĩnh để tạo ra các đối tượng ZoneId. Hai property quan trọng của ZoneIdidrules.
  • String id: ID là duy nhất.
  • ZoneRules rules: Là các quy tắc để xác định độ lệch múi giờ (time zone offset) tại một thời điểm cụ thể trên dòng thời gian.
Lớp ZoneOffset là một lớp con của ZoneId.
Dựa vào cú pháp của ID, ZoneId được chia làm 3 loại:
Type
Example
getId()
Type1
Region-based ZoneId
ZoneId.of("Europe/Paris")
Europe/Paris
Type2
Offset-based ZoneId
ZoneOffset.of("-06")
-06
Type2
Offset-based ZoneId
ZoneOffset.of("+06:05:20")
+06:05:20
Type3
UTC/GMT/UT ZoneId
ZoneId.ofOffset("UTC", ZoneOffset.of("+06"))
UTC+06
Type3
UTC/GMT/UT ZoneId
ZoneId.of("GMT-06:05:20")
GMT-06:05:20

2. Type1: Region-based ZoneId

Region-based ZoneId (ZonedId dựa trên khu vực), giá trị của tham số zoneId phải có 2 ký tự trở lên, và không được bắt đầu bằng "UTC", "GMT", "UT", "+", "-". Có rất nhiều giá trị đã được cung cấp sẵn, chẳng hạn "Europe/Paris", "Asia/Ho_Chi_Minh",... Phương thức tĩnh ZoneId.getAvailableZoneIds() trả về một tập hợp bao gồm các zoneId đó.
public static ZoneId of(String zoneId)
Bạn cũng có thể định nghĩa một khu vực địa lý và cung cấp các quy tắc cho nó thông qua ZoneRulesProvider.
  • Hướng dẫn và ví dụ Java ZoneRulesProvider
Ví dụ:
ZoneId_region_based_ex1.java
ZoneId zoneId1 = ZoneId.of("Europe/Paris");  
ZoneId zoneId2 = ZoneId.of("Asia/Ho_Chi_Minh");  

System.out.println(zoneId1.getId()); // Europe/Paris
System.out.println(zoneId2.getId()); // Asia/Ho_Chi_Minh

// Show format of Zoned Date Time
ZonedDateTime zonedDateTime = ZonedDateTime.of(2021, 6, 22, 0, 0, 0, 0, zoneId2);
System.out.println("zonedDateTime: " + zonedDateTime); // 2021-06-22T00:00+07:00[Asia/Ho_Chi_Minh]
Region-based ZoneId chứa các dữ liệu lịch sử về độ lệch múi giờ. Hãy xem một tình huống:
Ngày 1 tháng 1 năm 1986, chính quyền Nepal đã công bố múi giờ của mình là +5h45 GMT. Điều đó đồng nghĩa với việc họ đang nhanh hơn nước láng giềng Ấn Độ 15 phút. Động thái này nhằm tạo ra sự khác biệt với người hàng xóm khổng lồ và thể hiện sự tự hào dân tộc của người Nepal.
ID múi giờ của Nepal là "Asia/Kathmandu", ví dụ dưới đây cho thấy ZoneId.of("Asia/Kathmandu") đã chứa các dữ liệu lịch sử:
ZoneId_nepal_ex1.java
package org.o7planning.zoneid.type.ex;

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

public class ZoneId_nepal_ex1 {

    public static void main(String[] args) {
        ZoneId nepalZoneId = ZoneId.of("Asia/Kathmandu");

        ZonedDateTime zdt1 = ZonedDateTime.of(1985, 12, 30, 0, 0, 0, 0, nepalZoneId);
        System.out.println(zdt1); // 1985-12-30T00:00+05:30[Asia/Kathmandu]

        System.out.println();

        ZonedDateTime zdt2 = ZonedDateTime.of(1986, 1, 1, 0, 0, 0, 0, nepalZoneId);
        System.out.println(zdt2); // 1986-01-01T00:15+05:45[Asia/Kathmandu]
    }
}
Output:
1985-12-30T00:00+05:30[Asia/Kathmandu]

1986-01-01T00:15+05:45[Asia/Kathmandu]
Tiếp tục với ví dụ trên, chúng ta xem thông tin độ lệch múi giờ từ RoleRules:
ZoneId_nepal_ex2.java
ZoneId nepalZoneId = ZoneId.of("Asia/Kathmandu");

ZoneRules rules = nepalZoneId.getRules();

LocalDateTime ldt1 = LocalDateTime.of(1985, 12, 30, 0, 0, 0, 0);
ZoneOffset offset1 = rules.getOffset(ldt1);
System.out.println(offset1); // +05:30

LocalDateTime ldt2 = LocalDateTime.of(1986, 1, 1, 0, 15, 0, 0);
ZoneOffset offset2 = rules.getOffset(ldt2);  
System.out.println(offset2); // +05:45

3. Type2: Offset-based ZoneId

// Static method of ZoneOffset class.
public static ZoneOffset of(String offsetId)

public static ZoneOffset ofHours(int hours)  
public static ZoneOffset ofHoursMinutes(int hours, int minutes)  
public static ZoneOffset ofHoursMinutesSeconds(int hours, int minutes, int seconds)
public static ZoneOffset ofTotalSeconds(int totalSeconds)
Offset-based ZoneId (ZoneId dựa trên độ lệch múi giờ): Các ID múi giờ này bắt đầu bởi "+" hoặc "-". Tham số offsetId phải có định dạng như sau:
  • Z - for UTC
  • +h
  • +hh
  • +hh:mm
  • -hh:mm
  • +hhmm
  • -hhmm
  • +hh:mm:ss
  • -hh:mm:ss
  • +hhmmss
  • -hhmmss
Ví dụ:
ZoneId_offset_based_ex1.java
ZoneId zoneId1 = ZoneOffset.of("-06");
ZoneId zoneId2 = ZoneOffset.of("+06:05:20");
ZoneId zoneId3 = ZoneOffset.ofHoursMinutes(9, 45);

System.out.println(zoneId1.getId()); // -06:00
System.out.println(zoneId2.getId()); // +06:05:20
System.out.println(zoneId3.getId()); // +09:45

// Show format of Zoned Date Time:
ZonedDateTime zonedDateTime = ZonedDateTime.of(2021, 6, 22, 0, 0, 0, 0, zoneId2);
System.out.println("zonedDateTime: " + zonedDateTime); // 2021-06-22T00:00+06:05:20
Độ lệch múi giờ của chúng là cố định:
ZoneId_offset_based_ex2.java
ZoneId zoneId = ZoneOffset.of("+07:05:30");

System.out.println(zoneId.getId()); // +07:05:30

ZoneRules zoneRules = zoneId.getRules();
ZoneOffset zoneOffset = zoneRules.getOffset(Instant.now());
System.out.println("zoneOffset: " + zoneOffset.getId()); // +07:05:30

4. Type3: UTC, GMT, UT ZoneId

UTC, GMT, UT ZoneId: Các ID múi giờ loại này bắt đầu bởi "UTC", "GMT" hoặc "UT" tiếp sau đó là "+" hoặc "-".
public static ZoneId ofOffset(String prefix, ZoneOffset offset)

public static ZoneId of(String zoneId)
Ví dụ:
ZoneId_gmt_utc_ut_ex1.java
ZoneId z31 = ZoneId.ofOffset("UTC", ZoneOffset.of("+06"));
ZoneId z32 = ZoneId.ofOffset("GMT", ZoneOffset.of("-06:05:20"));
ZoneId z33 = ZoneId.ofOffset("UT", ZoneOffset.of("+05:20"));

System.out.println(z31.getId()); // UTC+06:00
System.out.println(z32.getId()); // GMT-06:05:20
System.out.println(z33.getId()); // UT+05:20   

// Parser:
ZoneId z31b = ZoneId.of("UTC+06:00");
ZoneId z32b = ZoneId.of("GMT-06:05:20");
ZoneId z33b = ZoneId.of("UT+05:20");

System.out.println(z31b.getId()); // UTC+06:00
System.out.println(z32b.getId()); // GMT-06:05:20
System.out.println(z33b.getId()); // UT+05:20
Output:
UTC+06:00
GMT-06:05:20
UT+05:20
UTC+06:00
GMT-06:05:20
UT+05:20
Các ID múi giờ UTC, GMT, UT có độ lệch múi giờ cố định.
ZoneId_gmt_utc_ut_ex2.java
ZoneId zoneId = ZoneId.ofOffset("GMT", ZoneOffset.of("+09"));
System.out.println(zoneId); // GMT+09:00

ZoneRules zoneRules = zoneId.getRules();
System.out.println("isFixedOffset? " + zoneRules.isFixedOffset()); // true

ZoneOffset zoneOffset = zoneRules.getOffset(Instant.now());
System.out.println("zoneOffset: " + zoneOffset); // +09:00

// Show format of Zoned Date Time.
ZonedDateTime zonedDateTime = ZonedDateTime.of(2021, 6, 22, 0, 0, 0, 0, zoneId);
System.out.println("zonedDateTime: " + zonedDateTime); // 2021-06-22T00:00+09:00[GMT+09:00]
Output:
GMT+09:00
isFixedOffset? true
zoneOffset: +09:00
zonedDateTime: 2021-06-22T00:00+09:00[GMT+09:00]

5. ZoneId methods

Các phương thức nhà máy tính (static factory method):
public static ZoneId systemDefault()    
public static ZoneId from(TemporalAccessor temporal)  
public static ZoneId of(String zoneId, Map<String, String> aliasMap)  
public static ZoneId of(String zoneId)  
public static ZoneId ofOffset(String prefix, ZoneOffset offset)
Các phương thức khác:
public static Set<String> getAvailableZoneIds()  
public abstract String getId()  
public String getDisplayName(TextStyle style, Locale locale)  
public abstract ZoneRules getRules();
public ZoneId normalized()

6. systemDefault()

Trả về múi giờ mặc định của hệ thống. Trên các hệ điều hành như Windows, Linux, Mac OS đều cho phép bạn thay đổi múi giờ mặc định.
public static ZoneId systemDefault()
Phương thức này gọi đến phương thức TimeZone.getDefault() và chuyển đổi kết quả thành ZoneId. Nếu múi giờ của hệ thống thay đổi, kết quả trả về của phương thức này cũng thay đổi.
Ví dụ:
ZoneId zoneId = ZoneId.systemDefault();

System.out.println(zoneId);
Output:
Asia/Bishkek

7. of(String)

Trả về một đối tượng ZoneId bằng cách tìm kiếm một ZoneId sẵn có trong hệ thống tương ứng với chuỗi zoneId đã cho, nếu không tìm thấy nó sẽ phân tích cú pháp của chuỗi zoneId để tạo ra một đối tượng ZoneOffset (Chú ý: ZoneOffset là một lớp con của ZoneId).
public static ZoneId of(String zoneId)
Case 1:
Các ZoneId được định nghĩa sẵn trong hệ thống liên quan tới một vùng địa lý cụ thể. Bạn có thể có được tập hợp các ZoneId này từ phương thức ZoneId.getAvailableZoneIds().
  • Asia/Bishkek
  • Europe/Paris
  • ...
ZoneId_of_ex1.java
// ZoneId from region ID
ZoneId zoneId1 = ZoneId.of("Europe/Paris");
System.out.println("zoneId1: " + zoneId1); // Europe/Paris

ZoneId zoneId2 = ZoneId.of("America/Chicago");
System.out.println("zoneId2: " + zoneId2); // America/Chicago
Case 2:
Nếu tham số zoneId bằng "Z", kết quả trả về là ZoneOffset.UTC. Ngược lại, nếu tham số zoneId chỉ là một ký tự và khác "Z" thì nó được coi là không hợp lệ và DateTimeException sẽ được ném ra.
ZoneId_of_ex2.java
ZoneId zoneId = ZoneId.of("Z"); // return ZoneOffset.UTC
System.out.println("ZoneId.of('Z'): " + zoneId); // Z
System.out.println("ZoneOffset.UTC: " + ZoneOffset.UTC); // Z

boolean same = zoneId == ZoneOffset.UTC;  
System.out.println("ZoneId.of('Z') == ZoneOffset.UTC? " + same); // true
Case 3:
Nếu tham số zoneId bắt đầu bởi "+" hoặc "-" thì nó sẽ được phân tích như một ZoneOffset bởi phương thức ZoneOffset.of(zoneId).
ZoneId_of_ex3.java
ZoneId zoneId = ZoneId.of("+09:30");
ZoneOffset zoneOffset1 = (ZoneOffset) zoneId;

// Same as:
ZoneOffset zoneOffset2 = ZoneOffset.of("+09:30");

System.out.println("zoneId: " + zoneId); // +09:30
System.out.println("zoneOffset: " + zoneOffset2); // +09:30
System.out.println("zoneOffset1.equals(zoneOffset2)? " + zoneOffset1.equals(zoneOffset2)); // true
Case 4:
Nếu tham số zoneId"UTC", "GMT" hoặc "UT", phương thức sẽ trả về đối tượng một đối tượng ZoneId có cùng ZoneRules với ZoneOffset.UTC.
ZoneId_of_ex4.java
ZoneId zoneId = ZoneOffset.UTC;

ZoneId zoneId1 = ZoneId.of("UTC");
ZoneId zoneId2 = ZoneId.of("GMT");
ZoneId zoneId3 = ZoneId.of("UT");

// Print out Zone-ID
System.out.println(zoneId.getId());  // Z
System.out.println(zoneId1.getId()); // UTC
System.out.println(zoneId2.getId()); // GMT
System.out.println(zoneId3.getId()); // UT

ZoneRules rules = zoneId.getRules();
ZoneRules rules1 = zoneId1.getRules();
ZoneRules rules2 = zoneId2.getRules();
ZoneRules rules3 = zoneId3.getRules();

System.out.println(rules);  // ZoneRules[currentStandardOffset=Z]
System.out.println(rules1); // ZoneRules[currentStandardOffset=Z]
System.out.println(rules2); // ZoneRules[currentStandardOffset=Z]
System.out.println(rules3); // ZoneRules[currentStandardOffset=Z]

System.out.println("rules1.equals(rules): " + rules1.equals(rules)); // true
System.out.println("rules2.equals(rules): " + rules2.equals(rules)); // true
System.out.println("rules3.equals(rules): " + rules3.equals(rules)); // true
Case 5:
Nếu tham số zoneId bắt đầu bởi "UTC+", "UTC-", "GMT+", "GMT-", "UT+", "UT-" thì một đối tượng ZoneId sẽ được trả về. Chẳng hạn, tham số zoneId bằng "GMT+09:30" sẽ tương đương với ZoneId.ofOffset("GMT",ZoneOffset.of("+09:30")).
ZoneId_of_ex5.java
// UTC
ZoneId zoneId1a = ZoneId.of("UTC+09:30");
ZoneId zoneId1b = ZoneId.ofOffset("UTC", ZoneOffset.of("+09:30"));
ZoneId zoneId1c = ZoneId.ofOffset("UTC", ZoneOffset.ofHoursMinutes(9, 30));
System.out.println(zoneId1a); // UTC+09:30
System.out.println(zoneId1b); // UTC+09:30
System.out.println(zoneId1c); // UTC+09:30

// GMT
ZoneId zoneId2a = ZoneId.of("GMT+05:30:20");
ZoneId zoneId2b = ZoneId.ofOffset("GMT", ZoneOffset.of("+05:30:20"));
ZoneId zoneId2c = ZoneId.ofOffset("GMT", ZoneOffset.ofHoursMinutesSeconds(5, 30, 20));
System.out.println(zoneId2a); // GMT+05:30:20
System.out.println(zoneId2b); // GMT+05:30:20
System.out.println(zoneId2c); // GMT+05:30:20

// UT
ZoneId zoneId3a = ZoneId.of("UT-07");
ZoneId zoneId3b = ZoneId.ofOffset("UT", ZoneOffset.of("-07"));
ZoneId zoneId3c = ZoneId.ofOffset("UT", ZoneOffset.ofHours(-7));
System.out.println(zoneId3a); // UT-07:00
System.out.println(zoneId3b); // UT-07:00
System.out.println(zoneId3c); // UT-07:00

8. of(String, Map<String, String>)

public static ZoneId of(String zoneId, Map<String, String> aliasMap)
Ví dụ:
ZoneId_of_aliasMap_ex1.java
package org.o7planning.zoneid.fm;

import java.time.ZoneId;
import java.util.HashMap;
import java.util.Map;

public class ZoneId_of_aliasMap_ex1 {

    public static void main(String[] args) {
        // Alias IDs:
        Map<String, String> aliasMap = new HashMap<>();
        aliasMap.put("hcm", "Asia/Ho_Chi_Minh");
        aliasMap.put("usc", "US/Central");
        aliasMap.put("prs", "Europe/Paris");

        ZoneId frZoneId = ZoneId.of("prs", aliasMap);
        ZoneId vnZoneId = ZoneId.of("hcm", aliasMap);
        ZoneId usZoneId = ZoneId.of("US/Central", aliasMap);
        ZoneId jpZoneId = ZoneId.of("Asia/Tokyo", aliasMap);
        ZoneId os9ZoneId = ZoneId.of("+09", aliasMap);

        System.out.println(frZoneId); // Europe/Paris
        System.out.println(vnZoneId); // Asia/Ho_Chi_Minh
        System.out.println(usZoneId); // US/Central
        System.out.println(jpZoneId); // Asia/Tokyo
        System.out.println(os9ZoneId); // +09:00

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

        // throws ZoneRulesException - Unknown time-zone ID: xx
        ZoneId xxZoneId = ZoneId.of("xx", aliasMap); // throws ZoneRulesException

        System.out.println(xxZoneId);
    }
}
Output:
Europe/Paris
Asia/Ho_Chi_Minh
US/Central
Asia/Tokyo
+09:00
 ------
Exception in thread "main" java.time.zone.ZoneRulesException: Unknown time-zone ID: xx
    at java.base/java.time.zone.ZoneRulesProvider.getProvider(ZoneRulesProvider.java:279)
    at java.base/java.time.zone.ZoneRulesProvider.getRules(ZoneRulesProvider.java:234)
    at java.base/java.time.ZoneRegion.ofId(ZoneRegion.java:120)
    at java.base/java.time.ZoneId.of(ZoneId.java:408)
    at java.base/java.time.ZoneId.of(ZoneId.java:356)
    at java.base/java.time.ZoneId.of(ZoneId.java:312)
    at org.o7planning.zoneid.fm.ZoneId_of_aliasMap_ex1.main(ZoneId_of_aliasMap_ex1.java:31)
ZoneId_of_aliasMap_ex2.java
package org.o7planning.zoneid.fm;

import java.time.ZoneId;
import java.util.Map;

public class ZoneId_of_aliasMap_ex2 {

    public static void main(String[] args) {
        // Alias IDs:
        Map<String, String> aliasMap = ZoneId.SHORT_IDS;

        aliasMap.forEach((k, v) -> System.out.println(k + " --> " + v));

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

        ZoneId zoneId1 = ZoneId.of("JST", aliasMap);
        ZoneId zoneId2 = ZoneId.of("VST", aliasMap);  

        System.out.println(zoneId1); // Asia/Tokyo
        System.out.println(zoneId2); // Asia/Ho_Chi_Minh
    }
}
Output:
NET --> Asia/Yerevan
CST --> America/Chicago
IST --> Asia/Kolkata
AET --> Australia/Sydney
BST --> Asia/Dhaka
ACT --> Australia/Darwin
HST --> -10:00
NST --> Pacific/Auckland
AST --> America/Anchorage
MST --> -07:00
SST --> Pacific/Guadalcanal
CTT --> Asia/Shanghai
PRT --> America/Puerto_Rico
ECT --> Europe/Paris
EAT --> Africa/Addis_Ababa
EST --> -05:00
PNT --> America/Phoenix
PLT --> Asia/Karachi
CNT --> America/St_Johns
IET --> America/Indiana/Indianapolis
VST --> Asia/Ho_Chi_Minh
JST --> Asia/Tokyo
ART --> Africa/Cairo
PST --> America/Los_Angeles
BET --> America/Sao_Paulo
MIT --> Pacific/Apia
CAT --> Africa/Harare
AGT --> America/Argentina/Buenos_Aires
 ------
Asia/Tokyo
Asia/Ho_Chi_Minh

9. ofOffset(String, ZoneOffset)

Tham số prefix chỉ có thể nhận một trong 4 giá trị: "UTC", "GMT", "UT", "".
public static ZoneId ofOffset(String prefix, ZoneOffset offset)
Ví dụ:
ZoneId_ofOffset_ex1.java
ZoneId zoneId1 = ZoneId.ofOffset("UTC", ZoneOffset.ofHours(9));
ZoneId zoneId2 = ZoneId.ofOffset("GMT", ZoneOffset.ofHoursMinutes(9, 30));
ZoneId zoneId3 = ZoneId.ofOffset("UT", ZoneOffset.ofHours(-7));

ZoneId zoneId4 = ZoneId.ofOffset("", ZoneOffset.ofHours(-5)); // Can cast to ZoneOffset

System.out.println(zoneId1); // UTC+09:00
System.out.println(zoneId2); // GMT+09:30
System.out.println(zoneId3); // UT-07:00
System.out.println(zoneId4); // -05:00

10. from(TemporalAccessor)

Trả về đối tượng ZoneId liên hợp với đối tượng TemporalAccessor đã cho.
public static ZoneId from(TemporalAccessor temporal)
Ví dụ:
ZoneId_from_ex1.java
package org.o7planning.zoneid.fm;

import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.TemporalAccessor;

public class ZoneId_from_ex1 {

    public static void main(String[] args) {
        // Obtains the current date-time from the system clock in the default time-zone.
        TemporalAccessor temporalAccessor = ZonedDateTime.now();
        System.out.println("ZonedDateTime: " + temporalAccessor);

        ZoneId zoneId = ZoneId.from(temporalAccessor);
        System.out.println("zoneId: " + zoneId);
    }
}
Output:
ZonedDateTime: 2021-06-24T21:34:23.518679+06:00[Asia/Bishkek]
zoneId: Asia/Bishkek

11. getAvailableZoneIds()

Trả về một Set<String> chứa tất cả các ID múi giờ sẵn có trong hệ thống, số phần tử của nó có thể tăng theo thời gian, tuy nhiên trong các ứng dụng thông thường nó thường có kích thước cố định. Phương thức này an toàn theo luồng (thread-safe).
  • Bao gồm tất cả Region-based ZoneId.
  • Không bao gồm Offset-based ZoneId.
public static Set<String> getAvailableZoneIds()
Ví dụ:
ZoneId_getAvailableZoneIds_ex1.java
package org.o7planning.zoneid.ex;

import java.time.ZoneId;
import java.util.Set;

public class ZoneId_getAvailableZoneIds_ex1 {

    public static void main(String[] args) {
        Set<String> zoneIds = ZoneId.getAvailableZoneIds();

        for (String zoneId : zoneIds) {
           System.out.println(zoneId);
        }
    }
}
Output:
Asia/Aden
America/Cuiaba
...
America/Sao_Paulo
Asia/Jayapura
America/Curacao
Asia/Dushanbe
America/Guyana
...
UTC
...
GMT0
...
Europe/Nicosia
Pacific/Guadalcanal
Europe/Athens
US/Pacific
Europe/Monaco

12. getRules()

Trả về đối tượng ZoneRules đại diện cho các quy tắc múi giờ (time-zone rules) của ZoneId này.
public abstract ZoneRules getRules()
Độ lệch múi giờ trong ZoneRules thu được từ một Region-based ZoneId là không cố định. Nó phụ thuộc vào thời điểm cụ thể hoặc phù thuộc vào thời gian trong năm.
Ví dụ: ZoneId.of("Asia/Ho_Chi_Minh") là múi giờ của miền nam Việt Nam. Từ năm 1960 tới trước ngày 13 tháng 6 năm 1975, ZoneId này sử dụng múi giờ +8, sau đó chuyển sang múi giờ +7 để thống nhất với miền bắc Việt Nam.
ZoneId_getRules_ex1.java
package org.o7planning.zoneid.ex;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.zone.ZoneRules;

public class ZoneId_getRules_ex1 {

    public static void main(String[] args) {
        ZoneId zoneId = ZoneId.of("Asia/Ho_Chi_Minh");
        ZoneRules zoneRules = zoneId.getRules();
        
        ZoneOffset zoneOffset1 = zoneRules.getOffset(LocalDateTime.of(1975, 6, 12, 0, 0, 0));
        ZoneOffset zoneOffset2 = zoneRules.getOffset(LocalDateTime.of(1975, 6, 13, 0, 0, 0));
        
        System.out.println("zoneOffset1: " + zoneOffset1); // +08:00
        System.out.println("zoneOffset2: " + zoneOffset2); // +07:00
    }
}
Output:
zoneOffset1: +08:00
zoneOffset2: +07:00
Bạn cũng có thể tạo ra một ZoneId với các quy tắc múi giờ tuỳ biến thông qua ZoneRulesProvider:
  • ZoneRulesProvider
  • ZoneRules

13. normalized()

Phương thức normalized() trả về một ZoneId đã được chuẩn hoá (normalized). Về cơ bản, nó sẽ kiểm tra xem độ lệch múi giờ của ZoneId này cố định hay không. Nếu cố định ZoneOffset sẽ được trả về, ngược lại nó trả về ZoneId này.
public ZoneId normalized()
Ví dụ:
ZoneId_normalized_ex1.java
package org.o7planning.zoneid.ex;

import java.time.ZoneId;

public class ZoneId_normalized_ex1 {

    public static void main(String[] args) {
        ZoneId zoneId1 = ZoneId.of("US/Central");
        System.out.println("zoneId1: " + zoneId1); // US/Central
        System.out.println("zoneId1.normalized(): " + zoneId1.normalized()); // US/Central

        ZoneId zoneId2 = ZoneId.of("Asia/Tokyo");
        System.out.println("\nzoneId2: " + zoneId2); // Asia/Tokyo
        System.out.println("zoneId2.normalized(): " + zoneId2.normalized()); // Asia/Tokyo

        ZoneId zoneId3 = ZoneId.of("UTC-09:30");
        System.out.println("\nzoneId3: " + zoneId3); // UTC-09:30
        System.out.println("zoneId3.normalized(): " + zoneId3.normalized()); // -09:30
    }
}
Output:
zoneId1: US/Central
zoneId1.normalized(): US/Central

zoneId2: Asia/Tokyo
zoneId2.normalized(): Asia/Tokyo

zoneId3: UTC-09:30
zoneId3.normalized(): -09:30