Lớp java.time.ZoneId

Lớp ZoneId trong gói java.time của Java được sử dụng để định danh (ID) biểu thị múi giờ, ví dụ như "Europe/Paris". Nó được sử dụng để xác định quy tắc chuyển đổi giữa thời điểm (Instant) và ngày giờ địa phương (LocalDateTime). Có hai loại định danh múi giờ chính:

↳ Độ lệch cố định (Fixed offsets): Là sự chênh lệch cố định so với Giờ Phối hợp Quốc tế (UTC/Greenwich). Múi giờ này có cùng độ lệch cho tất cả các ngày giờ địa phương.

↳ Vùng địa lý (Geographical regions): Là một khu vực áp dụng bộ quy tắc cụ thể để xác định độ lệch giờ so với UTC/Greenwich.

Mỗi định danh múi giờ (ID) là duy nhất trong hệ thống và có ba loại chính:

↳ Độ lệch cố định (ZoneOffset): Kiểu ID đơn giản nhất, bắt đầu bằng ký tự 'Z' hoặc dấu '+' hoặc '-'. Ví dụ: 'Z', '+05:30', '-08:00'.

↳ Kiểu offset với tiền tố (Offset-style IDs):Loại ID này có dạng giống độ lệch cố định nhưng đi kèm với một tiền tố như 'GMT', 'UTC' hoặc 'UT'. Ví dụ: 'GMT+02:00', 'UTC+01:00'. Các tiền tố được công nhận là 'UTC', 'GMT' và 'UT'. Phần sau dấu '+' hoặc '-' là độ lệch giờ và sẽ được chuẩn hóa trong quá trình tạo. Bạn có thể chuyển đổi các ID này sang ZoneOffset bằng phương thức normalized().

↳ ID dựa trên vùng (Region-based IDs): Là ID đại diện cho một vùng địa lý cụ thể, có độ dài ít nhất 2 ký tự và không bắt đầu bằng 'UTC', 'GMT', 'UT', '+' hoặc '-'. Các ID theo vùng được xác định bởi cấu hình, xem ZoneRulesProvider. Cấu hình này tập trung vào việc cung cấp tra cứu từ ID đến các quy tắc (ZoneRules) chi phối múi giờ đó.

Ⅰ. Khai báo lớp ZoneId trong Java

Để sử dụng lớp ZoneId và các lớp khác trong gói java.time, bạn cần thêm câu lệnh import vào đầu file Java của mình.

Cú pháp câu lệnh import:

Cú pháp

import java.time.ZoneId;

Cú pháp khai báo lớp ZoneId:

Cú pháp

public abstract class ZoneId
extends Object
implements Serializable

Dưới đây là giải thích chi tiết về cú pháp khai báo này:

↳ public: Lớp này có thể được truy cập từ bất kỳ đâu trong chương trình, không bị giới hạn phạm vi.

↳ abstract: Lớp ZoneId là trừu tượng (abstract), tức là không thể tạo đối tượng trực tiếp từ lớp này. Nó chỉ có thể được kế thừa bởi các lớp con.

↳ class ZoneId: Khai báo một lớp có tên là ZoneId.

↳ extends Object: Tất cả các lớp trong Java đều kế thừa từ lớp Object (lớp gốc của tất cả các lớp trong Java). Việc này cho phép lớp ZoneId kế thừa các phương thức cơ bản từ Object, chẳng hạn như toString(), equals(), và hashCode().

↳ implements Serializable: Serializable là một interface cho phép các đối tượng của lớp ZoneId có thể được chuyển đổi thành chuỗi byte để lưu trữ hoặc truyền qua mạng. Điều này làm cho các đối tượng ZoneId có thể được ghi vào một luồng hoặc đọc từ một luồng mà không mất dữ liệu.

Ⅱ. Các phương thức của lớp ZoneId

Lớp ZoneId cung cấp nhiều phương thức để thao tác với định danh múi giờ. Việc phân nhóm các phương thức theo chức năng sẽ giúp bạn hiểu rõ hơn về cách sử dụng lớp ZoneId. Dưới đây là cách phân nhóm các phương thức phổ biến của lớp ZoneId:

Tạo đối tượng ZoneId

↳ of(String zoneId): Tạo một đối tượng ZoneId từ một chuỗi ID múi giờ.

