openplanning

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

  1. ZoneOffset
  2. ZoneOffset methods
  3. of(String offsetId)
  4. ofX(..)
  5. from(TemporalAccessor)
  6. getRules()
  7. isSupported(TemporalField)
  8. get(TemporalField)
  9. getLong(TemporalField)
  10. range(TemporalField)
  11. query(TemporalQuery<R>)
  12. adjustInto(Temporal)

1. ZoneOffset

ZoneOffset là một lớp mở rộng từ lớp ZoneId, được sử dụng để tạo ra một định danh múi giờ (time zone ID) với độ lệch múi giờ (time zone offset) cố định, chẳng hạn +02:00.
public final class ZoneOffset
        extends ZoneId
        implements TemporalAccessor, TemporalAdjuster, Comparable<ZoneOffset>, Serializable
Nếu bạn muốn tạo ra một định danh múi giờ dựa trên tên của khu vực địa lý hãy sử dụng lớp ZoneId, trường hợp này độ lệch múi giờ có thể không cố định, nó phụ thuộc vào thời điểm cụ thể trên dòng thời gian hoặc phụ thuộc vào thời gian trong năm.
Trong Java, phạm vi của độ lệch múi giờ hợp lệ là từ -18:00 đến 18:00. Thực tế, cho đến năm 2008 các độ chênh lệch múi giờ đã được đăng ký trên thế giới chỉ nằm trong phạm vi từ -12:00 đến +14:00. Có thể bạn sẽ đặt ra câu hỏi "Tại sao độ lệch múi giờ có thể nằm ngoài phạm vi từ -11 đến 12?", điều này có thể được giải thích nếu bạn hiểu về "Giờ tiết kiệm ánh sáng ban ngày" (Daylight Saving Time - DST).
Lớp ZoneOffset là bất biến (immutable) vì vậy nó an toàn khi sử dụng trong môi trường Multithreading, khi so sánh các đối tượng ZoneOffset với nhau nên sử dụng phương thức equals(Object), nếu bạn sử dụng toán tử == hoặc sử dụng với IdentityHashMap có thể dẫn đến các kết quả không như mong đợi.

2. ZoneOffset methods

private static final int MAX_SECONDS = 18 * SECONDS_PER_HOUR;

public static final ZoneOffset UTC = ZoneOffset.ofTotalSeconds(0);
public static final ZoneOffset MIN = ZoneOffset.ofTotalSeconds(-MAX_SECONDS);
public static final ZoneOffset MAX = ZoneOffset.ofTotalSeconds(MAX_SECONDS);

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)  

public static ZoneOffset from(TemporalAccessor temporal)
public int getTotalSeconds()  

// Inherited from ZoneId class
public String getId()  

// Inherited from ZoneId class
public ZoneRules getRules()  

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

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

// Inherited from TemporalAccessor interface
public int get(TemporalField field)  

// Inherited from TemporalAccessor interface
public long getLong(TemporalField field)  

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

// Inherited from TemporalAdjuster interface
public Temporal adjustInto(Temporal temporal)

3. of(String offsetId)

Trả về một đối tượng ZoneOffset bằng cách phân tích chuỗi offsetId đã cho.
public static ZoneOffset of(String offsetId)
Chuỗi offsetId phải là một trong các định dạng dưới đây:
  • Z - for UTC
  • +h
  • +hh
  • +hh:mm
  • -hh:mm
  • +hhmm
  • -hhmm
  • +hh:mm:ss
  • -hh:mm:ss
  • +hhmmss
  • -hhmmss
Ví dụ:
ZoneOffset_of_ex1.java
package org.o7planning.zoneoffset.ex;

import java.time.ZoneOffset;
import java.time.ZonedDateTime;

public class ZoneOffset_of_ex1 {

    public static void main(String[] args) {
        ZoneOffset zoneId1 = ZoneOffset.of("-06");
        ZoneOffset zoneId2 = ZoneOffset.of("+06:05:20");
        ZoneOffset zoneId3 = ZoneOffset.of("+0930");
        
        System.out.println(zoneId1); // -06:00
        System.out.println(zoneId2); // +06:05:20
        System.out.println(zoneId3); // +09:30
        
        // 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
    }
}
Output:
-06:00
+06:05:20
+09:30
zonedDateTime: 2021-06-22T00:00+06:05:20

4. ofX(..)

Phương thức ofHours(hours) trả về một ZoneOffset với số giờ lệch được chỉ định. Tham số hours nằm trong phạm vi [-18,18].
Các phương thức khác được hiểu tương tự.
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)
Parameter
Min
Max
hours
-18
18
minutes
0
59
seconds
0
59
totalSeconds
-18*60*60
18*60*60
Ví dụ:
ZoneOffset_ofX_ex1.java
ZoneOffset zoneId1 = ZoneOffset.ofHours(-6);
ZoneOffset zoneId2 = ZoneOffset.ofHoursMinutesSeconds(6, 5, 20);
ZoneOffset zoneId3 = ZoneOffset.ofHoursMinutes(9, 30);
 
