【问题标题】:javascript to find leap yearjavascript查找闰年
【发布时间】:2011-12-31 19:26:05
【问题描述】:

当我有一个月的 2 月时,如何让下面的代码工作?目前它正在到达当天,然后在到达 if 之前停止,以确定它是否是闰年。

 if (month == 2) {
    if (day == 29) {
        if (year % 4 != 0 || year % 100 == 0 && year % 400 != 0) {
            field.focus();
             field.value = month +'/' +  '';
        }
    }
    else if (day > 28) {
        field.focus();
             field.value = month +'/' +  '';
    }
}

【问题讨论】:

  • “停止”如何?有错误吗?
  • 它从不评估年份以查看是否是闰年它直接进入 field.focus 和 field.value 是否是闰年
  • 您的条件看起来有点奇怪 - 因为它们现在是现在编写的,您只检查 day 的值是否为 29 或更大(基于 day == 29day > 28 if 子句)。我假设您打算写day <= 28,但如果是这种情况,您可以删除第二个else if 子句并直接使用else 子句。在闰年条款中添加一组额外的括号也可能更安全:if (year % 4 != 0 || (year % 100 == 0 && year % 400 != 0))
  • 您可能需要展示一些有关如何设置这些变量的代码。如果您使用的是 Date 对象,请记住它使用从零开始的月份。

标签: javascript date textfield leap-year


【解决方案1】:

Date objects 用于日期时间的东西会更安全,例如

isLeap = new Date(year, 1, 29).getMonth() == 1

由于人们一直在问这到底是如何工作的,这与 JS 如何计算年月日的日期值有关(详情here)。基本上,它首先计算每月的第一天,然后将 N -1 天添加到它。因此,当我们要求非闰年的 2 月 29 日时,结果将是 2 月 1 日 + 28 天 = 3 月 1 日:

> new Date(2015, 1, 29)
< Sun Mar 01 2015 00:00:00 GMT+0100 (CET)

闰年,2 月 1 日 + 28 = 2 月 29 日:

> new Date(2016, 1, 29)
< Mon Feb 29 2016 00:00:00 GMT+0100 (CET)

在上面的代码中,我将日期设置为 2 月 29 日,并查看是否发生了翻转。如果不是(月份仍为 1,即二月),则为闰年,否则为非闰年。

【讨论】:

  • 天哪。真是个黑客。 :)
  • 仅用于低容量场景,因为这比使用 isLeap = !((yr % 4) || (!(yr % 100) &amp;&amp; (yr % 400))); jsperf.com/ily/7 之类的东西慢大约 100 倍
  • == 1 在这里做什么?
  • @RymanHolmes JavaScript 的 Date 对象中的月份是零索引的。在闰年,第 1 个月(二月)的第 29 天有效,因此 getMonth() 返回 1(二月)。在非闰年,JavaScript 将 2 月 29 日“更正”为 3 月 1 日,因此 getMonth() 将返回 2(3 月)。
  • 这在 IE11 上不起作用,因为在生成的 Date() 对象中通过 2 月 29 日的获取已更正为 2 月 28 日。因此返回 1 并错误地标记为闰年。
【解决方案2】:

与使用 new Date() 相比,这大约快 100 倍!

更新:

这个最新版本使用了底部 3 位的位测试(它是 4 的倍数),以及检查年份是 16 的倍数(二进制的底部 4 位是 15)和倍数25 个。

ily = function(y) {return !(y & 3 || !(y % 25) && y & 15);};

http://jsperf.com/ily/15

又比我之前的版本稍微快一点(下):

ily = function(yr) {return !((yr % 4) || (!(yr % 100) && (yr % 400)));};

http://jsperf.com/ily/7

与 broc.seib 已经很快的条件运算符版本相比,它也快了 5%

速度测试结果:http://jsperf.com/ily/6

预期的逻辑测试结果:

alert(ily(1900)); // false
alert(ily(2000)); // true
alert(ily(2001)); // false
alert(ily(2002)); // false
alert(ily(2003)); // false
alert(ily(2004)); // true
alert(ily(2100)); // false
alert(ily(2400)); // true