↳ of(String zoneId, Map aliasMap): Tạo một ZoneId từ ID múi giờ, cho phép sử dụng bảng ánh xạ (map) để xử lý các tên gọi khác (alias) của múi giờ.

↳ ofOffset(String prefix, ZoneOffset offset): Tạo một ZoneId bao bọc một đối tượng ZoneOffset (độ lệch cố định).

↳ systemDefault(): Lấy múi giờ mặc định của hệ thống.

Dưới đây là ví dụ về cách sử dụng các phương thức để tạo đối tượng ZoneId trong một lớp Java. Ví dụ này sử dụng các phương thức of, of, ofOffset, và systemDefault:

Ví dụ: Example.java

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

public class Example {
    public static void main(String[] args) {
        // 1. Tạo ZoneId từ chuỗi ID múi giờ
        ZoneId zoneId1 = ZoneId.of("Europe/London");
        System.out.println("ZoneId từ chuỗi ID múi giờ: " + zoneId1);

        // 2. Tạo ZoneId từ chuỗi ID múi giờ với bảng ánh xạ (aliasMap)
        Map<String, String> aliasMap = new HashMap<>();
        aliasMap.put("LON", "Europe/London");
        ZoneId zoneId2 = ZoneId.of("LON", aliasMap);
        System.out.println("ZoneId từ chuỗi ID múi giờ với bảng ánh xạ: " + zoneId2);

        // 3. Tạo ZoneId từ độ lệch cố định
        ZoneOffset offset = ZoneOffset.ofHours(-5); // UTC-5
        ZoneId zoneId3 = ZoneId.ofOffset("UTC", offset);
        System.out.println("ZoneId từ độ lệch cố định: " + zoneId3);

        // 4. Lấy múi giờ mặc định của hệ thống
        ZoneId zoneId4 = ZoneId.systemDefault();
        System.out.println("Múi giờ mặc định của hệ thống: " + zoneId4);
    }
}

Kết quả của chương trình là:

ZoneId từ chuỗi ID múi giờ: Europe/London
ZoneId từ chuỗi ID múi giờ với bảng ánh xạ: Europe/London
ZoneId từ độ lệch cố định: UTC-05:00
Múi giờ mặc định của hệ thống: Asia/Saigon

Trong ví dụ trên, mỗi phương thức đều được sử dụng để tạo ra một đối tượng ZoneId khác nhau và in ra kết quả để bạn có thể thấy sự khác biệt trong cách chúng hoạt động.

Lấy thông tin múi giờ

↳ getDisplayName(TextStyle style, Locale locale): Lấy tên hiển thị của múi giờ theo phong cách (TextStyle) nhất định và ngôn ngữ (Locale) mong muốn.

↳ getId(): Lấy ID duy nhất của múi giờ.

↳ getAvailableZoneIds(): Lấy danh sách tất cả các ID múi giờ khả dụng.

↳ getRules(): Lấy các quy tắc của múi giờ cho phép thực hiện các tính toán liên quan đến chuyển đổi múi giờ.

Dưới đây là ví dụ về cách sử dụng các phương thức để lấy thông tin múi giờ trong một lớp Java. Ví dụ này sử dụng các phương thức getDisplayName, getId, getAvailableZoneIds, và getRules:

Ví dụ: Example.java

import java.time.ZoneId;
import java.time.format.TextStyle;
import java.time.zone.ZoneRules;
import java.util.Locale;
import java.util.Set;

public class Example {
    public static void main(String[] args) {
        // 1. Lấy ZoneId từ chuỗi ID múi giờ
        ZoneId zoneId = ZoneId.of("Europe/Paris");

        // 2. Lấy tên hiển thị của múi giờ theo phong cách và ngôn ngữ
        String displayName = zoneId.getDisplayName(TextStyle.FULL, Locale.ENGLISH);
        System.out.println("Tên hiển thị (Full) bằng tiếng Anh: " + displayName);

        // 3. Lấy ID duy nhất của múi giờ
        String id = zoneId.getId();
        System.out.println("ID của múi giờ: " + id);

        // 4. Lấy danh sách tất cả các ID múi giờ khả dụng
        Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
        System.out.println("Danh sách các ID múi giờ khả dụng:");
        availableZoneIds.forEach(System.out::println);

        // 5. Lấy các quy tắc của múi giờ
        ZoneRules rules = zoneId.getRules();
        System.out.println("Quy tắc của múi giờ: " + rules);
    }
}

