openplanning

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

  1. TemporalAdjuster
  2. Basic Examples
  3. Custom TemporalAdjuster Examples
  4. TemporalAdjusters Examples

1. TemporalAdjuster

Interface TemporalAdjuster là một công cụ để điều chỉnh một đối tượng Temporal để tạo ra một bản sao. Về cơ bản TemporalAdjuster tồn tại để ngoại hoá (externalize) một quá trình điều chỉnh các đối tượng Temporal thay vì điều chỉnh trực tiếp.
@FunctionalInterface
public interface TemporalAdjuster {
    Temporal adjustInto(Temporal temporal);
}
Ví dụ: Chúng ta tạo lớp TruncateTimeAdjuster để cắt bỏ thời gian (giờ, phút, giây, nano giây) của một đối tượng Temporal.
Temporal
Example
Apply TruncateTimeAdjuster
LocalDateTime
2020-11-25 13:30:45
2020-11-25 00:00:00
ZonedDateTime
2020-11-25 13:30:45+06:00[Asia/Bishkek]
2020-11-25 00:00:00+06:00[Asia/Bishkek]
LocalTime
13:30:45
00:00:00
TruncateTimeAdjuster.java
package org.o7planning.temporaladjuster.ex;

import java.time.temporal.ChronoField;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjuster;

public class TruncateTimeAdjuster implements TemporalAdjuster {
    @Override
    public Temporal adjustInto(Temporal temporal) {
        Temporal adjustedTemporal = temporal;
        if (temporal.isSupported(ChronoField.HOUR_OF_DAY)) {
            adjustedTemporal = adjustedTemporal.with(ChronoField.HOUR_OF_DAY, 0);
        }
        if (temporal.isSupported(ChronoField.MINUTE_OF_HOUR)) {
            adjustedTemporal = adjustedTemporal.with(ChronoField.MINUTE_OF_HOUR, 0);
        }
        if (temporal.isSupported(ChronoField.SECOND_OF_MINUTE)) {
            adjustedTemporal = adjustedTemporal.with(ChronoField.SECOND_OF_MINUTE, 0);
        }
        if (temporal.isSupported(ChronoField.NANO_OF_SECOND)) {
            adjustedTemporal = adjustedTemporal.with(ChronoField.NANO_OF_SECOND, 0);
        }
        return adjustedTemporal;
    }
}
Sử dụng TruncateTemporalAdjuster:
TruncateTimeAdjuster_ex1.java
TruncateTimeAdjuster truncateTimeAdjuster = new TruncateTimeAdjuster();

// Create a Temporal object from LocalDateTime
LocalDateTime localDateTime = LocalDateTime.now();
LocalDateTime adjustedLocalDateTime = (LocalDateTime) truncateTimeAdjuster.adjustInto(localDateTime);

System.out.printf("localDateTime: %s%n", localDateTime);
System.out.printf("adjustedLocalDateTime: %s%n%n", adjustedLocalDateTime);

//  Create a Temporal object from ZonedDateTime
ZonedDateTime zonedDateTime = ZonedDateTime.now();
ZonedDateTime adjustedZonedDateTime = (ZonedDateTime) truncateTimeAdjuster.adjustInto(zonedDateTime);

System.out.printf("zonedDateTime:  %s%n", zonedDateTime);
System.out.printf("adjustedZonedDateTime:  %s%n%n", adjustedZonedDateTime);

//  Create a Temporal object from OffsetDateTime
OffsetDateTime offsetDateTime = OffsetDateTime.now();
OffsetDateTime adjustedOffsetDateTime = (OffsetDateTime) truncateTimeAdjuster.adjustInto(offsetDateTime);

System.out.printf("offsetDateTime:  %s%n", offsetDateTime);
System.out.printf("adjustedOffsetDateTime:  %s%n", adjustedOffsetDateTime);
Output:
localDateTime: 2021-07-05T00:30:09.309188
adjustedLocalDateTime: 2021-07-05T00:00

zonedDateTime:  2021-07-05T00:30:09.322306+06:00[Asia/Bishkek]
adjustedZonedDateTime:  2021-07-05T00:00+06:00[Asia/Bishkek]

offsetDateTime:  2021-07-05T00:30:09.323143+06:00
adjustedOffsetDateTime:  2021-07-05T00:00+06:00
Có rất nhiều lớp trong Java Date Time API thi hành (implement) interface TemporalAdjuster, điều này có nghĩa là chúng có khả năng điều chỉnh các đối tượng Temporal khác:
Có 2 cách để điều chỉnh một đối tượng Temporal, 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
adjustedTemporal = thisAdjuster.adjustInto(temporal); // (1)
adjustedTemporal = temporal.with(thisAdjuster);       // (2)

