openplanning

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

  1. TemporalAccessor
  2. TemporalAccessor methods
  3. query(TemporalQuery<R>)
  4. range(TemporalField)
  5. get(TemporalField)
  6. getLong(TemporalField)
  7. isSupported(TemporalField)

1. TemporalAccessor

Interface TemporalAccessor mô phỏng một khái niệm chung nhất giữa các khái niệm ngày tháng (date), thời gian (time), độ lệch thời gian (time-offset), độ lệch múi giờ (zone-offset) và kỷ nguyên (era). Nó cung cấp các phương thức cơ bản để để lấy được các thông tin từ các đối tượng này.
public interface TemporalAccessor
Danh sách các lớp con hoặc enum thực hiện (implement) interface TemporalAccessor:
TemporalAccessor là một interface ở mức độ nền tảng (framework-level), hãy cẩn thận khi sử dụng nó trong ứng dụng bởi vì nó là một interface cơ sở của các hệ thống lịch khác nhau cùng được hỗ trợ trong Java Date Time API. Xem interface ChronoLocalDate với các thảo luận chi tiết hơn.
  • Hướng dẫn và ví dụ Java ChronoLocalDate
Chú ý: Nếu bạn có ý định viết các lớp triển khai (implement) interface TemporalAccessor, nên viết các lớp có tính bất biến (immutability) để nhất quán với Java Date Time API (Mặc dù điều này không bắt buộc).

2. TemporalAccessor methods

public boolean isSupported(TemporalField field);

public default ValueRange range(TemporalField field)  

public default int get(TemporalField field)  

public long getLong(TemporalField field);

public default <R> R query(TemporalQuery<R> query)

3. query(TemporalQuery<R>)

Truy vấn đối tượng TemporalAccessor này bằng đối tượng TemporalQuery chỉ định để trích ra thông tin.
public default <R> R query(TemporalQuery<R> query)
Xem các ví dụ về chủ đề này trong bài viết về TemporalQuery:

4. range(TemporalField)

Trả về một đối tượng ValueRange mô tả một phạm vi các giá trị hợp lệ của trường (field) được chỉ định. Đây là một phương thức mặc định của interface TemporalAccessor, nó có thể bị ghi đè (override) trong các lớp con của TemporalAccessor.
public default ValueRange range(TemporalField field) {
    if (field instanceof ChronoField) {
        if (isSupported(field)) {
            return field.range();
        }
        throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
    }
    Objects.requireNonNull(field, "field");
    return field.rangeRefinedBy(this);
}
Về cơ bản, đối tượng ValueRange chứa giá trị nhỏ nhất và lớn nhất của trường (field) đã cho theo kiểu dữ liệu long. Nếu trường chỉ định không có phạm vi hoặc không được hỗ trợ thì UnsupportedTemporalTypeException sẽ được ném ra.
ChronoField là một enum thực hiện (implement) interface TemporalField, nó chứa các trường tiêu chuẩn và đủ cho việc sử dụng trong Java Date Time API.
  • ChronoField.DAY_OF_WEEK
  • ChronoField.DAY_OF_YEAR
  • ChronoField.HOUR_OF_DAY
  • ...
TemporalAccessor_range_x1.java
package org.o7planning.temporalaccessor.ex;

import java.time.LocalDateTime;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.ValueRange;

public class TemporalAccessor_range_x1 {

    public static void main(String[] args) {

        TemporalAccessor localDateTime = LocalDateTime.of(2021, 2, 15, 0, 0, 0);
        System.out.printf("localDateTime: %s%n%n", localDateTime); // 2021-02-15T00:00

        if (localDateTime.isSupported(ChronoField.HOUR_OF_DAY)) {
            ValueRange valueRange1 = localDateTime.range(ChronoField.HOUR_OF_DAY);

            System.out.println("HOUR_OF_DAY range: " + valueRange1); // 0 - 23
            System.out.println("valueRange1.getMinimum(): " + valueRange1.getMinimum()); // 0
            System.out.println("valueRange1.getMaximum(): " + valueRange1.getMaximum()); // 23
        }
        System.out.println(" --------- ");

        if (localDateTime.isSupported(ChronoField.DAY_OF_MONTH)) {
            ValueRange valueRange2 = localDateTime.range(ChronoField.DAY_OF_MONTH);

            System.out.println("DAY_OF_MONTH range: " + valueRange2); // 1 - 28
            System.out.println("valueRange2.getMinimum(): " + valueRange2.getMinimum()); // 1
            System.out.println("valueRange2.getMaximum(): " + valueRange2.getMaximum()); // 28
        }

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

        if (localDateTime.isSupported(ChronoField.DAY_OF_YEAR)) {
            ValueRange valueRange3 = localDateTime.range(ChronoField.DAY_OF_YEAR);

            System.out.println("DAY_OF_MONTH range: " + valueRange3); // 1 - 365
            System.out.println("valueRange3.getMinimum(): " + valueRange3.getMinimum()); // 1
            System.out.println("valueRange3.getMaximum(): " + valueRange3.getMaximum()); // 365
        }
    }
}
Output:
localDateTime: 2021-02-15T00:00