System.out.println(zoneId1); // -06:00
System.out.println(zoneId2); // +06:05:20
System.out.println(zoneId3); // +09:30
 
// 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
Output:
-06:00
+06:05:20
+09:30
zonedDateTime: 2021-06-22T00:00+06:05:20

5. from(TemporalAccessor)

Trả về một đối tượng ZoneOffset từ đối tượng TemporalAccessor đã cho.
public static ZoneOffset from(TemporalAccessor temporal)
Ví dụ:
ZoneOffset_from_ex1.java
package org.o7planning.zoneoffset.ex;

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

public class ZoneOffset_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);
        
        ZoneOffset zoneOffset = ZoneOffset.from(temporalAccessor);
        System.out.println("zoneOffset: " + zoneOffset);
    }
}
Output:
ZonedDateTime: 2021-06-23T20:41:50.889465+06:00[Asia/Bishkek]
zoneOffset: +06:00

6. getRules()

Trả về một đối tượng ZoneRules liên hợp với ZoneOffset này, chứa các quy tắc múi giờ.
public ZoneRules getRules()
Đối tượng ZoneRules có được từ ZoneOffset này luôn có độ lệch múi giờ cố định:
ZoneOffset_getRules_ex1.java
package org.o7planning.zoneoffset.ex;

import java.time.Instant;
import java.time.ZoneOffset;
import java.time.zone.ZoneRules;

public class ZoneOffset_getRules_ex1 {

    public static void main(String[] args) {
        ZoneOffset zoneId = ZoneOffset.ofHoursMinutesSeconds(9, 30, 20);
        
        System.out.println(zoneId); // +09:30:20
        
        ZoneRules zoneRules = zoneId.getRules();
        
        ZoneOffset offset =  zoneRules.getOffset(Instant.now());
        System.out.println("offset: " + offset); // +09:30:20
    }
}
  • ZoneRules
  • ZoneRulesProvider

7. isSupported(TemporalField)

Kiểm tra xem một TemporalField có được hỗ trợ bởi ZoneOffset này không.
// Inherited from TemporalAccessor interface
public boolean isSupported(TemporalField field)
Nếu một TemporalField là kiểu ChronoField, chỉ ChronoField.OFFSET_SECONDS được hỗ trợ, các trường (field) khác không được hỗ trợ.
  • ChronoField.OFFSET_SECONDS
  • ChronoField.NANO_OF_DAY
  • ChronoField.MICRO_OF_SECOND
  • ...
  • ChronoField.MILLI_OF_SECOND
  • TemporalField
  • ChronoField

8. get(TemporalField)

Trả về giá trị của trường (field) đã chỉ định của đối tượng ZoneOffset này dưới dạng một số nguyên 32 bit.
// Inherited from TemporalAccessor interface
public int get(TemporalField field)
Ví dụ:
ZoneOffset_get_field_ex1.java
package org.o7planning.zoneoffset.ex;

import java.time.ZoneOffset;
import java.time.temporal.ChronoField;

public class ZoneOffset_get_field_ex1 {

    public static void main(String[] args) {
        // 9*60*60 + 30*60 + 20 = 34220 (seconds).
        ZoneOffset zoneId = ZoneOffset.ofHoursMinutesSeconds(9, 30, 20);
        
        if(zoneId.isSupported(ChronoField.OFFSET_SECONDS)) {
            int offsetSeconds = zoneId.get(ChronoField.OFFSET_SECONDS);
            
            System.out.println(offsetSeconds); // 34220
        }
    }
}
  • TemporalField
  • ChronoField

9. getLong(TemporalField)

Trả về giá trị của trường (field) đã chỉ định của đối tượng ZoneOffset này dưới dạng một số nguyên 64 bit.
// Inherited from TemporalAccessor interface
public long getLong(TemporalField field)
Ví dụ:
ZoneOffset_getLong_field_ex1.java
package org.o7planning.zoneoffset.ex;

import java.time.ZoneOffset;
import java.time.temporal.ChronoField;

public class ZoneOffset_getLong_field_ex1 {

    public static void main(String[] args) {
        // 9*60*60 + 30*60 + 20 = 34220 (seconds).
        ZoneOffset zoneId = ZoneOffset.ofHoursMinutesSeconds(9, 30, 20);
        
        if(zoneId.isSupported(ChronoField.OFFSET_SECONDS)) {
            long offsetSeconds = zoneId.getLong(ChronoField.OFFSET_SECONDS);
            
            System.out.println(offsetSeconds); // 34220
        }
    }
}
  • ChronoField
  • TemporalField

10. range(TemporalField)

Trả về phạm vi các giá trị hợp lệ cho trường (field) được chỉ định. Xem thêm phương thức isSupported(TemporalField).
// Inherited from TemporalAccessor interface
public ValueRange range(TemporalField field)
Ví dụ:
ZoneOffset_range_ex1.java
package org.o7planning.zoneoffset.ex;

import java.time.ZoneOffset;
import java.time.temporal.ChronoField;
import java.time.temporal.ValueRange;

public class ZoneOffset_range_ex1 {
    