2. Basic Examples

Ví dụ: Điều chỉnh tất cả các đối tượng Temporal đã cho thành tháng 5 năm 2000, các trường (field) khác không thay đổi.
TemporalAdjuster_ex1.java
package org.o7planning.temporaladjuster.ex;

import java.time.LocalDate;
import java.time.YearMonth;
import java.time.ZonedDateTime;
import java.time.temporal.TemporalAdjuster;

public class TemporalAdjuster_ex1 {

    public static void main(String[] args) {
        TemporalAdjuster adjuster = YearMonth.of(2020, 5); // May 2020.

        // Create a Temporal object from ZonedDateTime
        ZonedDateTime zonedDateTime = ZonedDateTime.now();
        ZonedDateTime adjustedZonedDateTime = (ZonedDateTime) adjuster.adjustInto(zonedDateTime);

        System.out.printf("zonedDateTime: %s%n", zonedDateTime);
        System.out.printf("adjustedZonedDateTime: %s%n%n", adjustedZonedDateTime);

        // Create a Temporal object from LocalDate
        LocalDate localDate = LocalDate.now();
        LocalDate adjustedLocalDate = (LocalDate) adjuster.adjustInto(localDate);

        System.out.printf("localDate: %s%n", localDate);
        System.out.printf("adjustedLocalDate: %s%n", adjustedLocalDate);
    }
}
Output:
zonedDateTime: 2021-07-05T00:51:07.837210+06:00[Asia/Bishkek]
adjustedZonedDateTime: 2020-05-05T00:51:07.837210+06:00[Asia/Bishkek]

localDate: 2021-07-05
adjustedLocalDate: 2020-05-05
Ví dụ: Điều chỉnh độ lệch múi giờ (zone-offset) cho các đối tượng OffsetDateTime đã cho thành +15;
TemporalAdjuster_ex2.java
TemporalAdjuster adjuster = ZoneOffset.ofHours(15);

// Create a Temporal object from OffsetDateTime
OffsetDateTime offsetDateTime1 = OffsetDateTime.now();
OffsetDateTime adjustedOffsetDateTime1 = (OffsetDateTime) adjuster.adjustInto(offsetDateTime1);

System.out.printf("offsetDateTime1: %s%n", offsetDateTime1);
System.out.printf("adjustedOffsetDateTime1: %s%n%n", adjustedOffsetDateTime1);

// Create a Temporal object from OffsetDateTime
OffsetDateTime offsetDateTime2 = OffsetDateTime.parse("2000-01-01T01:00+01:00");
OffsetDateTime adjustedOffsetDateTime2 = (OffsetDateTime) adjuster.adjustInto(offsetDateTime2);

System.out.printf("offsetDateTime2: %s%n", offsetDateTime2);
System.out.printf("adjustedOffsetDateTime2: %s%n%n", adjustedOffsetDateTime2);
Output:
offsetDateTime1: 2021-07-05T01:15:48.372665+06:00
adjustedOffsetDateTime1: 2021-07-05T01:15:48.372665+15:00

offsetDateTime2: 2000-01-01T01:00+01:00
adjustedOffsetDateTime2: 2000-01-01T01:00+15:00

3. Custom TemporalAdjuster Examples

Giả sử rằng các ngày làm việc trong tuần là từ thứ hai tới thứ sáu. Chúng ta sẽ viết lớp NextWorkingDayAdjuster để tìm kiếm ngày làm việc tiếp theo sau ngày đã cho.
NextWorkingDayAdjuster.java
package org.o7planning.temporaladjuster.ex;

import java.time.DayOfWeek;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjuster;

public class NextWorkingDayAdjuster implements TemporalAdjuster {
    @Override
    public Temporal adjustInto(Temporal temporal) {
        int field = temporal.get(ChronoField.DAY_OF_WEEK);
        DayOfWeek dayOfWeek = DayOfWeek.of(field);

        int daysToAdd = 1;
        if (DayOfWeek.FRIDAY.equals(dayOfWeek)) {
            daysToAdd = 3;
        } else if (DayOfWeek.SATURDAY.equals(dayOfWeek)) {
            daysToAdd = 2;
        }
        return temporal.plus(daysToAdd, ChronoUnit.DAYS);
    }
}
Ví dụ, sử dụng lớp NextWorkingDayAdjuster:
NextWorkingDayAdjuster_ex1.java
package org.o7planning.temporaladjuster.ex;

