模块  java.base
软件包  java.time.chrono

Interface ChronoLocalDate

  • All Superinterfaces:
    Comparable<ChronoLocalDate>TemporalTemporalAccessorTemporalAdjuster
    所有已知实现类:
    HijrahDateJapaneseDateLocalDateMinguoDateThaiBuddhistDate

    public interface ChronoLocalDate
    extends Temporal, TemporalAdjuster, Comparable<ChronoLocalDate>
    用于高级全球化用例的任意时间表中没有时间或时区的日期。

    大多数应用程序应将方法签名,字段和变量声明为LocalDate ,而不是此接口。

    ChronoLocalDateChronology chronology或日历系统可插拔日期的抽象表示。 日期根据TemporalField表示的字段定义,其中最常见的实现在ChronoField中定义。 年表定义了日历系统的运作方式和标准字段的含义。

    何时使用此界面

    API的设计鼓励使用LocalDate而不是此接口,即使在应用程序需要处理多个日历系统的情况下也是如此。

    这个概念起初看起来令人惊讶,因为全球化应用程序的自然方式可能最初似乎是抽象日历系统。 但是,如下所述,抽象日历系统通常是错误的方法,导致逻辑错误并且很难发现错误。 因此,应该考虑选择使用此接口而不是LocalDate的应用程序范围的架构决策。

    要考虑的架构问题

    这些是在整个应用程序中使用此接口之前必须考虑的一些要点。

    1)与仅使用LocalDate ,使用此接口的应用程序面临的错误概率明显更高。 这是因为在开发时不知道使用中的日历系统。 错误的一个关键原因是开发人员将其日常ISO日历系统知识的假设应用于旨在处理任意日历系统的代码。 下面的部分概述了这些假设如何导致问题减少错误风险的主要机制是强大的代码审查流程。 在代码的生命周期中,这也应被视为维护的额外成本。

    2)此接口不强制实现的不变性。 虽然实现说明表明所有实现都必须是不可变的,但代码或类型系统中没有任何内容可以强制执行此操作。 因此,任何声明接受ChronoLocalDate都可能被传递给一个写得不好或恶意编写的可变实现。

    3)使用此接口的应用程序必须考虑时代的影响。 LocalDate通过确保getYear()返回LocalDate保护用户免受时代概念的影响。 该决定确保开发人员可以将LocalDate实例视为由三个字段组成 - 年,月和月。 相比之下,此界面的用户必须将日期视为由四个字段组成 - 时代,年代,月份和日期。 额外的时代领域经常被遗忘,但对任意日历系统中的日期至关重要。 例如,在日历系统中,时代代表了皇帝的统治。 每当一个统治结束而另一个统治开始时,年龄将重置为一年。

    4)在两个系统之间传递日期的唯一商定国际标准是ISO-8601标准,该标准要求ISO日历系统。 在整个应用程序中使用此接口将不可避免地导致需要跨越网络或组件边界传递日期,这需要特定于应用程序的协议或格式。

    5)长期持久性,例如数据库,几乎总是只接受ISO-8601日历系统(或相关的Julian-Gregorian)中的日期。 在其他日历系统中传递日期会增加与持久性交互的复杂性。

    6)大多数时候,在整个申请过程中通过ChronoLocalDate是不必要的,如下面的最后一节所述。

    错误的假设导致多日历系统代码中的错误

    如上所述,在尝试使用和操纵任意日历系统中的日期时,需要考虑许多问题。 这些是一些关键问题。

    查询日期并假定该值永远不会超过31的代码无效。 某些日历系统在某些月份有超过31天。

    将日期增加12个月并假定添加了一年的代码无效。 某些日历系统具有不同的月份数,例如科普特语或Ethiopic中的13个。

    将日期添加一个月并假设月份值增加1或包装到下一年的代码无效。 有些日历系统一年中可变数月,例如希伯来语。

    添加一个月的代码,然后添加第二个月,并假定日期将保持接近其原始值无效。 一些日历系统在最长月份的长度和最短月份的长度之间具有很大差异。 例如,Coptic或Ethiopic有12个月的30天和1个月的5天。

    添加七天并假设已添加一周的代码无效。 有些日历系统有七周以上的时间,例如法国革命。

    即假设由于年份代码date1比当年更大date2然后date1是后date2无效。 这对于所有日历系统在提及年代时都是无效的,尤其是日历系统的不真实,其中年代随着每个新皇帝的统治而重新开始。

    将一年中的一个月和一个月中的一个作为年初处理的代码无效。 并非所有日历系统都以月份值为1开始。

    通常,在开发时日历系统未知时,操纵日期甚至查询日期对于错误是敞开的。 这就是为什么使用此接口的代码需要进行额外的代码审查。 这也是为什么避免这种接口类型的架构决策通常是正确的。

    改为使用LocalDate

    在整个应用程序中使用此接口的主要替代方法如下。
    • 使用LocalDate声明引用日期的所有方法签名。
    • 将时间顺序(日历系统)存储在用户配置文件中,或者从用户区域设置中查找年表
    • 在打印和解析期间,将ISO LocalDate转换为用户首选的日历系统
    这种方法将全球化日历系统的问题视为本地化问题,并将其限制在UI层。 这种方法与java平台中的其他本地化问题保持一致。

    如上所述,在日历系统的规则可插拔的日期执行计算需要技巧并且不推荐。 幸运的是,在任意日历系统中对日期执行计算的需求极为罕见。 例如,图书馆图书租赁计划的业务规则极不可能允许租赁为一个月,其中月份的含义取决于用户的首选日历系统。

    在任意日历系统中计算日期的关键用例是为显示和用户交互生成逐月日历。 同样,这是一个UI问题,并且仅在UI层的几个方法中使用该接口可能是合理的。

    在系统的任何其他部分中,必须在ISO之外的日历系统中操作日期,用例通常将指定要使用的日历系统。 例如,申请可能需要计算下一个可能需要操纵日期的伊斯兰或希伯来假期。 这种用例可以按如下方式处理:

    • 从传递给该方法的ISO LocalDate开始
    • 将日期转换为备用日历系统,对于此用例,该系统是已知的而不是任意的
    • 执行计算
    • 转换回LocalDate
    编写低级框架或库的开发人员也应避免使用此接口。 相反,应该使用两个通用访问接口中的一个。 使用TemporalAccessor如果需要只读访问,或使用Temporal如果需要进行读写访问。
    实现要求:
    必须小心实现此接口,以确保其他类正常运行。 可以实例化的所有实现必须是最终的,不可变的和线程安全的。 只要有可能,子类应该是Serializable。

    可以向系统添加附加日历系统。 有关详细信息,请参见Chronology

    从以下版本开始:
    1.8
    • 方法详细信息

      • from

        static ChronoLocalDate from​(TemporalAccessor temporal)
        从时态对象获得ChronoLocalDate的实例。

        这基于指定的时间获得本地日期。 TemporalAccessor表示一组任意日期和时间信息,该工厂将其转换为ChronoLocalDate的实例。

        转换从时间对象中提取并组合年表和日期。 该行为相当于将Chronology.date(TemporalAccessor)与提取的年表一起使用。 允许实现执行优化,例如访问与相关对象等效的那些字段。

        该方法匹配功能接口TemporalQuery的签名,允许其通过方法参考ChronoLocalDate::from用作查询。

        参数
        temporal - 要转换的时态对象,而不是null
        结果
        日期,不是空
        异常
        DateTimeException - 如果无法转换为 ChronoLocalDate
        另请参见:
        Chronology.date(TemporalAccessor)
      • getChronology

        Chronology getChronology()
        获取此日期的年表。

        Chronology表示正在使用的日历系统。 ChronoField中的时代和其他领域由年表定义。

        结果
        年表,不是空的
      • getEra

        default Era getEra()
        获得按时间顺序定义的时代。

        从概念上讲,时代是时间线的最大分支。 大多数日历系统都有一个纪元,将时间线划分为两个时代。 然而,有些时代有多个时代,例如每个领导者的统治时期。 确切含义由Chronology确定。

        所有正确实现的Era类都是单例,因此它是编写date.getEra() == SomeChrono.ERA_NAME)有效代码。

        此默认实现使用Chronology.eraOf(int)

        结果
        在此日期适用的年表特定时代常数,不为空
      • isLeapYear

        default boolean isLeapYear()
        检查年份是否为日历系统定义的闰年。

        闰年是比正常情况更长的一年。 确切的含义取决于年表,其约束条件是闰年必须意味着一年的长度超过非闰年。

        此默认实现使用Chronology.isLeapYear(long)

        结果
        如果此日期在闰年,则为true,否则为false
      • lengthOfMonth

        int lengthOfMonth()
        返回由此日期表示的月份长度,由日历系统定义。

        这将返回以天为单位的月份长度。

        结果
        以天为单位的月份长度
      • lengthOfYear

        default int lengthOfYear()
        返回由此日期表示的年份长度,由日历系统定义。

        这将返回以年为单位的年份长度。

        默认实现使用isLeapYear()并返回365或366。

        结果
        以天为单位的年份长度
      • isSupported

        default boolean isSupported​(TemporalField field)
        检查是否支持指定的字段。

        这将检查是否可以在此日期查询指定的字段。 如果是假,然后调用rangegetwith(TemporalField, long)方法会抛出异常。

        支持的字段集由年表定义,通常包括所有ChronoField日期字段。

        如果该字段不是ChronoField ,则通过调用TemporalField.isSupportedBy(TemporalAccessor)传递this作为参数来获得此方法的结果。 字段是否受支持由字段确定。

        Specified by:
        isSupported在界面 TemporalAccessor
        参数
        字段 - 要检查的字段,null返回false
        结果
        如果可以查询该字段,则为true,否则为false
      • isSupported

        default boolean isSupported​(TemporalUnit unit)
        检查指定的单元是否受支持。

        这将检查指定的单位是否可以添加到此日期或从该日期中减去。 如果为false,则调用plus(long, TemporalUnit)minus方法将引发异常。

        受支持的单位集由年表定义,通常包括除FOREVER之外的所有ChronoUnit日期单位。

        如果该单元不是ChronoUnit ,则此方法的结果是通过调用获得TemporalUnit.isSupportedBy(Temporal)传递this作为参数。 设备是否受支持由设备决定。

        Specified by:
        isSupported in interface Temporal
        参数
        unit - 要检查的单位,null返回false
        结果
        如果可以添加/减去单位,则为true,否则为false
      • with

        default ChronoLocalDate with​(TemporalAdjuster adjuster)
        返回与此对象相同类型的调整对象,并进行调整。

        这将根据指定调整程序的规则调整此日期时间。 简单的调整器可能只是设置其中一个字段,例如年份字段。 更复杂的调整器可能会将日期设置为该月的最后一天。 TemporalAdjusters提供了一系列常见调整。 这些包括找到“月的最后一天”和“下周三”。 理算员负责处理特殊情况,例如不同长度的月份和闰年。

        一些示例代码指示使用此方法的方式和原因:

          date = date.with(Month.JULY);        // most key classes implement TemporalAdjuster
          date = date.with(lastDayOfMonth());  // static import from Adjusters
          date = date.with(next(WEDNESDAY));   // static import from Adjusters and DayOfWeek 
        Specified by:
        with在界面 Temporal
        参数
        adjuster - 要使用的调整器,而不是null
        结果
        具有指定调整的相同类型的对象,而不是null
        异常
        DateTimeException - 如果无法进行调整
        ArithmeticException - 如果发生数字溢出
      • with

        default ChronoLocalDate with​(TemporalField field,
                                     long newValue)
        返回与此对象相同类型的对象,并更改指定的字段。

        这将返回基于此对象的新对象,并更改指定字段的值。 例如,在LocalDate ,这可用于设置年,月或日。 返回的对象将具有与此对象相同的可观察类型。

        在某些情况下,未完全定义更改字段。 例如,如果目标对象是代表1月31日的日期,那么将月份更改为2月将不清楚。 在这种情况下,该字段负责解析结果。 通常,它会选择上一个有效日期,这个日期是本例中2月的最后一个有效日期。

        Specified by:
        with ,界面 Temporal
        参数
        字段 - 要在结果中设置的字段,不为null
        newValue - 结果中字段的新值
        结果
        具有指定字段集的相同类型的对象,不为null
        异常
        DateTimeException - 如果无法设置该字段
        UnsupportedTemporalTypeException - 如果不支持该字段
        ArithmeticException - 如果发生数字溢出
      • plus

        default ChronoLocalDate plus​(TemporalAmount amount)
        返回与此对象相同类型的对象,并添加一个量。

        这会调整此时间,根据指定数量的规则添加。 该数量通常为Period但可以是实现TemporalAmount接口的任何其他类型,例如Duration

        一些示例代码指示使用此方法的方式和原因:

          date = date.plus(period);                // add a Period instance
          date = date.plus(duration);              // add a Duration instance
          date = date.plus(workingDays(6));        // example user-written workingDays method 

        请注意,不能保证调用plus后跟minus返回相同的日期时间。

        Specified by:
        plus ,接口 Temporal
        参数
        amount - 要添加的金额,而不是空
        结果
        具有指定调整的相同类型的对象,而不是null
        异常
        DateTimeException - 如果无法添加
        ArithmeticException - 如果发生数字溢出
      • plus

        default ChronoLocalDate plus​(long amountToAdd,
                                     TemporalUnit unit)
        返回与此对象具有相同类型的对象,并添加指定的句点。

        此方法返回基于此对象的新对象,并添加指定的时间段。 例如,在LocalDate ,这可用于添加若干年,月或日。 返回的对象将具有与此对象相同的可观察类型。

        在某些情况下,未完全定义更改字段。 例如,如果目标对象是表示1月31日的日期,则添加一个月将不清楚。 在这种情况下,该字段负责解析结果。 通常,它会选择上一个有效日期,这个日期是本例中2月的最后一个有效日期。

        Specified by:
        plus ,界面 Temporal
        参数
        amountToAdd - 要添加的指定单位的数量,可能为负数
        unit - 要添加的金额的单位,而不是空
        结果
        添加了指定期间的相同类型的对象,而不是null
        异常
        DateTimeException - 如果无法添加单位
        ArithmeticException - 如果发生数字溢出
      • minus

        default ChronoLocalDate minus​(TemporalAmount amount)
        返回与此对象相同类型的对象,并减去一定量。

        这会调整此时间,根据指定数量的规则减去。 该数量通常为Period但可以是实现TemporalAmount接口的任何其他类型,例如Duration

        一些示例代码指示使用此方法的方式和原因:

          date = date.minus(period);               // subtract a Period instance
          date = date.minus(duration);             // subtract a Duration instance
          date = date.minus(workingDays(6));       // example user-written workingDays method 

        请注意,不能保证调用plus后跟minus返回相同的日期时间。

        Specified by:
        minus在界面 Temporal
        参数
        amount - 要减去的金额,而不是空
        结果
        具有指定调整的相同类型的对象,而不是null
        异常
        DateTimeException - 如果无法进行减法
        ArithmeticException - 如果发生数字溢出
      • minus

        default ChronoLocalDate minus​(long amountToSubtract,
                                      TemporalUnit unit)
        返回与此对象相同类型的对象,并减去指定的时间段。

        此方法返回基于此对象的新对象,并减去指定的时间段。 例如,在LocalDate ,这可用于减去若干年,月或日。 返回的对象将具有与此对象相同的可观察类型。

        在某些情况下,未完全定义更改字段。 例如,如果目标对象是表示3月31日的日期,则减去一个月将不清楚。 在这种情况下,该字段负责解析结果。 通常,它会选择上一个有效日期,这个日期是本例中2月的最后一个有效日期。

        Specified by:
        minus在界面 Temporal
        参数
        amountToSubtract - 要减去的指定单位的数量,可能是负数
        unit - 要减去的金额的单位,而不是空
        结果
        减去指定时间段的相同类型的对象,不为null
        异常
        DateTimeException - 如果无法减去单位
        UnsupportedTemporalTypeException - 如果不支持该装置
        ArithmeticException - 如果发生数字溢出
      • query

        default <R> R query​(TemporalQuery<R> query)
        使用指定的查询查询此日期。

        这将使用指定的查询策略对象查询此日期。 TemporalQuery对象定义用于获取结果的逻辑。 阅读查询文档以了解此方法的结果。

        通过在指定的查询上调用TemporalQuery.queryFrom(TemporalAccessor)方法作为参数传递this来获得此方法的结果。

        Specified by:
        query在界面 TemporalAccessor
        参数类型
        R - 结果的类型
        参数
        query - 要调用的查询,而不是null
        结果
        查询结果,可以返回null(由查询定义)
        异常
        DateTimeException - 如果无法查询(由查询定义)
        ArithmeticException - 如果发生数字溢出(由查询定义)
      • adjustInto

        default Temporal adjustInto​(Temporal temporal)
        将指定的时态对象调整为与此对象具有相同的日期。

        这将返回与输入相同的可观察类型的时间对象,并将日期更改为与此相同。

        该调整是相当于使用Temporal.with(TemporalField, long)传递ChronoField.EPOCH_DAY作为字段。

        在大多数情况下,使用Temporal.with(TemporalAdjuster)更清楚地反转调用模式:

          // these two lines are equivalent, but the second approach is recommended
           temporal = thisLocalDate.adjustInto(temporal);
           temporal = temporal.with(thisLocalDate); 

        此实例是不可变的,不受此方法调用的影响。

        Specified by:
        adjustInto接口 TemporalAdjuster
        参数
        temporal - 要调整的目标对象,而不是null
        结果
        调整后的对象,不为空
        异常
        DateTimeException - 如果无法进行调整
        ArithmeticException - 如果发生数字溢出
      • until

        long until​(Temporal endExclusive,
                   TemporalUnit unit)
        根据指定的单位计算到另一个日期的时间量。

        这将根据单个TemporalUnit计算两个ChronoLocalDate对象之间的时间量。 起点和终点是this和指定的日期。 如果结束在开始之前,结果将是否定的。 所述Temporal传递给此方法被转换为ChronoLocalDate使用Chronology.date(TemporalAccessor) 计算返回一个整数,表示两个日期之间的完整单位数。 例如,可以使用startDate.until(endDate, DAYS)计算两个日期之间的天startDate.until(endDate, DAYS)

        使用此方法有两种等效方法。 第一种是调用此方法。 第二种是使用TemporalUnit.between(Temporal, Temporal)

          // these two lines are equivalent
           amount = start.until(end, MONTHS);
           amount = MONTHS.between(start, end); 
        应该根据哪个使代码更具可读性来做出选择。

        计算在此方法中针对ChronoUnit实施 单位DAYSWEEKSMONTHSYEARSDECADESCENTURIESMILLENNIAERAS应该由所有的实现支持。 其他ChronoUnit值将引发异常。

        如果该单元不是ChronoUnit ,则此方法的结果是通过调用获得TemporalUnit.between(Temporal, Temporal)传递this作为第一个参数和转换后的输入时间作为第二个参数。

        此实例是不可变的,不受此方法调用的影响。

        Specified by:
        until在界面 Temporal
        参数
        endExclusive - 结束日期,独占,在同一年表中转换为 ChronoLocalDate ,不为null
        unit - 计量金额的单位,而不是空
        结果
        此日期和结束日期之间的时间量
        异常
        DateTimeException - 如果金额无法计算,或者结束时间不能转换为 ChronoLocalDate
        UnsupportedTemporalTypeException - 如果不支持该装置
        ArithmeticException - 如果发生数字溢出
      • until

        ChronoPeriod until​(ChronoLocalDate endDateExclusive)
        计算此日期与另一个日期之间的时间段为ChronoPeriod

        这会计算两个日期之间的时间段。 所有提供的年表都使用年,月和日计算周期,但ChronoPeriod API允许使用其他单位表示周期。

        起点和终点是this和指定日期。 如果结束在开始之前,结果将是否定的。 每年,每月和每一天的负号都是相同的。

        使用该日期的年表进行计算。 如有必要,输入日期将转换为匹配。

        此实例是不可变的,不受此方法调用的影响。

        参数
        endDateExclusive - 结束日期,独占,可以是任何年代表,不为空
        结果
        此日期和结束日期之间的时间段,不为空
        异常
        DateTimeException - 如果无法计算期间
        ArithmeticException - 如果发生数字溢出
      • format

        default String format​(DateTimeFormatter formatter)
        使用指定的格式化程序格式化此日期。

        此日期将传递给格式化程序以生成字符串。

        默认实现必须如下所示:

          return formatter.format(this); 
        参数
        formatter - 要使用的格式化程序,而不是null
        结果
        格式化的日期字符串,不为null
        异常
        DateTimeException - 如果在打印期间发生错误
      • atTime

        default ChronoLocalDateTime<?> atTime​(LocalTime localTime)
        将此日期与创建ChronoLocalDateTime的时间相ChronoLocalDateTime

        这将返回在指定时间从此日期ChronoLocalDateTime形成的ChronoLocalDateTime 所有可能的日期和时间组合均有效。

        参数
        localTime - 使用的本地时间,不为空
        结果
        从此日期和指定时间形成的本地日期时间,不为空
      • toEpochDay

        default long toEpochDay()
        将此日期转换为大纪元日。

        Epoch Day count是一个简单的递增计数天,其中第0天是1970-01-01(ISO)。 对于所有年表,此定义都是相同的,从而实现转换。

        此默认实现查询EPOCH_DAY字段。

        结果
        相当于这个日期的大纪元日
      • compareTo

        default int compareTo​(ChronoLocalDate other)
        将此日期与另一个日期进行比较,包括年表。

        比较首先基于潜在的时间线日期,然后基于年表。 它与“等于”一致,如Comparable所定义。

        例如,以下是比较器顺序:

        1. 2012-12-03 (ISO)
        2. 2012-12-04 (ISO)
        3. 2555-12-04 (ThaiBuddhist)
        4. 2012-12-05 (ISO)
        值#2和#3表示时间线上的相同日期。 当两个值表示相同的日期时,将比较年表ID以区分它们。 需要此步骤以使排序“与equals一致”。

        如果要比较的所有日期对象都是相同的年表,则不需要附加的年表阶段,只使用本地日期。 要比较两个TemporalAccessor实例的日期,包括两个不同年代的日期,请使用ChronoField.EPOCH_DAY作为比较器。

        此默认实现执行上面定义的比较。

        Specified by:
        compareTo在界面 Comparable<ChronoLocalDate>
        参数
        other - 要比较的另一个日期,而不是null
        结果
        比较器值,如果更小则为负,如果更大则为正
      • isAfter

        default boolean isAfter​(ChronoLocalDate other)
        检查此日期是否在指定日期之后,忽略年表。

        这种方法与compareTo(java.time.chrono.ChronoLocalDate)中的比较不同,它只比较基础日期而不是年表。 这允许基于时间线位置比较不同日历系统中的日期。 这相当于使用date1.toEpochDay() > date2.toEpochDay()

        此默认实现基于纪元日执行比较。

        参数
        other - 要比较的另一个日期,而不是null
        结果
        如果这是在指定日期之后,则为true
      • isBefore

        default boolean isBefore​(ChronoLocalDate other)
        检查此日期是否在指定日期之前,忽略年表。

        该方法与compareTo(java.time.chrono.ChronoLocalDate)中的比较不同之处在于它仅比较基础日期而不是年表。 这允许基于时间线位置比较不同日历系统中的日期。 这相当于使用date1.toEpochDay() < date2.toEpochDay()

        此默认实现基于纪元日执行比较。

        参数
        other - 要比较的另一个日期,而不是null
        结果
        如果它在指定日期之前,则为true
      • isEqual

        default boolean isEqual​(ChronoLocalDate other)
        检查此日期是否等于忽略年表的指定日期。

        此方法与compareTo(java.time.chrono.ChronoLocalDate)中的比较不同之处在于它仅比较基础日期而非年表。 这允许基于时间线位置比较不同日历系统中的日期。 这相当于使用date1.toEpochDay() == date2.toEpochDay()

        此默认实现基于纪元日执行比较。

        参数
        other - 要比较的其他日期,而不是null
        结果
        如果基础日期等于指定日期,则为true
      • equals

        boolean equals​(Object obj)
        检查此日期是否等于另一个日期,包括年表。

        将此日期与另一个日期进行比较,确保日期和年表相同。

        要比较两个TemporalAccessor实例的日期,包括两个不同年代的日期,请使用ChronoField.EPOCH_DAY作为比较器。

        重写:
        equals在课程 Object
        参数
        obj - 要检查的对象,null返回false
        结果
        如果这等于另一个日期,则为true
        另请参见:
        Object.hashCode()HashMap
      • toString

        String toString()
        将此日期输出为String

        输出将包括完整的本地日期。

        重写:
        toString在课程 Object
        结果
        格式化日期,不为空