Как лучше всего определить количество дней в месяце с помощью JavaScript? - PullRequest
94 голосов
/ 25 ноября 2008

Я пользуюсь этой функцией, но мне бы хотелось узнать, какой самый эффективный и точный способ ее получить.

function daysInMonth(iMonth, iYear) {
   return 32 - new Date(iYear, iMonth, 32).getDate();
}

Ответы [ 12 ]

172 голосов
/ 25 ноября 2008

function daysInMonth (month, year) { // Use 1 for January, 2 for February, etc.
  return new Date(year, month, 0).getDate();
}

console.log(daysInMonth(2, 1999)); // February in a non-leap year.
console.log(daysInMonth(2, 2000)); // February in a leap year.

День 0 - последний день предыдущего месяца. Поскольку конструктор месяца основан на 0, это прекрасно работает. Немного хак, но это в основном то, что вы делаете, вычитая 32.

8 голосов
/ 29 марта 2011

Если вы часто вызываете эту функцию, может быть полезно кэшировать значение для повышения производительности.

Вот кеширующая версия Ответ FlySwat :

var daysInMonth = (function() {
    var cache = {};
    return function(month, year) {
        var entry = year + '-' + month;

        if (cache[entry]) return cache[entry];

        return cache[entry] = new Date(year, month, 0).getDate();
    }
})();
5 голосов
/ 07 января 2015

В некоторых ответах (также на другие вопросы) были проблемы високосного года или использовался объект Date. Хотя javascript Date object охватывает примерно 285616 лет (100 000 000 дней) по обе стороны от 1 января 1970 года, я был сыт по горло всевозможными неожиданными несоответствиями в разных браузерах (особенно в возрасте от 0 до 99). Мне также было любопытно, как рассчитать это.

Итак, я написал простой и прежде всего маленький алгоритм для вычисления правильного ( Proleptic григорианского / Астрономический / ISO 8601 : 2004 (пункт 4.3.2.1), поэтому год 0 существует и является високосным годом, а отрицательные годы поддерживаются ) числом дней для данного месяца и года.
Он использует алгоритм битовой маски короткого замыкания по модулю leapYear (слегка измененный для js) и общий алгоритм mod-8 month.

Обратите внимание, что в нотации AD/BC год 0 нашей эры / 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);
}
<!-- example for the snippet -->
<input type="text" value="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>

Обратите внимание, месяцы должны быть на основе 1!

Обратите внимание, что этот алгоритм отличается от алгоритма поиска магических чисел, который я использовал в своем Javascript для вычисления дня года (1 - 366) , потому что здесь дополнительная ветвь для високосного года нужен только на февраль.

3 голосов
/ 14 июля 2015

Чтобы устранить путаницу, я бы, вероятно, основал строку месяца, поскольку в настоящее время она равна 1.

function daysInMonth(month,year) {
    monthNum =  new Date(Date.parse(month +" 1,"+year)).getMonth()+1
    return new Date(year, monthNum, 0).getDate();
}

daysInMonth('feb', 2015)
//28

daysInMonth('feb', 2008)
//29
2 голосов
/ 22 марта 2016

С moment.js вы можете использовать метод daysInMonth ():

moment().daysInMonth(); // number of days in the current month
moment("2012-02", "YYYY-MM").daysInMonth() // 29
moment("2012-01", "YYYY-MM").daysInMonth() // 31
1 голос
/ 04 октября 2018

Вот идет

new Date(2019,2,0).getDate(); //28
new Date(2020,2,0).getDate(); //29
1 голос
/ 06 октября 2017

В одну строку:

// month is 1-12
function getDaysInMonth(year, month){
    return month == 2 ? 28 + (year % 4 == 0 ? (year % 100 == 0 ? (year % 400 == 0 ? 1 : 0) : 1):0) : 31 - (month - 1) % 7 % 2;
}
1 голос
/ 09 марта 2017

Если вы хотите количество дней в текущем месяце объекта Date, рассмотрите следующий метод:

Date.prototype.getNumberOfDaysInMonth = function(monthOffset) {
    if (monthOffset !== undefined) {
        return new Date(this.getFullYear(), this.getMonth()+monthOffset, 0).getDate();
    } else {
        return new Date(this.getFullYear(), this.getMonth(), 0).getDate();
    }
}

Тогда вы можете запустить его так:

var myDate = new Date();
myDate.getNumberOfDaysInMonth(); // Returns 28, 29, 30, 31, etc. as necessary
myDate.getNumberOfDaysInMonth(); // BONUS: This also tells you the number of days in past/future months!
1 голос
/ 13 сентября 2016

Однострочное прямое вычисление (без объекта Date):

function daysInMonth(m, y) {//m is 1-based, feb = 2
   return 31 - (--m ^ 1? m % 7 & 1:  y & 3? 3: y % 25? 2: y & 15? 3: 2);
}

console.log(daysInMonth(2, 1999)); // February in a non-leap year
console.log(daysInMonth(2, 2000)); // February in a leap year

Вариация с 0 по месяцам:

function daysInMonth(m, y) {//m is 0-based, feb = 1
   return 31 - (m ^ 1? m % 7 & 1:  y & 3? 3: y % 25? 2: y & 15? 3: 2);
}
0 голосов
/ 08 ноября 2017

Возможно, не самое элегантное решение, но простое для понимания и сопровождения; и это проверено в бою.

function daysInMonth(month, year) {
    var days;
    switch (month) {
        case 1: // Feb, our problem child
            var leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
            days = leapYear ? 29 : 28;
            break;
        case 3: case 5: case 8: case 10: 
            days = 30;
            break;
        default: 
            days = 31;
        }
    return days;
},
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...