【问题标题】:Java 8 LocalDate- determining the year of a yearless Feb-29 date?Java 8 LocalDate-确定无年的 2 月 29 日的年份?
【发布时间】:2015-04-30 17:22:38
【问题描述】:

我和我的同事有一个有趣的问题。我们使用的旧系统只返回ddMMM 格式的日期数据。如果当年的日期/月份是过去的,那么我们将假设该日期适用于明年。否则适用于当年。

所以今天是4/30/2015。如果系统返回带有12MAR 的记录,则该日期将转换为3/12/2016。如果日期为07MAY,则转换为5/7/2015

但是,由于是闰年,因此尚不清楚如何确定 29FEB 的年份。我们不能用一年来实例化它而不会引发错误。在尝试为当前年份创建 LocalDate 时,我们依赖于 try/catch。如果它抓住了,我们假设它属于明年。

有没有更洁净的方式来做到这一点?

【问题讨论】:

    标签: java date java-8 jodatime


    【解决方案1】:
    • 将值解析为 MonthDay,因为这就是您所拥有的。
    • 如果月-日不是 2 月 29 日,则照常处理
    • 如果 2 月 29 日,您需要对其进行特殊处理:
      • Year.isLeap(long) 判断当前年份是否为闰年
      • 如果是:
      • 如果当前是 2 月 29 日或之前,则结果是今年的 2 月 29 日
      • 如果当前是 2 月 29 日之后,您需要申请规则 - 您可以选择明年 3 月 1 日或明年 2 月 28 日
      • 如果不是(今年是闰年)
      • 如果目前是 2 月 28 日或之前,您需要再次申请规则,可能会在今年 3 月 1 日或 2 月 28 日返回
      • 如果当前是 2 月 28 日之后,那么该日期在逻辑上属于明年...
        • 如果明年是闰年,结果大概是明年2月29日
        • 如果明年不是闰年,那么您再次需要一个规则

    希望这概述了您需要考虑的三个“奇怪”情况 - 我们没有足够的信息来告诉您在这些情况下该怎么做。

    【讨论】:

      【解决方案2】:

      java.time

      现代方法是使用 java.time 类。具体来说,MonthDay 在您的情况下。

      请注意,您应始终指定 Locale 以确定在翻译月份名称时使用的人类语言。

      DateTimeFormatter f = DateTimeFormatter.ofPattern( "ddMMM" , Locale.ENGLISH );
      
      String input = "29FEB";
      MonthDay md = MonthDay.parse( input , f );
      

      您可以将其应用于年份以获取LocalDate 对象,即年-月-日的仅日期值。

      LocalDate

      LocalDate 类表示没有时间和时区的仅日期值。

      时区对于确定日期至关重要。对于任何给定的时刻,日期在全球范围内因区域而异。例如,Paris France 中午夜后几分钟是新的一天,而 Montréal Québec 中仍然是“昨天”。

      ZoneId z = ZoneId.of( "America/Montreal" );
      LocalDate today = LocalDate.now( z );
      

      如果我们正在查看 2 月 29 日,请检查闰年。如果这不是闰年,那么你说你想搬到明年。但如果明年也不是闰年呢?你需要继续前进,直到你到达闰年。

      int yearNumber today.getYear();
      LocalDate ld = null;
      if( md.equals( MonthDay.of( 2 , 29 )  && ( ! Year.of( today ).isLeap() ) ) { 
          // If asking for February 29, and this is not a leap year, move to next year, per our business rule.
          … keep adding years until you find a year that *is* a leap year.
          ld = md.atYear( yearNumber + x ); 
      } else {
          ld = md.atYear( yearNumber );
      }
      

      回落到 28 日

      如果月日是非闰年的 2 月 29 日,则此问题有一个特殊的业务规则,即跳转到下一年。但是对于其他人来说,请注意 java.time 中的默认行为是在要求 29 日为非闰年时简单地退回到 2 月 28 日。不抛出异常。

      LocalDate february28 = 
          MonthDay.of( 2 , 29 )
                  .atYear( myNonLeapYearNumber );  // 29th becomes 28th.
      

      关于java.time

      java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date.Calendarjava.text.SimpleDateFormat

      Joda-Time 项目现在位于 maintenance mode,建议迁移到 java.time。

      要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

      从哪里获得 java.time 类?

      ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

      【讨论】:

        猜你喜欢
        • 2016-06-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-26
        • 1970-01-01
        • 2019-01-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多