【讨论】:

    【解决方案3】:
    isLeap = !(new Date(year, 1, 29).getMonth()-1)
    

    ...在大多数 CPU 架构上,减一应该比比较更快。

    【讨论】:

    • 如果您需要每秒计算 1000 次,我可能会同意,但是当它们之间的速度差异几乎可以忽略不计时,可读性应该胜过速度。
    • 刚刚进行了一些速度测试,new Date 比使用布尔逻辑(比如!((yr % 4) || (!(yr % 100) &amp;&amp; (yr % 400))))慢了大约 100 倍。你可以说为了速度,我现在已经把这个可读性抛到了窗外,但 100 次可能是值得的 :)
    【解决方案4】:

    正确且快速:

    ily = function(yr) { return (yr%400)?((yr%100)?((yr%4)?false:true):false):true; }
    

    如果您处于循环中或计算纳秒,这比通过新的 Date() 对象运行您的年份快两个数量级。在此处比较性能:http://jsperf.com/ily

    【讨论】:

    • 由于这只是将布尔比较与布尔结果相结合,因此您可以不使用条件运算符而仅使用 &&、|| 和短路来表达这一点。也快 5% 左右:jsperf.com/ily/6
    • 你现在知道否定是什么了吗?
    【解决方案5】:

    更好的闰年历史计算。

    下面的代码考虑到闰年是在公元前 45 年与儒略历一起引入的,而西方世界的大部分地区在公元 1582 年采用公历,而公元 0 年 = 公元前 1 年。

    isLeap = function(yr) {
      if (yr > 1582) return !((yr % 4) || (!(yr % 100) && (yr % 400)));
      if (yr >= 0) return !(yr % 4);
      if (yr >= -45) return !((yr + 1) % 4);
      return false;
    };
    

    英国及其殖民地在 1752 年采用了公历,所以如果您更以盎格鲁为中心,这个版本会更好(我们假设英国从公元 43 年开始采用儒略历和罗马征服)。

    isLeap = function(yr) {
      if (yr > 1752) return !((yr % 4) || (!(yr % 100) && (yr % 400)));
      if (yr >= 43) return !(yr % 4);
      return false;
    };
    

    【讨论】:

    • + 用于历史课程。现在的问题是:闰年没有追溯引入吗?
    【解决方案6】:

    我之所以使用这个,是因为我讨厌一直将一月称为 0,二月称为 1。 对我和 PHP 和可读日期来说,二月 = 2。我知道这并不重要,因为数字永远不会改变,但它只是让我的大脑在不同的代码中思考相同。

    var year = 2012;
    var isLeap = new Date(year,2,1,-1).getDate()==29;
    

    【讨论】:

      【解决方案7】:

      您可以通过momentjs 调用.isLeapYear() 轻松实现此功能:

      var notLeapYear = moment('2018-02-29')
      console.log(notLeapYear.isLeapYear()); // false
      
      var leapYear = moment('2020-02-29')
      console.log(leapYear.isLeapYear()); // true
      &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.21.0/moment.min.js"&gt;&lt;/script&gt;

      【讨论】:

        【解决方案8】:

        一站式服务?

        const isLeapYear = (year) => (year % 100 === 0 ? year % 400 === 0 : year % 4 === 0);
        
        console.log(isLeapYear(2016)); // true
        console.log(isLeapYear(2000)); // true
        console.log(isLeapYear(1700)); // false
        console.log(isLeapYear(1800)); // false
        console.log(isLeapYear(2020)); // true
        

        【讨论】:

          【解决方案9】:
          function isLeap(year) {   
              if ( (year % 4 === 0 && year % 100 !== 0) || (year % 4 === 0 && year % 100 === 0 && year % 400 === 0) ) {
                  return 'Leap year.'
              } else {
                  return 'Not leap year.';
              }
          }
          

          【讨论】:

            【解决方案10】:

            伪代码

            if year is not divisible by 4 then not leap year
            else if year is not divisible by 100 then leap year
            else if year is divisible by 400 then leap year
            else not leap year
            

            JavaScript

            function isLeapYear (year) {
                return year % 4 == 0 && ( year % 100 != 0 || year % 400 == 0 )
            }
            

            如果year 不能被 4 整除,则使用上述代码可确保每个 year 只进行一次检查 只需添加括号,您就可以为每个 year 节省 2 个不能被 4 整除的检查

            【讨论】:

              【解决方案11】:

              另一种方法是查看该年份是否有 2 月 29 日。如果确实有这个日期,那么您就知道这是闰年。

              ES6

              // Months are zero-based integers between 0 and 11, where Febuary = 1
              const isLeapYear = year => new Date(year, 1, 29).getDate() === 29;
              

              测试

              > isLeapYear(2016);
              < true
              > isLeapYear(2019);
              < false
              

              【讨论】:

                【解决方案12】:
                function leapYear(year){
                    if((year%4==0) && (year%100 !==0) || (year%400==0)){
                        return true;
                    }
                    else{
                        return false;
                    }
                }
                var result = leapYear(1700);
                console.log(result);
                

                【讨论】:

                • 虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高​​答案的长期价值。
                【解决方案13】:

                预计 JavaScript 将获得一个新的日期/时间 API,它公开一个新的全局对象 - Temporal。这个全局对象为 JS 开发人员提供了一种更好的方式来处理日期/时间。它目前是一个stage 3 提案,应该很快就能使用。

                时间 API 公开了一个用于检查闰年的好属性 - inLeapYear。如果特定日期是闰年,则返回 true,否则返回 false。下面我们使用with()plainDateISO 返回的日期转换为我们特定年份的日期:

                const isLeap = year => Temporal.now.plainDateISO().with({year}).inLeapYear;
                console.log(isLeap(2020)); // true
                console.log(isLeap(2000)); // true
                console.log(isLeap(1944)); // true
                
                console.log(isLeap(2021)); // false
                console.log(isLeap(1999)); // false
                

                如果你只是想检查你当前的系统日期时间是否是闰年,你可以省略.with()

                // true if this year is a leap year, false if it's not a leap year
                const isLeap = Temporal.now.plainDateISO().inLeapYear; 
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2022-12-10
                  • 2021-05-19
                  • 2013-04-27
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2021-01-28
                  相关资源
                  最近更新 更多