您的当前位置:首页正文

temporal包

2024-11-07 来源:个人技术集锦

created: 2022-07-24T11:03:29+08:00
updated: 2022-07-24T14:10:52+08:00
tags:

  • DateTimeAPI
  • DateTimeAPI/Temporal
  • DateTimeAPI/TemporalAccessor
  • DateTimeAPI/TemporalField
  • DateTimeAPI/TemporalField/ChronoField
  • DateTimeAPI/TemporalUnit
  • DateTimeAPI/TemporalUnit/ChronoUnit
  • DateTimeAPI/TemporalAccessor
  • DateTimeAPI/TemporalAccessor/TemporalAccessors
  • DateTimeAPI/TemporalQuery
  • DateTimeAPI/TemporalQuery/TemporalQueries

The Temporal Package

java.time.temporal 包提供了支持日期和时间代码,特别是日期和时间计算的接口、类和枚举的集合。

这些接口旨在用于最低级别。应用程序代码应该根据具体类型声明变量和参数,例如 LocalDateZonedDateTime,而不是根据 Temporal 接口。这与声明 String 类型的变量完全一样,而不是 CharSequence 类型的变量。

Temporal and TemporalAccessor

Temporal 接口提供了用于访问基于时间的对象的框架,并由基于时间的类实现,例如 InstantLocalDateTimeZonedDateTime。此接口提供了添加或减去时间单位的方法,使基于时间的算术在各种日期和时间类中变得容易且一致。 TemporalAccessor 接口提供只读版本的 Temporal 接口。

TemporalTemporalAccessor 对象都是根据字段定义的,由 TemporalField 接口中指定的那样。 ChronoField 枚举是 TemporalField 接口的具体实现,并提供了一组丰富的已定义常量,例如 DAY_OF_WEEKMINUTE_OF_HOURMONTH_OF_YEAR

这些字段的单位由 TemporalUnit 接口指定。 ChronoUnit 枚举实现了 TemporalUnit 接口。字段 ChronoField.DAY_OF_WEEKChronoUnit.DAYSChronoUnit.WEEKS 的组合。 ChronoFieldChronoUnit 枚举将在以下部分中讨论。

Temporal 接口中基于算术的方法需要根据 TemporalAmount 值定义的参数。

ChronoField and IsoFields

实现 TemporalField 接口的 ChronoField 枚举提供了一组丰富的常量来访问日期和时间值。一些示例是 CLOCK_HOUR_OF_DAYNANO_OF_DAYDAY_OF_YEAR。此枚举可用于表示时间的概念方面,例如一年中的第三周、一天中的第 11 个小时或每月的第一个星期一。当遇到未知类型的 Temporal 时,可以使用 TemporalAccessor.isSupported(TemporalField) 方法来确定 Temporal 是否支持特定字段。以下代码行返回 false,表示 LocalDate 不支持 ChronoField.CLOCK_HOUR_OF_DAY

boolean isSupported = LocalDate.now().isSupported(ChronoField.CLOCK_HOUR_OF_DAY);

ISO-8601 特定的 ISO-8601 日历系统的附加字段在 IsoFields 类中定义。以下示例显示如何使用 ChronoFieldIsoFields 获取字段的值:日历系统的附加字段在 IsoFields 类中定义。以下示例显示如何使用 ChronoFieldIsoFields 获取字段的值:

time.get(ChronoField.MILLI_OF_SECOND)
int qoy = date.get(IsoFields.QUARTER_OF_YEAR);

另外两个类定义了可能有用的附加字段,WeekFieldsJulianFields

ChronoUnit

ChronoUnit 枚举实现了 TemporalUnit 接口,并提供了一组基于日期和时间的标准单位,从毫秒到千年。请注意,并非所有类都支持所有 ChronoUnit 对象。例如,Instant 类不支持 ChronoUnit.MONTHSChronoUnit.YEARS。 Date-Time API 中的类包含可用于验证类是否支持特定时间单位的 isSupported(TemporalUnit) 方法。以下对 isSupported() 的调用返回 false,确认 Instant 类不支持 ChronoUnit.DAYS

Instant instant = Instant.now();
boolean isSupported = instant.isSupported(ChronoUnit.DAYS);

Temporal Adjuster

java.time.temporal 包中的 TemporalAdjuster 接口提供了采用 Temporal 值并返回调整值的方法。调整器可以与任何基于时间的类型一起使用。

如果调整器与 ZonedDateTime 一起使用,则会计算一个新的日期,以保留原始时间和时区值。

Predefined Adjusters

TemporalAdjusters 类(注意复数)提供了一组预定义的调整器,用于查找每月的第一天或最后一天、一年的第一天或最后一天、每月的最后一个星期三或特定日期后的第一个星期二,举几个例子。预定义的调整器被定义为静态方法,旨在与静态导入语句一起使用。

下面的示例使用几个 TemporalAdjusters 方法,结合基于时间的类中定义的 with 方法,根据 2000 年 10 月 15 日的原始日期计算新日期:

LocalDate date = LocalDate.of(2000, Month.OCTOBER, 15);
DayOfWeek dotw = date.getDayOfWeek();
System.out.printf("%s is on a %s%n", date, dotw);

System.out.printf("first day of Month: %s%n",
                  date.with(TemporalAdjusters.firstDayOfMonth()));
System.out.printf("first Monday of Month: %s%n",
                  date.with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY)));
System.out.printf("last day of Month: %s%n",
                  date.with(TemporalAdjusters.lastDayOfMonth()));
