性能对这一个人来说至关重要......这件事需要快速闪电!
您如何验证给定月份的天数?
我的第一个想法是创建一个包含给定月份日期的数组,其中索引代表月份:
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)
答案 0 :(得分: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);
}
答案 1 :(得分: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对象,我不必担心它。
干净的技巧,嗯?很脏,但那是给你的脚本...
答案 2 :(得分: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日作为日期返回。
答案 3 :(得分:5)
如果月份不是二月,请从数组中获取数字。否则,检查年份是否跳跃返回29,或者返回28.是否存在问题?
答案 4 :(得分: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;
}
}
}
答案 5 :(得分:4)
您是否尝试过moment.js?
validation非常易于使用:
var m = moment("2015-11-32");
m.isValid(); // false
我不知道这些表演,但是该项目在GitHub上盯着 11,000+次(质量保证)。
答案 6 :(得分: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);
}
答案 7 :(得分: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
答案 8 :(得分:3)
所有这些逻辑已经内置于javascript引擎中...为什么要重新编码?除非你这样做是为了练习,否则你可以使用javascript Date对象:
像这样:
function daysInMonth(aDate) {
return new Date(aDate.getYear(), aDate.getMonth()+1, 0).getDate();
}
答案 9 :(得分:2)
假设JS Date对象标准,其中月份从0开始编号,并且您有daysInMonth数组:
var days = daysInMonth[month] + ((month === 1) && (year % 4 === 0) && ((year % 100 !== 0) || (year % 400 === 0)));
将为您提供当月的天数,如果该月份是2月份,那么28天将增加到29天,而这一年是闰年。
答案 10 :(得分:2)
在计算机术语中,new Date()
和regular expression
解决方案慢!如果你想要一个超快速(超级神秘)的单行,请试试这个(假设m
采用Jan=1
格式):
唯一真正的速度竞争来自@GitaarLab,所以我创建了一个头对头的JSPerf供我们测试:http://jsperf.com/days-in-month-head-to-head/5
我一直在尝试不同的代码更改以获得最佳性能。
当前版本
在查看相关问题Leap year check using bitwise operators (amazing speed)并发现25&amp; 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中得到相同的结果。
答案 11 :(得分:1)
除闰年的详细信息外,每月的日子很容易被人们所知:
我基于解决此问题的算法留下了一个实现:
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)
/**
* 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));
});
&#13;
<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>
&#13;
答案 12 :(得分:0)
您可以使用DateTime来解决此问题:
new DateTime('20090901')->format('t'); // gives the days of the month