任何月份的天数

Bry*_*ett 18 javascript date

我如何编写一个JavaScript函数来接受代表一年中1到12个月的数字,然后返回该月的天数?

Jam*_*mes 51

function getDaysInMonth(m, y) {
   return /8|3|5|10/.test(--m)?30:m==1?(!(y%4)&&y%100)||!(y%400)?29:28:31;
}
Run Code Online (Sandbox Code Playgroud)

  • 呵呵 - 穷人必须检查这样的作业是否正确;) (8认同)
  • 请原谅这个神秘的本质; 我无法帮助它:D (7认同)
  • 布莱恩哈哈特没有理解这个......哈哈哈 (6认同)
  • 诗意.我能听到我脑袋里的韵律;) (5认同)
  • 你应该把这个提交给@ 140bytes (5认同)

Cal*_*leb 45

试试这个:

function numberOfDays(year, month) {
    var d = new Date(year, month, 0);
    return d.getDate();
}
Run Code Online (Sandbox Code Playgroud)

因为闰年你也需要过年.

  • @Crescent Fresh:好的,我知道现在发生了什么.这个月需要从中减去1以纠正零索引,但是后来使用的策略是检查下个月(即,将月份加1,从而取消减去1)并退回当天(第3个参数为`日期`构造函数)乘以1,使其成为下月的第0天,直到当月的最后一天.所以它有效.但它很聪明.聪明的代码是不可维护的代码.我会将其重构为更具可读性的内容,或者至少添加注释来解释其聪明之处. (4认同)
  • 这几乎是正确的,除了就Javascript的"Date"对象而言,月份从0-11开始索引,OP想要输入从1-12索引的月份.如果你想要我的upvote,你必须从传入的月份变量中减去1. (3认同)
  • @Asaph:"聪明"是主观的.算法很健全.关于唯一的负面IMO是它确实击中系统时钟来做一些可以用简单的条件和数学确定的东西. (3认同)

Jam*_*mes 27

九月,
四月,六月和十一月三十天;
其余所有人都有三十一人,
仅有二月
二十日,其中有二十八天清楚,
每一年闰年二十九天.

<3维基百科

  • 我更喜欢这个版本"九月四月六月三十天,难怪,其余的都有面包和果酱,除了奶奶,她骑自行车." (14认同)

Bru*_*uno 13

喜欢詹姆斯的回答.对那些感兴趣的人稍微重新格式化.

function getDaysInMonth(m, y)
{
    // months in JavaScript start at 0 so decrement by 1 e.g. 11 = Dec
    --m;

    // if month is Sept, Apr, Jun, Nov return 30 days
    if( /8|3|5|10/.test( m ) ) return 30;

    // if month is not Feb return 31 days
    if( m != 1 ) return 31;

    // To get this far month must be Feb ( 1 )
    // if the year is a leap year then Feb has 29 days
    if( ( y % 4 == 0 && y % 100 != 0 ) || y % 400 == 0 ) return 29;

    // Not a leap year. Feb has 28 days.
    return 28;
}
Run Code Online (Sandbox Code Playgroud)

在这里小提琴


Git*_*LAB 7

大家都知道,计数Chuck的一拳击败单纯的诗歌中的任何一天一周一个月..

查克诺里斯的拳头. 计算knucle的.

如果你不能编译和运行(如诗歌),那么请继续阅读.


没有正则表达式和减2 模数余数运算,也没有闰年问题或Date-object.
虽然javascript Date object在1970年1月1日的两边都覆盖了大约285616年(100,000,000天),但我厌倦了不同浏览器中的各种意外日期不一致(最明显的是0到99年).我也很好奇如何计算它.

所以我写了一个简单的,最重要的,算法(轻松击败詹姆斯的答案)来计算正确的(Proleptic Gregorian/Astronomical/ISO 8601:2004(第4.3.2.1节),所以年份0存在并且是闰年和负数年支持)给定月份和年份的天数.
它使用短路位掩码 - 模数leapYear算法(略微修改为js)和常见的mod- 8月算法(再次修改以获得最短路径).