HOUR_OF_DAY range: 0 - 23
valueRange1.getMinimum(): 0
valueRange1.getMaximum(): 23
 ---------
DAY_OF_MONTH range: 1 - 28
valueRange2.getMinimum(): 1
valueRange2.getMaximum(): 28
 ---------
DAY_OF_MONTH range: 1 - 365
valueRange3.getMinimum(): 1
valueRange3.getMaximum(): 365
  • TemporalField
  • ChronoField

5. get(TemporalField)

Trả về giá trị của trường (field) được chỉ định từ đối tượng TemporalAccessor này như một số nguyên 32 bit.
public default int get(TemporalField field) {
    ValueRange range = range(field);
    if (range.isIntValue() == false) {
        throw new UnsupportedTemporalTypeException("Invalid field " + field + " for get() method, use getLong() instead");
    }
    long value = getLong(field);
    if (range.isValidValue(value) == false) {
        throw new DateTimeException("Invalid value for " + field + " (valid values " + range + "): " + value);
    }
    return (int) value;
}
Chú ý: Trong một vài trường hợp bạn nên sử dụng phương thức getLong(TemporalField) thay vì get(TemporalField). Nguyên nhân là kiểu dữ liệu int là không đủ để lưu trữ giá trị của một vài trường (field), chẳng hạn ChronoField.PROLEPTIC_MONTH, ChronoField.EPOCH_DAY.
Ví dụ:
TemporalAccessor_get_x1.java
package org.o7planning.temporalaccessor.ex;

import java.time.LocalDate;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;

public class TemporalAccessor_get_x1 {

    public static void main(String[] args) {
        TemporalAccessor localDate = LocalDate.of(2021, 2, 15);
        System.out.printf("localDate: %s%n%n", localDate); // 2021-02-15T00:00  
        
        if (localDate.isSupported(ChronoField.YEAR)) {
            int year = localDate.get(ChronoField.YEAR);  
            System.out.println("year: " + year); // 2021
        }

        if (localDate.isSupported(ChronoField.DAY_OF_MONTH)) {
            int dayOfMonth = localDate.get(ChronoField.DAY_OF_MONTH);  
            System.out.println("dayOfMonth: " + dayOfMonth); // 15
        }

        if (localDate.isSupported(ChronoField.DAY_OF_YEAR)) {
            int dayOfYear = localDate.get(ChronoField.DAY_OF_YEAR);
            System.out.println("dayOfYear: " + dayOfYear); // 46
        }
    }
}
  • ChronoField
  • TemporalField

6. getLong(TemporalField)

Trả về giá trị của trường (field) được chỉ định từ đối tượng TemporalAccessor này như một số nguyên 64 bit.
public long getLong(TemporalField field)
Về cơ bản, phương thức này giống với phương thức get(TemporalField), điều khác biệt là nó trả về kiểu dữ liệu long. Ví dụ, kiểu dữ liệu int là không đủ để lưu trữ giá trị của trường ChronoField.EPOCH_DAY, vì vậy bạn cần sử dụng phương thức getLong(Temporal).
Các trường tiêu chuẩn dưới đây cần được sử dụng bởi phương thức getLong(TemporalField) thay vì phương thức get(TemporalField):
  • ChronoField.PROLEPTIC_MONTH
  • ChronoField.EPOCH_DAY
TemporalAccessor_getLong_x1.java
package org.o7planning.temporalaccessor.ex;

import java.time.LocalDate;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;

public class TemporalAccessor_getLong_x1 {