    public static void main(String[] args) {
        ZoneOffset zoneOffset = ZoneOffset.ofHoursMinutesSeconds(9, 30, 20);
        System.out.println("zoneOffset: " + zoneOffset);

        if (zoneOffset.isSupported(ChronoField.OFFSET_SECONDS)) {
            ValueRange valueRange = zoneOffset.range(ChronoField.OFFSET_SECONDS);

            // [-64800,64800] seconds ~ [-18, 18] hours.
            System.out.println("valueRange: " + valueRange); // -64800 - 64800
        }
    }
}
Output:
zoneOffset: +09:30:20
valueRange: -64800 - 64800
  • TemporalField
  • ChronoField

11. query(TemporalQuery<R>)

Truy vấn đối tượng ZoneOffset này dựa trên một tham số TemporalQuery đã cho để trích ra thông tin từ đối tượng ZoneOffset này.
// Inherited from TemporalAccessor interface
public <R> R query(TemporalQuery<R> query)
Ví dụ:
ZoneOffset_query_ex1.java
package org.o7planning.zoneoffset.ex;

import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.temporal.TemporalQueries;

public class ZoneOffset_query_ex1 {
    
    public static void main(String[] args) {
        ZoneOffset zoneOffset = ZoneOffset.ofHoursMinutesSeconds(9, 30, 20);
        System.out.println("zoneOffset: " + zoneOffset);

        ZoneId zone = zoneOffset.query(TemporalQueries.zone());
        System.out.println("zone(): " + zone); // +09:30:20

        ZoneId zoneId = zoneOffset.query(TemporalQueries.zoneId());
        System.out.println("zoneId(): " + zoneId); // null
    }
}
Output:
zoneOffset: +09:30:20
zone(): +09:30:20
zoneId(): null
Ví dụ: Viết một TemporalQuery tuỳ biến để tìm kiếm tất cả các ZoneId sẵn có trong hệ thống có cùng độ lệch múi giờ với ZoneOffset này.
ZoneOffset_query_ex2.java
package org.o7planning.zoneoffset.ex;

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalQuery;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

public class ZoneOffset_query_ex2 {

    public static void main(String[] args) {
        ZoneOffset myZoneOffset = ZoneOffset.ofHours(7);
        System.out.println("myZoneOffset: " + myZoneOffset);
        System.out.println(" ------ ");
        
        // ZoneId list has the same offset with myZoneOffset
        List<ZoneId> zoneIdList = myZoneOffset.query(new SameOffsetTemporalQuery());
        for(ZoneId zoneId: zoneIdList)  {
            System.out.println(zoneId);
        }
    }
}

class SameOffsetTemporalQuery implements TemporalQuery<List<ZoneId>> {

    @Override
    public List<ZoneId> queryFrom(TemporalAccessor temporal) {
        List<ZoneId> returnList = new ArrayList<>();
        Set<String> zoneIdNames = ZoneId.getAvailableZoneIds();

        if (temporal.isSupported(ChronoField.OFFSET_SECONDS)) {
            ZoneOffset z = ZoneOffset.from(temporal);

            for (String zoneIdName : zoneIdNames) {
                ZoneId zid = ZoneId.of(zoneIdName);
                ZoneOffset offset = zid.getRules().getOffset(Instant.now());

                if (z.compareTo(offset) == 0) {
                    returnList.add(zid);
                }
            }
        }
        return returnList;
    }
}
Output:
myZoneOffset: +07:00
 ------
Asia/Pontianak
Etc/GMT-7
Asia/Phnom_Penh
Asia/Novosibirsk
Antarctica/Davis
Asia/Tomsk
Asia/Jakarta
Asia/Barnaul
Indian/Christmas
Asia/Ho_Chi_Minh
Asia/Hovd
Asia/Bangkok
Asia/Vientiane
Asia/Novokuznetsk
Asia/Krasnoyarsk
Asia/Saigon

12. adjustInto(Temporal)

Trả về một bản sao của đối tượng Temporal đã cho với độ lệch múi giờ giống với ZoneOffset này.
// Inherited from TemporalAdjuster interface
public Temporal adjustInto(Temporal temporal)
Ví dụ:
ZoneOffset_adjustInto_ex1.java
package org.o7planning.zoneoffset.ex;

import java.time.OffsetDateTime;
import java.time.ZoneOffset;

public class ZoneOffset_adjustInto_ex1 {

    public static void main(String[] args) {
        // Get the Temporal instance
        OffsetDateTime temporalInstance = OffsetDateTime.now();
        System.out.println("Original Temporal instance: " + temporalInstance);

        // Get the ZoneOffset
        ZoneOffset zoneOffset = ZoneOffset.ofHoursMinutes(9, 30);

        // Using adjustInto() method
        OffsetDateTime adjustedTemporal = (OffsetDateTime) zoneOffset.adjustInto(temporalInstance);
        System.out.println("Adjusted Temporal instance: " + adjustedTemporal);
    }
}
Output:
Original Temporal instance: 2021-06-24T01:18:39.633932+06:00
Adjusted Temporal instance: 2021-06-24T01:18:39.633932+09:30