Kết quả của chương trình là:

ID của múi giờ: Europe/Paris
Danh sách các ID múi giờ khả dụng:
Asia/Aden
America/Cuiaba
Etc/GMT+9
...
Europe/Monaco
Quy tắc của múi giờ: ZoneRules[currentStandardOffset=+01:00]

So sánh và kiểm tra

↳ equals(Object obj): Kiểm tra xem ZoneId này có bằng với ZoneId khác hay không.

↳ hashCode(): Trả về giá trị băm của ZoneId.

Dưới đây là ví dụ về cách sử dụng các phương thức equals, hashCode, và các phương thức so sánh khác của lớp ZoneId trong một lớp Java:

Ví dụ: Example.java

import java.time.ZoneId;

public class Example {
    public static void main(String[] args) {
        // Tạo hai ZoneId
        ZoneId zoneId1 = ZoneId.of("America/New_York");
        ZoneId zoneId2 = ZoneId.of("America/Los_Angeles");
        ZoneId zoneId3 = ZoneId.of("America/New_York");

        // So sánh hai ZoneId
        boolean isEqual = zoneId1.equals(zoneId3);
        System.out.println("zoneId1 và zoneId3 có bằng nhau không? " + isEqual);

        // So sánh hai ZoneId khác nhau
        boolean isDifferent = !zoneId1.equals(zoneId2);
        System.out.println("zoneId1 và zoneId2 có khác nhau không? " + isDifferent);

        // Lấy giá trị băm của ZoneId
        int hash1 = zoneId1.hashCode();
        int hash2 = zoneId2.hashCode();
        System.out.println("Giá trị băm của zoneId1: " + hash1);
        System.out.println("Giá trị băm của zoneId2: " + hash2);

    }
}

Kết quả của chương trình là:

zoneId1 và zoneId3 có bằng nhau không? true
zoneId1 và zoneId2 có khác nhau không? true
Giá trị băm của zoneId1: -1243098545
Giá trị băm của zoneId2: -1536188513

Trong ví dụ trên, các phương thức equals và hashCode được sử dụng để so sánh các đối tượng ZoneId và in ra giá trị băm của chúng, giúp bạn thấy cách các đối tượng ZoneId được so sánh và định danh khác nhau.

Chuyển đổi

↳ from(TemporalAccessor temporal): Lấy ZoneId từ một đối tượng thời gian khác (ví dụ như ZonedDateTime).

Dưới đây là ví dụ cho phương thức from của lớp ZoneId:

Ví dụ: Example.java

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

public class Example {
    public static void main(String[] args) {
        // Tạo một đối tượng ZonedDateTime
        ZonedDateTime zonedDateTime = ZonedDateTime.now();

        // Lấy ZoneId từ ZonedDateTime
        ZoneId zoneId = ZoneId.from(zonedDateTime);

        // In ra ZoneId
        System.out.println("ZoneId của khu vực: " + zoneId);
    }
}

Kết quả của chương trình là:

ZoneId của khu vực: Asia/Saigon

Trong ví dụ trên, phương thức from được sử dụng để lấy ZoneId từ một đối tượng ZonedDateTime, và kết quả được in ra để bạn thấy cách chuyển đổi giữa các đối tượng thời gian khác nhau.

Chuẩn hóa

↳ normalized(): Chuẩn hóa ZoneId - nếu có thể, trả về một ZoneOffset tương ứng (cho trường hợp ID là độ lệch cố định).

Dưới đây là ví dụ về phương thức normalized() của lớp ZoneId:

Ví dụ: Example.java

import java.time.ZoneId;

public class Example {
    public static void main(String[] args) {
        // Tạo các đối tượng ZoneId
        ZoneId zoneId1 = ZoneId.of("UTC");
        ZoneId zoneId2 = ZoneId.of("America/New_York");

        // Chuẩn hóa ZoneId
        ZoneId normalizedZoneId1 = zoneId1.normalized();
        ZoneId normalizedZoneId2 = zoneId2.normalized();

        // In kết quả
        System.out.println("ZoneId1 được chuẩn hóa: " + normalizedZoneId1); // UTC+00:00
        System.out.println("ZoneId2 được chuẩn hóa: " + normalizedZoneId2); // America/New_York (do không phải là độ lệch cố định)

        // So sánh ZoneId gốc và đã chuẩn hóa
        System.out.println("zoneId1 có bằng normalizedZoneId1 không?: " + zoneId1.equals(normalizedZoneId1)); 
        System.out.println("zoneId2 có bằng normalizedZoneId2 không?: " + zoneId2.equals(normalizedZoneId2)); // true hoặc false tùy thuộc vào việc chuẩn hóa
    }
}