请注意,在AD/BC表示法中,第0年AD/BC不存在:相反年份1 BC是闰年!
如果您需要考虑BC符号,那么只需减去一年(否则为正)年值!(或者将年份减去1进一步的年度计算.)

function daysInMonth(m, y){
  return m===2?y&3||!(y%25)&&y&15?28:29:30+(m+(m>>3)&1);
}
Run Code Online (Sandbox Code Playgroud)
<!-- example for the snippet -->
<input type="text" placeholder="enter year" onblur="
  for( var r='', i=0, y=+this.value
     ; 12>i++
     ; r+= 'Month: ' + i + ' has ' + daysInMonth(i, y) + ' days<br>'
     );
  this.nextSibling.innerHTML=r;
" /><div></div>
Run Code Online (Sandbox Code Playgroud)

注意,月份必须是1个(根据要求提出的问题)!

注意,这是一个不同的算法,然后我在我的Javascript中使用的幻数查找计算一年中的日期(1 - 366)答案,因为这里闰年的额外分支仅在2月需要.


编辑(历史):
我解除了修改后的mod8个月算法

return(m===2?y&3||!(y%25)&&y&15?28:29:30)+(m+(m>>3)&1);   //algo 1
Run Code Online (Sandbox Code Playgroud)

到三元并删除了现在不需要的外括号(好的调用,TrueBlueAussie):

return m===2?y&3||!(y%25)&&y&15?28:29:30+(m+(m>>3)&1);    //algo 2
Run Code Online (Sandbox Code Playgroud)

经过严格的测试后,结果证明这是最快的算法(感谢TrueBlueAussie的测试,我为缓存jsperf设置进行了测试).我们猜测这比我的(更短且看似更快)算法3(下面的神奇数字按位查找)更快的原因是,现代浏览器可能可以预先优化常量位移m>>3.

我想......好吧......"为什么我不再这样做?:"

return m===2?y&3||!(y%25)&&y&15?28:29:30+(5546>>m&1);     // algo 3
Run Code Online (Sandbox Code Playgroud)

它使用一个"幻数"来进行偏移的简单逐位查找:

DNOSAJJMAMFJ* = Months (right to left)
CBA9876543210 = Month === bit position in hex (we never use pos 0: January is 1)
1010110101010 = offset from 30 = binary === 5546 decimal

13位小于31位,因此我们可以安全地在bitshift上保存另一个字符而不是>>>(因为我们不需要强制无符号32位).

这消除了一个内存调用(var m),一个加法和一个优先级!(它的一个字符更短)

有人会认为:显然这3个额外的优化击败了我的第一个/第二个算法(正如TrueBlueAussie评论的那样,已经是最快的了)......
但正如我已经提到的,事实证明这个(算法3)在现代并不快浏览器(我知道,相当意外),我们认为这是因为引擎无法再优化比特移位.
我会把它留在这里,也许有一天它更快,谁知道..

事实证明我的算法2是最快(除了TrueBlueAussie的完整2D阵列,当然,虽然需要更多的内存并且仍然需要快速的算法来构建它的客户端),我遵循TrueBlueAussie的建议来恢复我使用算法的答案2.

我仍然有一个爆炸合作,并感谢重新审视我的答案!


Gon*_*ing 5

在计算机术语中,new Date()regular expression解决方案是慢!如果你想要一个超高速(和超神秘)的一行,试试这个(假设mJan=1格式按问题):

唯一真正的速度竞争来自@GitaarLab,所以我创建了一个头对头的JSPerf供我们测试:http://jsperf.com/days-in-month-head-to-head/5

我一直在尝试不同的代码更改以获得最佳性能.

当前版本

在查看这个相关问题闰年检查使用按位运算符(惊人的速度)并发现25和15幻数代表什么,我已经提出了这种优化的答案混合:

function getDaysInMonth(m, y) {
    return m===2 ? y & 3 || !(y % 25) && y & 15 ? 28 : 29 : 30 + (m +(m >> 3) & 1);
}
Run Code Online (Sandbox Code Playgroud)

JSFiddle: http ://jsfiddle.net/TrueBlueAussie/H89X3/22/

JSPerf结果: http ://jsperf.com/days-in-month-head-to-head/5

出于某种原因,(m+(m>>3)&1)是不是更有效(5546>>m&1)几乎所有的浏览器.


之前的版本:

这个!通过反转值(略微增加)删除了一个测试:

function getDaysInMonth(m, y) {
    return m === 2 ? (y % 4 || !(y % 100) && (y % 400)) ? 28 : 29 : 30 + (m + (m >> 3) & 1);
}
Run Code Online (Sandbox Code Playgroud)

这个删除了任何不必要的括号:

function getDaysInMonth2(m, y) {
    return m === 2 ? !(y % 4 || !(y % 100) && (y % 400)) ? 29 : 28 : 30 + (m + (m >> 3) & 1);
}
Run Code Online (Sandbox Code Playgroud)

这个+比XOR(^)快一点

function getDaysInMonth(m, y) {
    return (m === 2) ? (!((y % 4) || (!(y % 100) && (y % 400))) ? 29 : 28) : 30 + ((m + (m >> 3)) & 1);
}
Run Code Online (Sandbox Code Playgroud)

这是我最初的尝试:

function getDaysInMonth(m, y) {
    return m == 2 ? (!((y % 4) || (!(y % 100) && (y % 400))) ? 29 : 28) : (30 + ((m >> 3 ^ m) & 1));
}
Run Code Online (Sandbox Code Playgroud)

它基于我的闰年答案在这里工作:javascript找到闰年这个答案在这里闰年检查使用按位运算符(惊人的速度)以及以下二进制逻辑.


二进制月的快速教训:

如果您以二进制形式解释所需月份(Jan = 1)的索引,您会注意到31天的月份有3位清除和位0设置,或位3设置和位0清除.

Jan = 1  = 0001 : 31 days
Feb = 2  = 0010
Mar = 3  = 0011 : 31 days
Apr = 4  = 0100
May = 5  = 0101 : 31 days
Jun = 6  = 0110
Jul = 7  = 0111 : 31 days
Aug = 8  = 1000 : 31 days
Sep = 9  = 1001
Oct = 10 = 1010 : 31 days
Nov = 11 = 1011
Dec = 12 = 1100 : 31 days
Run Code Online (Sandbox Code Playgroud)

这意味着您可以将值移位3个位置>> 3,将位与原始位置进行异或,^ m并查看结果是否在位10 0位置使用& 1.注意:事实证明它+比XOR(^)略快,并且(m >> 3) + m在第0位给出相同的结果.

JSPerf结果:http://jsperf.com/days-in-month-perf-test/6(比接受的答案快23倍).


更新:我对前两个答案+最新(@ James,@ Caleb和@GitaarLAB)进行了对比,以确保它们给出了一致的结果,并且所有4个从1年到1年的所有年份都返回相同的值4000:http://jsfiddle.net/TrueBlueAussie/8Lmpnpz4/6/.除了@Caleb之外,除了@Caleb之外,0年级是相同的.

另一个更新:

如果绝对速度是唯一的目标,并且您不介意浪费内存,那么将结果存储在给定的年度内,在二维表中可能是最快的方式:

function DIM(m, y) { //TrueBlueAussie
    return m===2?(y%4||!(y%100)&&(y%400))?28:29:30+(m+(m>>3)&1);
}
array = new Array(4000);
for (var y = 1; y < 4000; y++){
    array[y] = [];
    for (var m = 1; m < 13; m++)
    {
        array[y][m] = DIM(m, y);
    }
}

// This just does a lookup into the primed table - wasteful, but fast
function getDaysInMonth2(m, y){
    return array[y][m];
}
Run Code Online (Sandbox Code Playgroud)

JSPerf: http ://jsperf.com/days-in-month-head-to-head/5