openplanning

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

  1. TemporalQuery
  2. Ex: AllLeapYearsInSameDecadeQuery
  3. Ex: AllMondaysInSameMonthQuery
  4. Ex: AllZoneIdsSameOffsetQuery
  5. TemporalQueries

1. TemporalQuery

Interface TemporalQuery là một công cụ để truy vấn một đối tượng TemporalAccessor để trích ra các thông tin. Về cơ bản TemporalQuery tồn tại để ngoại hoá (externalize) việc truy vấn thông tin của đối tượng TemporalAccessor thay vì trích xuất thông tin một cách trực tiếp.
@FunctionalInterface
public interface TemporalQuery<R> {
    R queryFrom(TemporalAccessor temporal);
}
Ví dụ: Chúng ta viết lớp HourMinuteQuery để trích ra thông tin giờ và phút dưới dạng một chuỗi "HH:mm" từ các đối tượng TemporalAccessor.
TemporalAccessor
Example
Using HourMinuteQuery
LocalDateTime
2020-11-25 13:30:45
13:30
ZonedDateTime
2020-11-25 15:30:45+06:00[Asia/Bishkek]
15:30
LocalTime
21:45:45
21:45
HourMinuteQuery.java
package org.o7planning.temporalquery.ex;

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

public class HourMinuteQuery implements TemporalQuery<String> {
    @Override
    public String queryFrom(TemporalAccessor temporal) {
        if (temporal.isSupported(ChronoField.HOUR_OF_DAY) //
                && temporal.isSupported(ChronoField.MINUTE_OF_HOUR)) {
            int hour = temporal.get(ChronoField.HOUR_OF_DAY);
            int minute = temporal.get(ChronoField.MINUTE_OF_HOUR);
            return hour + ":" + minute;
        }
        return null;
    }
}
Sử dụng HourMinuteQuery:
HourMinuteQuery_ex1.java
package org.o7planning.temporalquery.ex;

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

public class HourMinuteQuery_ex1  {
    public static void main(String[] args) {
        // TemporalAccessor object:
        ZonedDateTime parisNow = ZonedDateTime.now(ZoneId.of("Europe/Paris"));
        
        System.out.printf("Paris now is: %s%n", parisNow);
        
        HourMinuteQuery query = new HourMinuteQuery();
        
        String info = query.queryFrom(parisNow);
        System.out.println("Info: " + info);
    }
}
Output:
Paris now is: 2021-07-05T19:17:54.978689+02:00[Europe/Paris]
Info: 19:17
Có 2 cách để truy vấn một đối tượng TemporalAccessor, cách tiếp cận thứ hai được khuyến nghị sử dụng.
// These two lines are equivalent, but the second approach is recommended
information = thisQuery.queryFrom(temporalAccessor);  // (1)
information = temporalAccessor.query(thisQuery);          // (2)

2. Ex: AllLeapYearsInSameDecadeQuery

Tạo một TemporalQuery để tìm kiếm tất cả các năm nhuận trong cùng một thập kỷ với một đối tượng TemporalAccessor.
AllLeapYearsInSameDecadeQuery.java
package org.o7planning.temporalquery.ex;

import java.time.DateTimeException;
import java.time.chrono.ChronoLocalDate;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalQuery;
import java.util.ArrayList;
import java.util.List;

// Return all leap years in the same Decade with a TemporalAccessor.
public class AllLeapYearsInSameDecadeQuery implements TemporalQuery<List<Integer>> {

    @Override
    public List<Integer> queryFrom(TemporalAccessor temporal) {
        if (!(temporal instanceof ChronoLocalDate)) {
            throw new DateTimeException("Only ChronoLocalDate is supported");
        }
        List<Integer> leapYears = new ArrayList<>();

        ChronoLocalDate localDate = (ChronoLocalDate) temporal;

        int year = localDate.get(ChronoField.YEAR);
        int firstYearInSameDecade = year - (year % 10);
        
        for (int i = 0; i < 10; i++) {
            int y = firstYearInSameDecade + i;
            ChronoLocalDate newLocalDate = localDate.with(ChronoField.YEAR, y);
            if (newLocalDate.isLeapYear()) {
                leapYears.add(newLocalDate.get(ChronoField.YEAR));
            }
        }
        return leapYears;
    }
}
AllLeapYearsInSameDecadeQuery_ex1.java
LocalDate today = LocalDate.now();
System.out.println("Today is: " + today);
System.out.println("Year: " + today.getYear());

System.out.printf("Leap years in the same decade with %d:%n%n", today.getYear());

AllLeapYearsInSameDecadeQuery query = new AllLeapYearsInSameDecadeQuery();

// Return leap years in the same decade with today.
List<Integer> leapYears = query.queryFrom(today);
for(Integer leapYear: leapYears)  {
    System.out.println("Leap year: " + leapYear);
}
Output:
Today is: 2021-07-05
Year: 2021
Leap years in the same decade with 2021:

Leap year: 2020
Leap year: 2024
Leap year: 2028

3. Ex: AllMondaysInSameMonthQuery

Tạo một TemporalQuery để tìm kiếm tất cả các thứ hai (monday) trong cùng một tháng với một đối tượng TemporalAccessor.
AllMondaysInSameMonthQuery.java
package org.o7planning.temporalquery.ex;

import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalQuery;
import java.time.temporal.ValueRange;
import java.util.ArrayList;
import java.util.List;

public class AllMondaysInSameMonthQuery implements TemporalQuery<List<LocalDate>>{

    @Override
    public List<LocalDate> queryFrom(TemporalAccessor temporal) {
        if(!(temporal instanceof LocalDate))  {
            throw new DateTimeException("Only LocalDate is supported");
        }
        LocalDate localDate = (LocalDate) temporal;
        List<LocalDate> retList= new ArrayList<LocalDate>();
        
        ValueRange range = localDate.range(ChronoField.DAY_OF_MONTH);
        
        for(long dayOfMonth = range.getMinimum(); dayOfMonth<= range.getMaximum(); dayOfMonth++) {
            LocalDate date = localDate.withDayOfMonth((int) dayOfMonth);
            int dayOfWeek = date.get(ChronoField.DAY_OF_WEEK) ;
            if(dayOfWeek == 1) { // Monday
                retList.add(date);
            }
        }
        return retList;
    }
}
AllMondaysInSameMonthQuery_ex1.java
LocalDate localDate = LocalDate.now();

System.out.println("Today is: " + localDate );
System.out.println("All mondays in the same month:\n");

AllMondaysInSameMonthQuery query = new AllMondaysInSameMonthQuery();

// Same as: mondaysInSameMonth = localDate.query(query);
List<LocalDate> mondaysInSameMonth = query.queryFrom(localDate);

for(LocalDate monday: mondaysInSameMonth)  {
    System.out.println(monday);
}
Output:
Today is: 2021-07-05
All mondays in the same month:

2021-07-05
2021-07-12
2021-07-19
2021-07-26

4. Ex: AllZoneIdsSameOffsetQuery

Tạo một TemporalQuery để tìm kiếm tất cả các ZoneId sẵn có trong hệ thống và có cùng độ lệch múi giờ (zone-offset) với một đối tượng TemporalAccessor.
AllZoneIdsSameOffsetQuery.java
package org.o7planning.temporalquery.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;

// Find all available ZoneIds with the same offset as a TemporalAccessor.
public class AllZoneIdsSameOffsetQuery implements TemporalQuery<List<ZoneId>> {

    @Override
    public List<ZoneId> queryFrom(TemporalAccessor temporal) {
        ZoneOffset offset = ZoneOffset.from(temporal);

        List<ZoneId> returnList = new ArrayList<>();
        Set<String> zoneIdNames = ZoneId.getAvailableZoneIds();

        if (temporal.isSupported(ChronoField.OFFSET_SECONDS)) {

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

                if (offset.compareTo(os) == 0) {
                    returnList.add(zid);
                }
            }
        }
        return returnList;
    }
}
AllZoneIdsSameOffsetQuery_ex1.java
ZonedDateTime parisNow = ZonedDateTime.now(ZoneId.of("Europe/Paris"));

System.out.printf("Paris now is: %s%n", parisNow);
System.out.printf("Paris offset: %s%n", parisNow.getOffset());

AllZoneIdsSameOffsetQuery query = new AllZoneIdsSameOffsetQuery();

// Same as: sameOffsetZoneIds = parisNow.query(query);
List<ZoneId> sameOffsetZoneIds = query.queryFrom(parisNow);

System.out.printf("All available ZoneId with the same offset as %s:%n%n",parisNow.getOffset());

for(ZoneId zoneId: sameOffsetZoneIds) {
    System.out.println(zoneId.getId() +" : " + zoneId.getRules().getOffset(Instant.now()));
}
Output:
Paris now is: 2021-07-05T17:44:23.310010+02:00[Europe/Paris]
Paris offset: +02:00
All available ZoneId with the same offset as +02:00:

Africa/Cairo : +02:00
Africa/Mbabane : +02:00
Europe/Brussels : +02:00  
Africa/Harare : +02:00
.....
Africa/Khartoum : +02:00
Africa/Johannesburg : +02:00
Europe/Belgrade : +02:00
Europe/Bratislava : +02:00
Arctic/Longyearbyen : +02:00
Europe/Monaco : +02:00

5. TemporalQueries

Lớp TemporalQueries cung cấp các phương thức tĩnh để có được các đối tượng TemporalQuery thông dụng và hữu ích. Các thông tin nhận được có thể là:
  • Chronology
  • LocalDate
  • LocalTime
  • ZoneOffset
  • Precision
  • Zone
  • ZoneId