Module java.base
Package java.time.chrono

Interface ChronoLocalDate

所有超接口:
Comparable<ChronoLocalDate>, Temporal, TemporalAccessor, TemporalAdjuster
所有已知实现类:
HijrahDate, JapaneseDate, LocalDate, MinguoDate, ThaiBuddhistDate

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

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

ChronoLocalDate是日期的抽象表示,其中Chronology chronology或日历系统是可插拔的。日期是根据由TemporalField表示的字段定义的,其中大多数常见实现在ChronoField中定义。日历系统定义了日历系统的操作方式和标准字段的含义。

何时使用此接口

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

这个概念起初可能会令人惊讶,因为全球化应用程序的自然方式最初似乎是抽象化日历系统。然而,正如下面所探讨的,抽象化日历系统通常是错误的方法,会导致逻辑错误和难以找到的错误。因此,应该将选择使用这个接口而不是LocalDate视为应用程序范围的架构决策。

需要考虑的架构问题

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

1) 使用这个接口的应用程序,而不仅仅使用LocalDate,面临着更高概率的错误。这是因为在开发时不知道使用的日历系统。错误的一个主要原因是开发人员将他们对ISO日历系统的日常知识的假设应用于旨在处理任意日历系统的代码。下面的部分概述了这些假设如何导致问题。减少这种增加的错误风险的主要机制是强有力的代码审查过程。这也应该被视为代码寿命维护中的额外成本。

2) 这个接口不强制实现的不可变性。虽然实现说明指出所有实现必须是不可变的,但代码或类型系统中没有任何内容来强制执行这一点。因此,声明接受ChronoLocalDate的任何方法可能会传递一个编写不良或恶意的可变实现。

3) 使用这个接口的应用程序必须考虑时代的影响。LocalDate通过确保getYear()返回推测年份来屏蔽用户对时代的概念。这个决定确保开发人员可以将LocalDate实例视为由三个字段组成 - 年、年份和月份。相比之下,使用这个接口的用户必须将日期视为由四个字段组成 - 时代、年份、月份和日期。额外的时代字段经常被遗忘,但对于任意日历系统中的日期来说,它是至关重要的。例如,在日本日历系统中,时代代表一位天皇的统治。每当一位天皇的统治结束并另一位开始时,年份将重置为一。

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

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

6) 大多数情况下,在整个应用程序中传递ChronoLocalDate是不必要的,如下面的最后一节所讨论的。

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

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

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

将12个月添加到日期并假设已添加一年是无效的。一些日历系统有不同数量的月份,比如科普特或埃塞俄比亚有13个月。

将一个月添加到日期并假设月份值将增加一个或转到下一年是无效的。一些日历系统在一年中有可变数量的月份,比如希伯来历。

添加一个月,然后再添加一个月,并假设日期将保持接近其原始值是无效的。一些日历系统中最长月份和最短月份之间的差异很大。例如,科普特或埃塞俄比亚有12个30天的月份和1个5天的月份。

添加七天并假设已添加一周是无效的。一些日历系统的一周不是七天,比如法国革命历。

假设因为date1的年份大于date2的年份,所以date1date2之后是无效的。这对于所有日历系统来说都是无效的,当涉及到年代时尤其如此,尤其是对于日本日历系统,其中每位新天皇的统治都会重新开始年代。

将一月一日和一年的开始视为无效。并非所有日历系统都在月值为一时开始新的一年。

总的来说,在开发时不知道日历系统时,操作日期甚至查询日期都很容易出现错误。这就是为什么使用这个接口的代码必须经过额外的代码审查。这也是为什么避免使用这种接口类型通常是正确的架构决策。

使用LocalDate代替

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

如上所述,在可插拔规则的日历系统上执行计算需要技巧,不建议这样做。幸运的是,在任意日历系统中执行日期计算的需求非常罕见。例如,图书馆图书租赁方案的业务规则几乎不太可能允许租赁一个月,其中月份的含义取决于用户首选的日历系统。

在系统的任何其他部分中,必须在ISO之外的日历系统中操作日期时,用例通常会指定要使用的日历系统。例如,应用程序可能需要计算下一个伊斯兰或希伯来节日,这可能需要操作日期。这种用例可以如下处理:

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

可以向系统添加其他日历系统。有关更多详细信息,请参阅Chronology

