Який найкращий спосіб визначити кількість днів у місяці за допомогою JavaScript?


107

Я використовував цю функцію, але хотів би знати, який найефективніший і найточніший спосіб її отримати.

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

Відповіді:


200

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.


42
цей синтаксис мене деякий час бентежить. Для дотримання схеми JS я рекомендую здійснити такий трюк:return new Date(year, month + 1, 0).getDate();
fguillen

2
На жаль, це не вдається встановити дати до 1000 року н.е., коли ви можете встановити рік правильно лише за допомогою SetFullYear (). Щоб зробити його кулезахисним, використовуйте нову дату (2000+ (рік 2000, місяць, місяць, 0) .getDate ()
Ноель Уолтерс

4
Зауважте до мого майбутнього "Я": рівняння fguillen з "+ 1" дає 28 днів, коли рік - 2014, а місяць - 1 (що в JavaScript-об'єкті дата означає лютий). Можливо, хочеться піти з цим хоча б здивування. Але яка чудова ідея від FlySwat!
Гаррі Пеконен

@ NoelWalters - ви впевнені, що деякі веб-переглядачі неправильно перетворюють двозначні роки в дати 20-го століття (тому дати до 100 року н.е., а не 1000 р. Н. Е.), Однак ваш виправлення не виправляє цього в цих браузерах. Єдиний спосіб надійно встановити двозначний рік - це використовувати setFullYear : var d=new Date();d.setFullYear(year, month, date);.
RobG

1
Що робити, якщо monthце 12 ? Чи не повинен Dateконструктор приймати значення від 0 до 11 ?
anddero

8

Якщо ви часто викликаєте цю функцію, може бути корисним кешування значення для кращої продуктивності.

Ось кешована версія відповіді 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();
    }
})();

6
Чи внутрішня програма C / C ++ настільки повільна, що для цього потрібне кешування?
Піт Елвін

1
@PeteAlvin Залежить від реалізації Date(тому не існує універсальної відповіді на це питання) і того, як часто ваш код буде викликати значення dayInMonthз однаковими значеннями. Тож єдина розумна відповідь: профіліруйте свій код і порівняйте його!
долмен

1
Мені це подобається! Але замість того, щоб використовувати новий об’єкт cache, я використовую localStorage.
andrew

5

Деякі відповіді (також на інші запитання) мали проблеми високосного року або використовували об’єкт Date. Хоча в JavaScript Date objectохоплює близько 285 616 років (100,000,000 днів) по обидві сторони від 1 січня 1970 року народження, я був ситий по горло усіма видами несподіваних дат неузгодженості різних браузерів (перш за все 0 року до 99). Мені також було цікаво, як це обчислити.

Тому я написав простий і, перш за все, невеликий алгоритм для обчислення правильного ( Proleptic Gregorian / Astronomical / ISO 8601: 2004 (п. 4.3.2.1), тому рік0 існує, і це високосний рік, і негативні роки підтримуються ) кількість днів для заданий місяць і рік.
Він використовує короткозамкнений алгоритм bitmask-modulo 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);
}
<!-- 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) відповідь, тому що тут додаткова гілка для високосного року потрібна лише на лютий.


4

Щоб зняти плутанину, я б, мабуть, зробив рядок місяця, як це наразі 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

4

З моментом 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


2

Синтаксис ES6

const d = (y, m) => new Date(y, m, 0).getDate();

повертає

console.log( d(2020, 2) );
// 29

console.log( d(2020, 6) );
// 30

1
Додаючи нову відповідь на старе питання з 14 існуючими відповідями, дуже важливо відзначити, який новий аспект питання стосується вашої відповіді. Це просто синтаксис ES6?
Джейсон Аллер

зрозумів. буде додавати контекст у відповідь відтепер.
RASG

1
function numberOfDays(iMonth, iYear) {
         var myDate = new Date(iYear, iMonth + 1, 1);  //find the fist day of next month
         var newDate = new Date(myDate - 1);  //find the last day
            return newDate.getDate();         //return # of days in this month
        }

1

Враховуючи високосні роки:

function (year, month) {
    var isLeapYear = ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0);

    return [31, (isLeapYear ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
}

Приємно. Легко дивитися. Підтвердьте [ertie] s для використання вбудованої карти / негайно введеного значення.
Коді

1

Пряме обчислення в одній лайнері (без об'єкта дати):

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);
}

1

Якщо ви хочете кількість днів у поточному місяці об’єкта 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

В одному рядку:

// 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

Може бути трохи більше вбити в порівнянні з обраною відповіддю :) Але ось це:

function getDayCountOfMonth(year, month) {
  if (month === 3 || month === 5 || month === 8 || month === 10) {
    return 30;
  }

  if (month === 1) {
    if (year % 4 === 0 && year % 100 !== 0 || year % 400 === 0) {
      return 29;
    } else {
      return 28;
    }
  }

  return 31;
};

console.log(getDayCountOfMonth(2020, 1));

Тут я знайшов вищезгаданий код: https://github.com/ElemeFE/element/blob/dev/src/utils/date-util.js

function isLeapYear(year) { 
  return ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0); 
};

const getDaysInMonth = function (year, month) {
  return [31, (isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
};

console.log(getDaysInMonth(2020, 1));

Тут я знайшов вищезгаданий код: https://github.com/datejs/Datejs/blob/master/src/core.js


1

Якщо ви збираєтеся передати змінну дати, це може бути корисним

const getDaysInMonth = date =>
  new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();

daysInThisMonth = getDaysInMonth(new Date());

console.log(daysInThisMonth);


-1

Мабуть, не найвишуканіше рішення, але легко зрозуміти та підтримувати; і, це випробування на бій.

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;
},
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.