了解一个月的天数计算

问题描述 投票:0回答:1

我在Gist中找到了这段代码,它计算一个月中的最后一天(或者换句话说:一个月中的天数):

private fun lastDayInMonth(month: Int, year: Int): Int {
    return if (month != 2) {
        31 - (month - 1) % 7 % 2
    } else {
        if (year and 3 == 0 && (year % 25 != 0 || year and 15 == 0)) {
            29
        } else {
            28
        }
    }
}

有人可以解释一下这是如何以及为什么有效的吗?这是哪种算法,有名字或知名作者吗?

kotlin date datetime math calendar
1个回答
0
投票

一个月的天数规则

在看代码之前,首先让我们看看规则是什么。它们分为两部分:

  1. 忽略二月,月份 (a) 31 天和 30 天交替,持续六个月,然后 (b) 31 天和 30 天交替,持续五个月。

  2. 要确定二月,我们需要知道它是否是闰年。闰年的规则是1:

    能被四整除的每一年都是闰年,能被100整除的年份除外,但如果能被400整除,这些百年年就是闰年。

    这分为三部分:如果能被 4 整除,一年就是闰年,但如果能被 100 整除则不是闰年,但如果能被 400 整除就是闰年。

代码

代码遵循类似的方法。

  1. 首先,代码计算出非二月中的天数。它使用表达式

    (month - 1) % 7 % 2
    ,在0和1之间振荡,在适当的月份调整31到30天。
    % 2
    进行定期交替,并
    % 7
    在 8 月及以后“重置”((b) 部分)。

  2. 对于闰年,代码遵循相同的三部分包含/排除方法。它通过以下方式做到这一点:

    1. 通过使用按位 AND 检查是否

      year and 3 == 0
      来计算年份是否可以被 4 整除。要了解这一点,请观察当且仅当最后两个二进制数字中包含 00 时,年份才能被 4 整除,并且这些数字是唯一在按位 AND 与 3 进行比较时给出 0 的数字。

    2. 如果检查年份是否能被 25 整除,则计算年份是否能被 100 整除。这必须与我们从 1. 知道年份能被 4 整除的情况相同,如果这部分要改变最终结果,并且能被 4 整除的数字,当且仅当能被 100 整除的数字。

    3. 通过检查年份是否能被 16 整除来确定年份是否能被 400 整除(使用类似于 1. 的按位 AND 方法)。如果这是真的,并且它将改变表达式的结果,那么年份也一定能被 25 整除。这意味着这相当于计算出年份是否能被 400 整除,因为数字能被 400 整除当且仅当它能同时被 25 和 16 整除(观察 25 x 16 = 400)。

结论

所以,计算已经相当简洁地表达了月日计算。尽管使用现代编译器,我怀疑按位运算是否比模运算更快。

这是哪种算法,有名字或知名作者吗?

它并不是真正的算法,而是以简洁的方式用代码表达众所周知的规则。


1 https://en.wikipedia.org/wiki/Gregorian_calendar

© www.soinside.com 2019 - 2024. All rights reserved.