自从:
1.8
  • Method Details

    • timeLineOrder

      static Comparator<ChronoLocalDate> timeLineOrder()
      获取一个比较器,按时间顺序比较ChronoLocalDate,忽略年表。

      此比较器与compareTo(java.time.chrono.ChronoLocalDate)中的比较不同,因为它仅比较基础日期而不比较年表。这允许根据日期在本地时间线上的位置比较不同日历系统中的日期。基础比较等同于比较纪元日。

      返回:
      一个比较器,按时间顺序比较,忽略年表
      参见:
    • from

      static ChronoLocalDate from(TemporalAccessor temporal)
      从临时对象获取ChronoLocalDate的实例。

      根据指定的临时对象获取本地日期。 TemporalAccessor表示一组任意的日期和时间信息,此工厂将其转换为ChronoLocalDate的实例。

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

      此方法与函数接口TemporalQuery的签名匹配,允许通过方法引用ChronoLocalDate::from使用作为查询。

      参数:
      temporal - 要转换的临时对象,不能为空
      返回:
      日期,不能为空
      抛出:
      DateTimeException - 如果无法转换为ChronoLocalDate
      参见:
    • 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)
      检查是否支持指定字段。

      检查指定字段是否可以在此日期上查询。如果为false,则调用rangegetwith(TemporalField, long)方法将抛出异常。

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

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

      在接口中指定:
      isSupported in interface TemporalAccessor
      参数:
      field - 要检查的字段,null返回false
      返回:
      如果字段可以查询,则为true,否则为false
    • isSupported

      default boolean isSupported(TemporalUnit unit)
      检查是否支持指定单位。

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

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

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

      在接口中指定:
      isSupported in interface Temporal
      参数:
      unit - 要检查的单位,null返回false
      返回:
      如果单位可以添加/减去,则为true,否则为false
    • with

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

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

      以下是示例代码,说明了此方法的使用方式和原因:

        date = date.with(Month.JULY);        // 大多数关键类实现TemporalAdjuster
        date = date.with(lastDayOfMonth());  // 从Adjusters进行静态导入
        date = date.with(next(WEDNESDAY));   // 从Adjusters和DayOfWeek进行静态导入
       
      在接口中指定:
      with in interface Temporal
      参数:
      adjuster - 要使用的调整器,不能为空
      返回:
      具有指定调整的相同类型的对象,不能为空
      抛出:
      DateTimeException - 如果无法进行调整
      ArithmeticException - 如果发生数值溢出
    • with

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

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

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

      指定者:
      with 在接口 Temporal
      参数:
      field - 要在结果中设置的字段,不能为空
      newValue - 结果中字段的新值
      返回:
      具有指定字段设置的相同类型的对象,不能为空
      抛出:
      DateTimeException - 如果无法设置字段
      UnsupportedTemporalTypeException - 如果不支持该字段
      ArithmeticException - 如果发生数值溢出
    • plus

      default ChronoLocalDate plus(TemporalAmount amount)
      返回与此对象类型相同的对象,其中添加了一定数量的值。

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

      以下是一些示例代码,说明了此方法的使用方式和原因:

        date = date.plus(period);                // 添加一个Period实例
        date = date.plus(duration);              // 添加一个Duration实例
        date = date.plus(workingDays(6));        // 示例用户编写的workingDays方法
       

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

      指定者:
      plus 在接口 Temporal
      参数:
      amount - 要添加的数量,不能为空
      返回:
      具有指定调整的相同类型的对象,不能为空
      抛出:
      DateTimeException - 如果无法进行添加
      ArithmeticException - 如果发生数值溢出
    • plus

      default ChronoLocalDate plus(long amountToAdd, TemporalUnit unit)
      返回与此对象类型相同的对象,其中添加了指定的周期。

      此方法返回一个基于此对象的新对象,其中添加了指定的周期。例如,在LocalDate上,可以用于添加一定数量的年、月或日。返回的对象将具有与此对象相同的可观察类型。

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

      指定者:
      plus 在接口 Temporal
      参数:
      amountToAdd - 要添加的指定单位的数量,可以为负数
      unit - 要添加的数量的单位,不能为空
      返回:
      具有指定周期添加的相同类型的对象,不能为空
      抛出:
      DateTimeException - 如果无法添加该单位
      ArithmeticException - 如果发生数值溢出
    • minus

      default ChronoLocalDate minus(TemporalAmount amount)
      返回与此对象类型相同的对象,其中减去了一定数量的值。

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

      以下是一些示例代码,说明了此方法的使用方式和原因:

        date = date.minus(period);               // 减去一个Period实例
        date = date.minus(duration);             // 减去一个Duration实例
        date = date.minus(workingDays(6));       // 示例用户编写的workingDays方法
       

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

      指定者:
      minus 在接口 Temporal
      参数:
      amount - 要减去的数量,不能为空
      返回:
      具有指定调整的相同类型的对象,不能为空
      抛出:
      DateTimeException - 如果无法进行减法
      ArithmeticException - 如果发生数值溢出
    • minus

      default ChronoLocalDate minus(long amountToSubtract, TemporalUnit unit)
      返回与此对象类型相同的对象,其中减去了指定的周期。

      此方法返回一个基于此对象的新对象,其中减去了指定的周期。例如,在LocalDate上,可以用于减去一定数量的年、月或日。返回的对象将具有与此对象相同的可观察类型。

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

      指定者:
      minus 在接口 Temporal
      参数:
      amountToSubtract - 要减去的指定单位的数量,可以为负数
      unit - 要减去的数量的单位,不能为空
      返回:
      具有指定周期减去的相同类型的对象,不能为空
      抛出:
      DateTimeException - 如果无法减去该单位
      UnsupportedTemporalTypeException - 如果不支持该单位
      ArithmeticException - 如果发生数值溢出
    • query

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

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

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

      指定者:
      query 在接口 TemporalAccessor
      类型参数:
      R - 结果的类型
      参数:
      query - 要调用的查询,不能为空
      返回:
      查询结果,可能返回null(由查询定义)
      抛出:
      DateTimeException - 如果无法查询(由查询定义)
      ArithmeticException - 如果发生数值溢出(由查询定义)
    • adjustInto

      default Temporal adjustInto(Temporal temporal)
      调整指定的时间对象,使其具有与此对象相同的日期。

      返回一个具有与输入相同的可观察类型的时间对象,日期更改为与此相同。

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

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

         // 这两行代码是等效的,但推荐第二种方法
         temporal = thisLocalDate.adjustInto(temporal);
         temporal = temporal.with(thisLocalDate);
       

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

      指定者:
      adjustInto 在接口 TemporalAdjuster
      参数:
      temporal - 要调整的目标对象,不能为空
      返回值:
      调整后的对象,不能为空
      抛出:
      DateTimeException - 如果无法进行调整
      ArithmeticException - 如果发生数值溢出
    • until

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

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

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

         // 这两行是等效的
         amount = start.until(end, MONTHS);
         amount = MONTHS.between(start, end);
       
      应根据哪种方法使代码更易读来进行选择。

      此方法中实现了ChronoUnit的计算。单位DAYSWEEKSMONTHSYEARSDECADESCENTURIESMILLENNIAERAS应该由所有实现支持。其他ChronoUnit值将抛出异常。

      如果单位不是ChronoUnit,则通过调用TemporalUnit.between(Temporal, Temporal)并将this作为第一个参数、转换后的输入时间作为第二个参数来获取此方法的结果。

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

      指定者:
      until 在接口 Temporal
      参数:
      endExclusive - 结束日期(不包括),将在相同年表中转换为ChronoLocalDate,不能为空
      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 - 要使用的格式化程序,不能为空
      返回值:
      格式化的日期字符串,不能为空
      抛出:
      DateTimeException - 在打印过程中发生错误
    • atTime

      default ChronoLocalDateTime<?> atTime(LocalTime localTime)
      将此日期与时间组合以创建ChronoLocalDateTime

      这将返回一个由此日期和指定时间形成的ChronoLocalDateTime。日期和时间的所有可能组合都是有效的。

      参数:
      localTime - 要使用的本地时间,不能为空
      返回值:
      由此日期和指定时间形成的本地日期时间,不能为空
    • toEpochDay

      default long toEpochDay()
      将此日期转换为Epoch Day。

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

      此默认实现查询EPOCH_DAY字段。

      返回值:
      等效于此日期的Epoch Day
    • compareTo

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

      比较首先基于基础时间线日期,然后基于年表。它是“与equals一致”的,如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作为比较器。

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

      指定者:
      compareTo 在接口 Comparable<ChronoLocalDate>
      参数:
      other - 要比较的另一个日期,不能为空
      返回值:
      比较器值,即此本地日期与other本地日期和此年表与other年表的比较,按顺序返回第一个非零结果,否则返回零
      参见:
    • isAfter

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

      此方法与compareTo(java.time.chrono.ChronoLocalDate)中的比较不同,因为它仅比较基础日期而不比较年表。这允许根据时间线位置比较不同日历系统中的日期。这等效于使用date1.toEpochDay() > date2.toEpochDay()

      此默认实现基于epoch-day执行比较。

      参数:
      other - 要比较的另一个日期,不能为空
      返回值:
      如果此日期在指定日期之后,则为true
    • isBefore

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

      此方法与compareTo(java.time.chrono.ChronoLocalDate)中的比较不同,因为它仅比较基础日期而不比较年表。这允许根据时间线位置比较不同日历系统中的日期。这等效于使用date1.toEpochDay() < date2.toEpochDay()

      此默认实现基于epoch-day执行比较。

      参数:
      other - 要比较的另一个日期,不能为空
      返回值:
      如果此日期在指定日期之前,则为true
    • isEqual

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

      此方法与compareTo(java.time.chrono.ChronoLocalDate)中的比较不同,因为它仅比较基础日期而不比较年表。这允许根据时间线位置比较不同日历系统中的日期。这等效于使用date1.toEpochDay() == date2.toEpochDay()

      此默认实现基于epoch-day执行比较。

      参数:
      other - 要比较的另一个日期,不能为空
      返回值:
      如果基础日期等于指定日期,则为true
    • equals

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

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

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

      覆盖:
      equals 在类 Object
      参数:
      obj - 要检查的对象,null返回false
      返回:
      如果此日期等于另一个日期,则为true
      参见:
    • hashCode

      int hashCode()
      此日期的哈希码。
      覆盖:
      hashCode 在类 Object
      返回:
      适当的哈希码
      参见:
    • toString

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

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

      覆盖:
      toString 在类 Object
      返回:
      格式化的日期,不为null