【问题标题】:Java conventions for checking leap year [duplicate]检查闰年的Java约定[重复]
【发布时间】:2018-04-09 08:45:03
【问题描述】:

根据我教科书中的代码,以及我在网上找到的相同代码,在 Java 中检查闰年看起来像这样:

if (month == 2 && day == 29 && !(year % 400 == 0 || 
       (year % 4 == 0 && year % 100 != 0))) {
     // don't do stuff because it's not leap year
  }

我的问题是:你为什么不能这样写?

if (month == 2 && day == 29 && !(year % 4 == 0)) {
    // don't do stuff because it's not leap year
}

闰年可以被 4 整除。因此,如果 (year % 4 == 0) 不正确,那么无论您如何削减它,那么您的年份不是闰年并且该陈述是错误的。那里的额外代码似乎是多余的。为什么我的教科书要我这样写?是否有某种我不知道的 Java 约定?

【问题讨论】:

  • Leap year is divisible by 4 这不是真的,en.wikipedia.org/wiki/Leap_year
  • 这些额外的天数以 4 的倍数为单位出现(除了可以被 100 整除但不能被 400 整除的年份)
  • 这不是您不知道的“与 Java 的某种约定”,而是与 公历 的约定。世纪年(可被 100 整除)即使能被 4 整除,也不是闰年,除非它们能被 400 整除。因此,1796 年和 1804 年:闰年,1800 年不能; 1896 和 1904:闰年,1900 不是; 1996、2000、2004:所有闰年; 2096 和 2104:闰年,2100 不是。
  • 使用 Java 8 Year 类。 Year.isLeap(2000) 返回trueYear.isLeap(1999) 返回falseYear.isLeap(2100) 返回 false 因为公历规则说它应该这样做。
  • 对于那些不赞成 Q 和 A 的傻瓜,这是一个有效的问题。大多数人被教导闰年是任何能被 4 整除的年份。知道这件事的人都知道这是不真实的。但我敢打赌,你 10 岁或 60 岁的父亲不会。大多数人甚至不知道“格里高利”是什么意思。

标签: java conventions


【解决方案1】:

我的问题是。为什么不能这样写?

if (month == 2 && day == 29 && !(year % 4 == 0)) {
   // don't do stuff because it's not leap year
}

嗯......你可以,但它不会给出 1900 年、2100 年等年份的正确答案1。更复杂的版本是正确的。

基本上,在公历中确定给定年份何时是闰年的规则比您在小学学到的要复杂得多。如果您想了解更多详情:

另请注意,公历并不完美,如here 所述。然而,它在传统实践中是如此根深蒂固,以至于用于“修复”感知问题的各种calendrical reform proposals 并没有太大的机会。 (至少,当人类在地球上时不是这样的:-))


我只是想弄清楚为什么文本提供的 if 语句的条件比它实际需要的要多...

因为,条件确实需要。见上文!


从 Java 软件工程的角度来看,一个更好的主意是使用 Java 8 java.time API 来测试闰年,而不是自己编写代码(并且可能会出错!)。


1 - 你可能会说:“我的代码不需要在 2100 年工作,因为在那之前我会死”。对此有一个简单的两个字反驳。 “千年虫”。

【讨论】:

    【解决方案2】:

    您问题中的第一段代码是正确的,如(根据维基百科):

    在公历中,每个闰年有 366 天,而不是通常的 365 天,将 2 月延长到 29 天,而不是常见的 28 天。这些额外的天数以 4 的倍数出现(除了可整除的年份) 100,但不是 400)。

    虽然我使用 Java 8 的 java.time 包检查闰年的方式是这样的:

    boolean isLeapYear = Year.now().isLeap();
    

    如果你想检查是不是 2 月 29 日,你可以使用

    boolean is29Feb = MonthDay.now().getDayOfMonth() == 29 && YearMonth.now().getMonth() == Month.FEBRUARY;
    

    【讨论】:

      【解决方案3】:

      如果您可以使用该库,我更喜欢它,它会删除错误检查。

      public static boolean isLeapYear(int year) {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, year);
        return cal.getActualMaximum(Calendar.DAY_OF_YEAR) > 365;
      }
      

      这是非常标准的代码,您可以在任何地方获取。

      【讨论】:

      • Nitpick:我认为 OP 实际上是在检查闰日。
      • 通过阅读这篇文章我很确定它是闰年。是什么让你说闰日?而且只有 2 月 29 日,对吧?
      • @NathanHughes 标题似乎另有说明?
      • @Scary:发布的代码检查特定日期。我认为 OP 的术语不够严谨。既然有 jdk8 新的热度,为什么还要给老旧的日历 API?
      • 这是对两者的一种检查。如果您向应用提供日期 2 月 29 日和一年。它检查以确保年份实际上是闰年,否则它会抛出 IllegalArgumentException
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-14
      • 1970-01-01
      相关资源
      最近更新 更多