验证给定月份的天数

问题描述 投票:22回答:13

性能对这一个人来说至关重要......这件事需要快速闪电! 您如何验证给定月份的天数?

我的第一个想法是创建一个包含给定月份日期的数组,索引代表月份:

var daysInMonth = [
    31, // January
    28, // February
    31, // March
    etc.
];

然后做一些事情:

function validateDaysInMonth(days, month)
{
    if (days < 1 || days > daysInMonth[month]) throw new Error("Frack!");
}

但是......闰年怎么样?如何实现闰年检查并保持功能运行相对较快? 更新:我希望你们向我们展示一些代码,这些代码可以完成月闰年验证的日期。

这是描述今天使用的逻辑的流程图:

(来源:about.com

javascript
13个回答
51
投票
function daysInMonth(m, y) { // m is 0 indexed: 0-11
    switch (m) {
        case 1 :
            return (y % 4 == 0 && y % 100) || y % 400 == 0 ? 29 : 28;
        case 8 : case 3 : case 5 : case 10 :
            return 30;
        default :
            return 31
    }
}

function isValid(d, m, y) {
    return m >= 0 && m < 12 && d > 0 && d <= daysInMonth(m, y);
}

2
投票

假设JS Date对象标准,其中月份从0开始编号,并且您有daysInMonth数组:

var days = daysInMonth[month] + ((month === 1) && (year % 4 === 0) && ((year % 100 !== 0) || (year % 400 === 0)));

将给你这个月的天数,如果月份是2月份,那么28天会增加到29天,而这一年是闰年。


2
投票

在计算机方面,new Date()regular expression解决方案很慢!如果你想要一个超快速(和超级神秘的)单线程,试试这个(假设mJan=1格式):

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

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

当前版本

在查看了相关问题Leap year check using bitwise operators (amazing speed)并发现25和15幻数代表什么之后,我想出了这种优化的答案混合:

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

的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)更有效。


它基于我的闰年答案在这里工作:javascript to find leap year这个答案在这里Leap year check using bitwise operators (amazing speed)以及以下二进制逻辑。

二进制月的快速教训:

如果您以二进制形式解释所需月份(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

这意味着您可以使用>> 3将值移位3位,使用原始^ m将位置XOR,并使用1查看位置0中的结果是0还是& 1。注意:事实证明+比XOR(^)略快,而(m >> 3) + m在第0位给出相同的结果。

JSPerf结果:http://jsperf.com/days-in-month-perf-test/6


1
投票

除闰年的详细信息外,每月的日子很容易被人们所知。

我留下了一个基于解决这个问题的算法的实现:

Algorithm

if (year is not divisible by 4) then (it is a common year)
else if (year is not divisible by 100) then (it is a leap year)
else if (year is not divisible by 400) then (it is a common year)
else (it is a leap year)

Implementation in Javascript

/**
 * Doc: https://en.wikipedia.org/wiki/Leap_year#Algorithm
 * param : month is indexed: 1-12
 * param: year
 **/
		function daysInMonth(month, year) {
			switch (month) {
				case 2 : //Febrary
					if (year % 4) {
						return 28; //common year
					}
					if (year % 100) {
						return 29; //  leap year
					}
					
					if (year % 400) {
						return 28; //common year
					}
					return 29; //  leap year
				case 9 : case 4 : case 6 : case 11 :
					return 30;
				default :
					return 31
			}
		}
    
    /** Testing daysInMonth Function **/
    $('#month').change(function() {
        var mVal = parseInt($(this).val());
        var yVal = parseInt($('#year').val());
        $('#result').text(daysInMonth(mVal, yVal));
    });
    
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<label>Year</label>
<input type='number' id='year' min='1000' max='2500'>

<label>month</label>
<input type='number' id='month' min='1' max='12'>
<h1>
   days: <span id='result' style='color:#E650A0'></span>
</h1>

0
投票

您可以使用DateTime来解决此问题:

new DateTime('20090901')->format('t'); // gives the days of the month

13
投票

我一直在使用Date对象(假设它已编译,因此与脚本相比非常快)。

诀窍在于,如果为日期部分输入的数字太高,则Date对象将换行到下个月。所以:

var year = 2009;
var month = 1;
var date = 29;

var presumedDate = new Date(year, month, date);

if (presumedDate.getDate() != date)
    WScript.Echo("Invalid date");
else
    WScript.Echo("Valid date");

这将回显“无效日期”,因为presumedDate实际上是3月1日。

这使得闰年等所有麻烦都留给了Date对象,我不必担心它。

干净的把戏,嗯?很脏,但那是给你的脚本......


6
投票

这不会像接受的答案那样好。我把它扔在这里因为我认为这是最简单的代码。大多数人不需要优化此功能。

function validateDaysInMonth(year, month, day)
{
    if (day < 1 || day > 31 || (new Date(year, month, day)).getMonth() != month)
        throw new Error("Frack!");
}

它利用了javascript Date构造函数将在超出范围的日期执行日期算术的事实,例如,如果您这样做:

var year = 2001; //not a leap year!
var month = 1 //February
var day = 29; //not a valid date for this year
new Date(year, month, day);

该对象将返回2001年3月1日作为日期。


5
投票

如果月份不是2月,请从数组中获取数字。否则,检查年份是否跳跃返回29,或返回28.是否有问题?


4
投票
function caldays(m,y)
{
    if (m == 01 || m == 03 || m == 05 || m == 07 || m == 08 || m == 10 || m == 12)
    {
        return 31;              
    }
    else if (m == 04 || m == 06 || m == 09 || m == 11)
    {
        return 30;        
    }
    else
    {    
        if ((y % 4 == 0) || (y % 400 == 0 && y % 100 != 0))
        {    
            return 29;          
        }
        else 
        {
            return 28;              
        }
    }    
}

来源:http://www.dotnetspider.com/resources/20979-Javascript-code-get-number-days-perticuler-month-year.aspx


4
投票

Moment.js

你试过moment.js吗?

validation非常容易使用:

var m = moment("2015-11-32");
m.isValid(); // false

我不知道这些表演,但是该项目在GitHub上盯着11,000多次(质量保证)。

资料来源:http://momentjs.com/docs/#/parsing/is-valid/


3
投票

我同意Moayad和TED。坚持查找表,除非月份是2月。如果你需要一个检查闰年的算法,wikipedia has two

if year modulo 400 is 0 then leap
 else if year modulo 100 is 0 then no_leap
 else if year modulo 4 is 0 then leap
 else no_leap

A more direct algorithm (terms may be grouped either way):

function isLeapYear (year):
 if ((year modulo 4 is 0) and (year modulo 100 is not 0)) or (year modulo 400 is 0)
  then true
 else false

3
投票

我主要是同意Moayad。我会使用表查找,并在2月和年份进行if检查。

伪代码:

Last_Day = Last_Day_Of_Month[Month];
Last_Day += (Month == February && Leap_Year(Year)) ? 1 : 0;

请注意,Leap_Year()不能简单地实现为(Year % 4 == 0),因为闰年​​的规则比这更复杂。这是一个算法cribbed from Wikipedia

bool Leap_Year (int year) {
   return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}

3
投票

所有这些逻辑已经内置到javascript引擎中......为什么要重新编写它?除非你这样做是为了练习,否则你可以使用javascript Date对象:

像这样:

function daysInMonth(aDate) {
      return new Date(aDate.getYear(), aDate.getMonth()+1, 0).getDate();      
   }
© www.soinside.com 2019 - 2024. All rights reserved.