用JavaScript计算月中的最后一天

Ken*_*Ken 254 javascript date

如果您提供0dayValueDate.setFullYear你上一个月的最后一天:

d = new Date(); d.setFullYear(2008, 11, 0); //  Sun Nov 30 2008
Run Code Online (Sandbox Code Playgroud)

mozilla中提到了这种行为.这是一个可靠的跨浏览器功能还是我应该考虑其他方法?

Gra*_*ner 376

var month = 0; // January
var d = new Date(2008, month + 1, 0);
alert(d); // last day in January

IE 6: Thu Jan 31 00:00:00 CST 2008
IE 7: Thu Jan 31 00:00:00 CST 2008
IE 8: Beta 2: Thu Jan 31 00:00:00 CST 2008
Opera 8.54: Thu, 31 Jan 2008 00:00:00 GMT-0600
Opera 9.27: Thu, 31 Jan 2008 00:00:00 GMT-0600
Opera 9.60: Thu Jan 31 2008 00:00:00 GMT-0600
Firefox 2.0.0.17: Thu Jan 31 2008 00:00:00 GMT-0600 (Canada Central Standard Time)
Firefox 3.0.3: Thu Jan 31 2008 00:00:00 GMT-0600 (Canada Central Standard Time)
Google Chrome 0.2.149.30: Thu Jan 31 2008 00:00:00 GMT-0600 (Canada Central Standard Time)
Safari for Windows 3.1.2: Thu Jan 31 2008 00:00:00 GMT-0600 (Canada Central Standard Time)
Run Code Online (Sandbox Code Playgroud)

产出差异是由于实施的差异toString(),而不是因为日期不同.

当然,仅仅因为上面提到的浏览器使用0作为上个月的最后一天并不意味着他们将继续这样做,或者未列出的浏览器会这样做,但它使人们相信它应该工作的可信度每个浏览器都一样.

  • "仅仅因为浏览器......使用0作为上个月的最后一天并不意味着他们将继续这样做".是的,ECMA-262要求他们这样做. (28认同)
  • 这看起来效果很好.出于好奇,你在所有这些引擎上使用什么来运行javascript?有所有设置或某种工具? (17认同)
  • 你可以使用d.getDate()来获取实际的一天. (5认同)
  • 请注意,使用"new Date"***比其他计算方法慢得多*它甚至不会出现在性能图表上*:http://jsperf.com/days-in-month-perf-test/ 6 (3认同)
  • 它在Chrome 48.0.2564.116上对我不起作用.也许,这种方式已经不再是"标准"了. (3认同)
  • @AdamMiller'第13个月'似乎解决了明年1月就好了. (2认同)

kar*_*ins 75

我会在下个月的第一天使用中间日期,并返回前一天的日期:

int_d = new Date(2008, 11+1,1);
d = new Date(int_d - 1);
Run Code Online (Sandbox Code Playgroud)

  • 这是 IMO 的最佳解决方案。我尝试了接受的答案,但在获取当月的最后一个时它有一些错误。它返回今天的日期。不知道为什么会发生这种情况。 (2认同)
  • 我无法重现该错误。这给了我在所有浏览器中正确的日期:`today = new Date(); new Date(today.getFullYear(), today.getMonth()+1, 0).toString();` (2认同)

ora*_*rad 64

我觉得这对我来说是最好的解决方案.让Date对象为您计算它.

var today = new Date();
var lastDayOfMonth = new Date(today.getFullYear(), today.getMonth()+1, 0);
Run Code Online (Sandbox Code Playgroud)

将day参数设置为0表示比上个月的最后一天月份的第一天少一天.

  • 没关系,我注意到所选答案的建议相同。这是最快和最可靠的方法,无论日历类型如何都有效。例如,如果 Date 实现了格里高利历以外的其他东西,它仍然可以工作。请参阅 http://intldate.codeplex.com 以获取 Date 对象的非公历实现示例。 (2认同)
  • @orad:当心声称某些东西*“是最快的”*,因为这种方法实际上比某些替代方法慢得多。使用 `new Date` 是 * 慢得多 * 它甚至没有出现在性能图表上*:http://jsperf.com/days-in-month-perf-test/6 (2认同)
  • Native JS Date 仅使用公历。但是您可以使用其他一些实现来模拟它以获得其他日历类型。例如,参见 [IntlDate](http://intldate.codeplex.com/)。如果您有一个使用 Date 对象创建月视图的日期选择器,它并不关心它使用的是哪个 Date 实现(本机或模拟),只要它们具有相同的接口即可。因此,使用共享界面允许在不同的日历类型之间切换,而无需知道每个日历上一个月有多少天。 (2认同)

Gon*_*ing 23

在计算机术语中,new Date()regular expression解决方案是慢!如果你想要一个超快(超级神秘)的单行,请试试这个(假设mJan=1格式).我一直在尝试不同的代码更改以获得最佳性能.

我目前最快的版本:

在查看这个相关问题闰年检查使用按位运算符(惊人的速度)并发现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)