import java.time.LocalDate;
import java.time.ZonedDateTime;
import java.time.temporal.TemporalAdjuster;

public class NextWorkingDayAdjuster_ex1 {
    public static void main(String[] args) {
        TemporalAdjuster adjuster = new NextWorkingDayAdjuster();

        // Create a Temporal object from LocalDate
        LocalDate localDate = LocalDate.now();
        LocalDate nextWorkingDay = (LocalDate) adjuster.adjustInto(localDate);

        System.out.printf("localDate: %s%n", localDate);
        System.out.printf("nextWorkingDay: %s%n", nextWorkingDay);
        System.out.println(" ----- ");

        // Create a Temporal object from ZonedDateTime
        ZonedDateTime zonedDateTime = ZonedDateTime.now();
        ZonedDateTime adjustedZonedDateTime = (ZonedDateTime) adjuster.adjustInto(zonedDateTime);
        nextWorkingDay = adjustedZonedDateTime.toLocalDate();

        System.out.printf("zonedDateTime: %s%n", zonedDateTime);
        System.out.printf("adjustedZonedDateTime: %s%n", adjustedZonedDateTime);
        System.out.printf("nextWorkingDay: %s%n", nextWorkingDay);
    }
}
Output:
localDate: 2021-07-05
nextWorkingDay: 2021-07-06
 -----
zonedDateTime: 2021-07-05T01:34:09.112648+06:00[Asia/Bishkek]
adjustedZonedDateTime: 2021-07-06T01:34:09.112648+06:00[Asia/Bishkek]
nextWorkingDay: 2021-07-06
Ví dụ: Viết lớp NextChristmasAdjuster để tìm kiếm ngày giáng sinh tiếp theo:
NextChristmasAdjuster.java
package org.o7planning.temporaladjuster.ex;

import java.time.Period;
import java.time.temporal.ChronoField;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjuster;

public class NextChristmasAdjuster implements TemporalAdjuster {
    @Override
    public Temporal adjustInto(Temporal temporal) {
        int month = temporal.get(ChronoField.MONTH_OF_YEAR);
        int day = temporal.get(ChronoField.DAY_OF_MONTH);
        if(month == 12 && day > 25)  {
            temporal = temporal.plus(Period.ofYears(1));
        }
        return temporal.with(ChronoField.MONTH_OF_YEAR, 12).with(ChronoField.DAY_OF_MONTH, 25);
    }
}
Sử dụng lớp NextChristmasAdjuster:
NextChristmasAdjuster_ex1.java
package org.o7planning.temporaladjuster.ex;

import java.time.LocalDate;
import java.time.temporal.TemporalAdjuster;

public class NextChristmasAdjuster_ex1 {
    public static void main(String[] args) {
        TemporalAdjuster adjuster = new NextChristmasAdjuster();

        // Create a Temporal object from LocalDate
        LocalDate localDate1 = LocalDate.of(2021, 7, 5);
        LocalDate nextChristmasDay = (LocalDate) adjuster.adjustInto(localDate1);

        System.out.printf("localDate1: %s%n", localDate1);
        System.out.printf("nextChristmasDay: %s%n", nextChristmasDay);
        System.out.println(" ----- ");

        // Create a Temporal object from LocalDate
        LocalDate localDate2 = LocalDate.of(2021, 12, 26);
        nextChristmasDay = (LocalDate) adjuster.adjustInto(localDate2);

        System.out.printf("localDate2: %s%n", localDate2);
        System.out.printf("nextChristmasDay: %s%n", nextChristmasDay);
    }
}
Output:
localDate1: 2021-07-05
nextChristmasDay: 2021-12-25
 -----
localDate2: 2021-12-26
nextChristmasDay: 2022-12-25

4. TemporalAdjusters Examples

Lớp TemporalAdjusters cung cấp các phương thức tĩnh để có được các TemporalAdjuster tiêu chuẩn. Chúng bao gồm:
  • Tìm kiếm ngày đầu tiên hoặc cuối cùng của tháng.
  • Tìm kiếm ngày đầu tiên của tháng tiếp theo.
  • Tìm kiếm ngày đầu tiên hoặc cuối cùng của năm.
  • Tìm kiếm ngày đầu tiên của năm tiếp theo.
  • Tìm kiếm "ngày trong tuần" (day-of-week) đầu tiên hoặc cuối cùng trong một tháng, chẳng hạn "Thứ tư đầu tiên của tháng sáu".
  • Tìm kiếm "ngày trong tuần" (day-of-week) trước hoặc tiếp theo, chẳng hạn "Thứ năm tiếp theo".