System.out.printf("first day of next Month: %s%n",
                  date.with(TemporalAdjusters.firstDayOfNextMonth()));
System.out.printf("first day of next Year: %s%n",
                  date.with(TemporalAdjusters.firstDayOfNextYear()));
System.out.printf("first day of Year: %s%n",
                  date.with(TemporalAdjusters.firstDayOfYear()));

result

2000-10-15 is on a SUNDAY
first day of Month: 2000-10-01
first Monday of Month: 2000-10-02
last day of Month: 2000-10-31
first day of next Month: 2000-11-01
first day of next Year: 2001-01-01
first day of Year: 2000-01-01

Custom Adjusters

您还可以创建自己的自定义调节器。为此,您需要创建一个使用 adjustInto(Temporal) 方法实现 TemporalAdjuster 接口的类。

example

public class PaydayAdjuster implements TemporalAdjuster {
    /**
     * The adjustInto method accepts a Temporal instance 
     * and returns an adjusted LocalDate. If the passed in
     * parameter is not a LocalDate, then a DateTimeException is thrown.
     */
    public Temporal adjustInto(Temporal input) {
        LocalDate date = LocalDate.from(input);
        int day;
        if (date.getDayOfMonth() < 15) {
            day = 15;
        } else {
            day = date.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth();
        }
        date = date.withDayOfMonth(day);
        if (date.getDayOfWeek() == DayOfWeek.SATURDAY ||
                date.getDayOfWeek() == DayOfWeek.SUNDAY) {
            date = date.with(TemporalAdjusters.previous(DayOfWeek.FRIDAY));
        }

        return input.with(date);
    }
}

example

LocalDate nextPayday = date.with(new PaydayAdjuster());

在 2013 年,6 月 15 日和 6 月 30 日都发生在周末。使用 6 月 3 日和 6 月 18 日(2013 年)的相应日期运行前面的示例,得到以下结果:

Given the date:  2013 Jun 3
the next payday: 2013 Jun 14

Given the date:  2013 Jun 18
the next payday: 2013 Jun 28

Temporal Query

TemporalQuery 可用于从基于时间的对象中检索信息。

Predefined Queries

TemporalQueries 类(注意复数)提供了几个预定义的查询,包括在应用程序无法识别基于时间的对象的类型时有用的方法。与调整器一样,预定义查询被定义为静态方法,并设计为与静态导入语句一起使用。

例如,精度查询返回特定基于时间的对象可以返回的最小 ChronoUnit。以下示例对几种基于时间的对象使用精度查询:

TemporalQuery<TemporalUnit> query = TemporalQueries.precision();
System.out.printf("LocalDate precision is %s%n",
                  LocalDate.now().query(query));
System.out.printf("LocalDateTime precision is %s%n",
                  LocalDateTime.now().query(query));
System.out.printf("Year precision is %s%n",
                  Year.now().query(query));
System.out.printf("YearMonth precision is %s%n",
                  YearMonth.now().query(query));
System.out.printf("Instant precision is %s%n",
                  Instant.now().query(query));

result

LocalDate precision is Days
LocalDateTime precision is Nanos
Year precision is Years
YearMonth precision is Months
Instant precision is Nanos

Custom Queries

example1

public class FamilyVacations implements TemporalQuery<Boolean> {
    // Returns true if the passed-in date occurs during one of the
    // family vacations. Because the query compares the month and day only,
    // the check succeeds even if the Temporal types are not the same.
    public Boolean queryFrom(TemporalAccessor date) {
        int month = date.get(ChronoField.MONTH_OF_YEAR);
        int day = date.get(ChronoField.DAY_OF_MONTH);

        // Disneyland over Spring Break
        if ((month == Month.APRIL.getValue()) && ((day >= 3) && (day <= 8)))
            return Boolean.TRUE;

        // Smith family reunion on Lake Saugatuck
        if ((month == Month.AUGUST.getValue()) && ((day >= 8) && (day <= 14)))
            return Boolean.TRUE;

        return Boolean.FALSE;
    }
}

use

// define a year, a month and a day
LocalDate = date = LocalDate.of(year, month, day);
boolean isFamilyVacation = date.query(new FamilyVacations());

example2

public class FamilyBirthdays {
    // Returns true if the passed-in date is the same as one of the
    // family birthdays. Because the query compares the month and day only,
    // the check succeeds even if the Temporal types are not the same.
    public static Boolean isFamilyBirthday(TemporalAccessor date) {
        int month = date.get(ChronoField.MONTH_OF_YEAR);
        int day = date.get(ChronoField.DAY_OF_MONTH);

        // Angie's birthday is on April 3.
        if ((month == Month.APRIL.getValue()) && (day == 3))
            return Boolean.TRUE;

        // Sue's birthday is on June 18.
        if ((month == Month.JUNE.getValue()) && (day == 18))
            return Boolean.TRUE;

        // Joe's birthday is on May 29.
        if ((month == Month.MAY.getValue()) && (day == 29))
            return Boolean.TRUE;

        return Boolean.FALSE;
    }
}

use

// Invoking the query without using a lambda expression.
Boolean isFamilyVacation = date.query(new FamilyVacations());

// Invoking the query using a lambda expression.
Boolean isFamilyBirthday = date.query(FamilyBirthdays::isFamilyBirthday);

if (isFamilyVacation.booleanValue() || isFamilyBirthday.booleanValue())
    System.out.printf("%s is an important date!%n", date);
else
    System.out.printf("%s is not an important date.%n", date);

[[Period和Duration]]

Top