    public static void main(String[] args) {
        TemporalAccessor localDate = LocalDate.of(2021, 2, 15);
        System.out.printf("localDate: %s%n%n", localDate); // 2021-02-15T00:00  
        
        if (localDate.isSupported(ChronoField.EPOCH_DAY)) {
            // Using getLong(TemporalField) method:
            long epochDay  = localDate.getLong(ChronoField.EPOCH_DAY);  
            System.out.println("epochDay: " + epochDay); // 18673
        }

        if (localDate.isSupported(ChronoField.EPOCH_DAY)) {
            // Using get(TemporalField) method:
            int epochDay  = localDate.get(ChronoField.EPOCH_DAY); // --> Exception!
            System.out.println("epochDay: " + epochDay);  
        }
    }
}
Output:
localDate: 2021-02-15

epochDay: 18673
Exception in thread "main" java.time.temporal.UnsupportedTemporalTypeException: Invalid field 'EpochDay' for get() method, use getLong() instead
    at java.base/java.time.LocalDate.get0(LocalDate.java:699)
    at java.base/java.time.LocalDate.get(LocalDate.java:650)
    at org.o7planning.temporalaccessor.ex.TemporalAccessor_getLong_x1.main(TemporalAccessor_getLong_x1.java:21)
  • ChronoField
  • TemporalField

7. isSupported(TemporalField)

Kiểm tra xem trường (field) chỉ định có được hỗ trợ bởi TemporalAccessor này không.
public boolean isSupported(TemporalField field)
(**) Xem các lớp cụ thể để biết danh sách các trường (field) tiêu chuẩn được nó hỗ trợ.
Ví dụ:
  • Lớp LocalDate đại diện cho ngày tháng (date) và không bao gồm thời gian và múi giờ. Nó hỗ trợ các trường tiêu chuẩn như ChronoField.YEAR, ChronoField.DAY_OF_MONTH,.. nhưng không hỗ trợ các trường như ChronoField.SECOND_OF_DAY, ChronoField.HOUR_OF_DAY, ...
  • Lớp LocalDateTime đại diện cho ngày tháng (date) và thời gian (time) nhưng không bao gồm múi giờ. Nó hỗ trợ các trường tiêu chuẩn như ChronoField.YEAR, ChronoField.DAY_OF_MONTH, ChronoField.SECOND_OF_DAY, ChronoField.HOUR_OF_DAY.. nhưng không hỗ trợ các trường như ChronoField.OFFSET_SECONDS,..
TemporalAccessor_isSupported_ex1.java
TemporalAccessor localDate = LocalDate.of(2021, 2, 15);

System.out.println("Does localDate support: ");
 
System.out.println(" YEAR ? " + localDate.isSupported(ChronoField.YEAR)); // true
System.out.println(" DAY_OF_MONTH ? " + localDate.isSupported(ChronoField.DAY_OF_MONTH)); // true
System.out.println(" SECOND_OF_DAY ? " + localDate.isSupported(ChronoField.SECOND_OF_DAY)); // false
System.out.println(" HOUR_OF_DAY ? " + localDate.isSupported(ChronoField.HOUR_OF_DAY)); // false
System.out.println(" OFFSET_SECONDS ? " + localDate.isSupported(ChronoField.OFFSET_SECONDS)); // false

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

TemporalAccessor localDateTime = LocalDateTime.of(2021, 2, 15, 12, 30, 45);
System.out.println("Does localDateTime support: ");

System.out.println(" YEAR ? " + localDateTime.isSupported(ChronoField.YEAR)); // true
System.out.println(" DAY_OF_MONTH ? " + localDateTime.isSupported(ChronoField.DAY_OF_MONTH)); // true
System.out.println(" SECOND_OF_DAY ? " + localDateTime.isSupported(ChronoField.SECOND_OF_DAY)); // true
System.out.println(" HOUR_OF_DAY ? " + localDateTime.isSupported(ChronoField.HOUR_OF_DAY)); // true
System.out.println(" OFFSET_SECONDS ? " + localDate.isSupported(ChronoField.OFFSET_SECONDS)); // false
Output:
Does localDate support:
 YEAR ? true
 DAY_OF_MONTH ? true
 SECOND_OF_DAY ? false
 HOUR_OF_DAY ? false
 OFFSET_SECONDS ? false
 -----
Does localDateTime support:
 YEAR ? true
 DAY_OF_MONTH ? true
 SECOND_OF_DAY ? true
 HOUR_OF_DAY ? true
 OFFSET_SECONDS ? false
  • TemporalField
  • ChronoField