鉴于位移,这显然假设你的m&y参数都是整数,因为将数字作为字符串传递将导致奇怪的结果.

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)几乎所有的浏览器.

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


它基于我的闰年答案在这里工作: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

  • @GitaarLAB:正如您所知,您已经提到过,这与您的从未完全相同。彼此算法的增量更新与“原始算法”不同。我也为这个答案付出了很多努力:P (2认同)
  • 请注意`y` 和`m` 变量必须是整数而不是字符串!它会导致错误的计算,例如二月它返回 30。我不得不使用 `parseInt()` 函数来使它工作。 (2认同)

leb*_*eze 17

我的同事偶然发现了以下问题,这可能是一个更容易的解决方案

function daysInMonth(iMonth, iYear)
{
    return 32 - new Date(iYear, iMonth, 32).getDate();
}
Run Code Online (Sandbox Code Playgroud)

从http://snippets.dzone.com/posts/show/2099偷来的

  • 奈杰尔将其修改为更简洁的解决方案.看他的帖子. (2认同)

Nig*_*gel 14

lebreeze提供的解决方案略有修改:

function daysInMonth(iMonth, iYear)
{
    return new Date(iYear, iMonth, 0).getDate();
}
Run Code Online (Sandbox Code Playgroud)

  • 这应该是“return new Date(iYear, 1 + iMonth, 0).getDate();”,相当于@lebreeze的解决方案。 (2认同)

Eri*_*ric 9

我最近不得不做类似的事情,这就是我想出的:

/**
* Returns a date set to the begining of the month
* 
* @param {Date} myDate 
* @returns {Date}
*/
function beginningOfMonth(myDate){    
  let date = new Date(myDate);
  date.setDate(1)
  date.setHours(0);
  date.setMinutes(0);
  date.setSeconds(0);   
  return date;     
}

/**
 * Returns a date set to the end of the month
 * 
 * @param {Date} myDate 
 * @returns {Date}
 */
function endOfMonth(myDate){
  let date = new Date(myDate);
  date.setMonth(date.getMonth() +1)
  date.setDate(0);
  date.setHours(23);
  date.setMinutes(59);
  date.setSeconds(59);
  return date;
}
Run Code Online (Sandbox Code Playgroud)

将它传入一个日期,它将返回一个设置为月初或月底的日期。

begninngOfMonth函数是不言自明的,但endOfMonth函数中的内容是我将月份增加到下个月,然后使用setDate(0)将日期回滚到上个月的最后一天,这是设置日期规格:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setDate https://www.w3schools.com/jsref/jsref_setdate.asp

然后我将小时/分钟/秒设置为一天结束,这样如果您使用某种需要日期范围的 API,您将能够捕获最后一天的全部内容。这部分可能超出了原始帖子的要求,但它可以帮助其他人寻找类似的解决方案。

编辑:setMilliseconds()如果您想更加精确,您还可以加倍努力并设置毫秒。


Aar*_*Lee 9

如何不这样做

请注意本月最后一个月的任何如下所示的答案:

var last = new Date(date)
last.setMonth(last.getMonth() + 1) // This is the wrong way to do it.
last.setDate(0)
Run Code Online (Sandbox Code Playgroud)

这适用于大多数日期,但如果date已经是该月的最后一天,且该月的天数多于下个月,则该方法会失败。

例子:

假设date07/31/21.

然后last.setMonth(last.getMonth() + 1)增加月份,但保持日期设置为31

你得到一个 Date 对象08/31/21

实际上 09/01/21是.

那么last.setDate(0)结果就是08/31/21我们真正想要的是07/31/21

  • 这是一个很好的收获,但最好保留为您所指的答案的评论,因为您没有提供实际问题的解决方案。 (7认同)

art*_*lar 7

试试这个。

lastDateofTheMonth = new Date(year, month, 0)
Run Code Online (Sandbox Code Playgroud)

例子:

new Date(2012, 8, 0)
Run Code Online (Sandbox Code Playgroud)

输出:

Date {Fri Aug 31 2012 00:00:00 GMT+0900 (Tokyo Standard Time)}
Run Code Online (Sandbox Code Playgroud)

  • 但请记住,月份是从零开始的,因此传递“8”是因为该月份实际上是九月,而不是八月。 (9认同)

小智 5

这对我有用。将提供给定年份和月份的最后一天:

var d = new Date(2012,02,0);
var n = d.getDate();
alert(n);
Run Code Online (Sandbox Code Playgroud)

  • 小心“2”前面的 0 它将被解释为八进制。 (2认同)