Kết quả của chương trình là:

ZoneId1 được chuẩn hóa: Z
ZoneId2 được chuẩn hóa: America/New_York
zoneId1 có bằng normalizedZoneId1 không?: false
zoneId2 có bằng normalizedZoneId2 không?: true

Trong ví dụ trên, phương thức normalized() được sử dụng để chuẩn hóa các đối tượng ZoneId. Nếu ZoneId là một độ lệch cố định, phương thức này trả về ZoneOffset tương ứng. Nếu không, nó trả về chính ZoneId đó.

Hiển thị

↳ toString(): Trả về chuỗi thể hiện ZoneId này, thường dưới dạng ID múi giờ.

Dưới đây là ví dụ cho phương thức toString của lớp ZoneId:

Ví dụ: Example.java

import java.time.ZoneId;

public class Example {
    public static void main(String[] args) {
        // Tạo các đối tượng ZoneId
        ZoneId zoneId1 = ZoneId.of("America/New_York");
        ZoneId zoneId2 = ZoneId.of("Europe/London");
        ZoneId zoneId3 = ZoneId.of("Asia/Tokyo");

        // Hiển thị chuỗi của các ZoneId
        System.out.println("zoneId1.toString(): " + zoneId1.toString()); // America/New_York
        System.out.println("zoneId2.toString(): " + zoneId2.toString()); // Europe/London
        System.out.println("zoneId3.toString(): " + zoneId3.toString()); // Asia/Tokyo
    }
}

Kết quả của chương trình là:

zoneId1.toString(): America/New_York
zoneId2.toString(): Europe/London
zoneId3.toString(): Asia/Tokyo

Trong ví dụ trên, phương thức toString được sử dụng để hiển thị ID của các đối tượng ZoneId, cho phép bạn dễ dàng xem và xác nhận định danh của từng múi giờ.

Các ngoại lệ thường gặp khi sử dụng lớp ZoneId trong Java

Dưới đây là các ngoại lệ thường gặp và nguyên nhân của chúng:

Ngoại lệ DateTimeException

↳ Nguyên nhân: Khi tạo một đối tượng ZoneId từ một ID múi giờ không hợp lệ hoặc không tồn tại.

↳ Ví dụ: Thử tạo một ZoneId với chuỗi "Invalid/Zone" sẽ gây ra ngoại lệ này.

Ngoại lệ ZoneRulesException

↳ Nguyên nhân: Khi ZoneId yêu cầu các quy tắc múi giờ không hợp lệ hoặc không thể tìm thấy.

↳ Ví dụ: Khi ZoneId không thể tra cứu các quy tắc chuyển đổi cho một múi giờ nào đó, chẳng hạn như "GMT+1000".

Ngoại lệ IllegalArgumentException

↳ Nguyên nhân: Khi cung cấp một chuỗi không hợp lệ cho phương thức ZoneId.of(String zoneId).

↳ Ví dụ: Cung cấp một chuỗi rỗng hoặc một chuỗi không đúng định dạng, chẳng hạn như "InvalidZone".

Lưu ý:

Khi làm việc với ZoneId, việc kiểm tra dữ liệu đầu vào và các thao tác múi giờ là rất quan trọng để tránh các ngoại lệ. Sử dụng các phương thức kiểm tra và xử lý ngoại lệ như try-catch để cung cấp thông báo lỗi hoặc xử lý các tình huống bất thường giúp ứng dụng của bạn ổn định và dễ duy trì hơn.

Câu Nói Truyền Cảm Hứng

“Bắt đầu ở đâu không quan trọng, quan trọng là bạn sẵn sàng bắt đầu.” – W. Clement Stone

Không Gian Tích Cực

“Chúc bạn luôn giữ vững niềm tin và sức mạnh để vượt qua mọi thử thách trong cuộc sống.”