Jaki jest najlepszy sposób określenia liczby dni w miesiącu za pomocą JavaScript?


107

Używałem tej funkcji, ale chciałbym wiedzieć, jaki jest najbardziej skuteczny i dokładny sposób jej uzyskania.

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

Odpowiedzi:


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.

Dzień 0 to ostatni dzień poprzedniego miesiąca. Ponieważ konstruktor miesiąca jest oparty na 0, działa to ładnie. Trochę hack, ale to w zasadzie to, co robisz, odejmując 32.


42
ta składnia od jakiegoś czasu mnie dezorientuje. Aby podążać za wzorcem JS, polecam zaimplementować taką sztuczkę:return new Date(year, month + 1, 0).getDate();
fguillen

2
Niestety nie udaje się to w przypadku dat sprzed 1000 rne, w których można poprawnie ustawić rok tylko za pomocą SetFullYear (). Aby uczynić go kuloodpornym, użyj nowej daty (2000+ (rok% 2000), miesiąc, 0) .getDate ()
Noel Walters

4
Uwaga dla mojej przyszłej jaźni: równanie Fguillena z „+ 1” daje 28 dni, gdy rok jest 2014, a miesiąc 1 (co w JavaScript Date-object oznacza luty). Prawdopodobnie chciałbym się z tym pogodzić dla najmniejszego zdziwienia. Ale co za wspaniały pomysł od FlySwat!
Harry Pehkonen,

@ NoelWalters - masz rację, że niektóre przeglądarki nieprawidłowo konwertują lata dwucyfrowe na daty w XX wieku (a więc daty sprzed 100 rne, a nie 1000 rne), jednak twoja poprawka nie naprawia tego w tych przeglądarkach. Jedynym sposobem, aby wiarygodnie ustalonych dwa lata cyfrowych jest użycie setFullYear : var d=new Date();d.setFullYear(year, month, date);.
RobG

1
A jeśli monthma 12 lat ? Czy Datekonstruktor nie powinien przyjmować wartości od 0 do 11 ?
anddero

8

Jeśli często wywołujesz tę funkcję, może być przydatne buforowanie wartości w celu uzyskania lepszej wydajności.

Oto wersja buforująca odpowiedzi 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
Czy wewnętrzna procedura C / C ++ jest tak powolna, że ​​wymaga buforowania?
Pete Alvin

1
@PeteAlvin Zależy to od implementacji Date(więc nie ma uniwersalnej odpowiedzi na to pytanie) i tego, jak często Twój kod będzie wywoływał metodę dayInMonthz tymi samymi wartościami. Więc jedyną rozsądną odpowiedzią jest: profiluj swój kod i testuj go!
dolmen

1
Lubię to! Ale zamiast używać nowego obiektu, cacheużywam localStorage.
andrew

5

Niektóre odpowiedzi (także na inne pytania) dotyczyły problemów z rokiem przestępnym lub wykorzystywały obiekt Date. Chociaż javascript Date objectobejmuje około 285616 lat (100 000 000 dni) po obu stronach 1 stycznia 1970 r., Miałem dość wszelkiego rodzaju nieoczekiwanych niespójności dat w różnych przeglądarkach (zwłaszcza w latach od 0 do 99). Byłem też ciekawy, jak to obliczyć.

Napisałem więc prosty, a przede wszystkim mały algorytm do obliczania poprawnej ( Proleptic Gregorian / Astronomical / ISO 8601: 2004 (punkt 4.3.2.1), więc rok0 istnieje i jest rokiem przestępnym, a lata ujemne są obsługiwane ) liczby dni dla danego miesiąca i roku.
Wykorzystuje algorytm zwarcia bitmask-modulo leapYear (nieznacznie zmodyfikowany dla js) i wspólny algorytm mod-8 miesięcy.

Zauważ, że w AD/BCnotacji rok 0 AD / BC nie istnieje: zamiast tego rok 1 BCjest rokiem przestępnym!
JEŚLI musisz uwzględnić notację BC, po prostu odejmij najpierw jeden rok (w przeciwnym razie dodatniej) wartości roku !! (Lub odejmij rok od 1do dalszych obliczeń).

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>

Uwaga, miesiące muszą być liczone od 1!

Zauważ, że jest to inny algorytm niż magiczne wyszukiwanie liczb, których użyłem w moim JavaScript, aby obliczyć dzień roku (1 - 366) odpowiedź, ponieważ tutaj dodatkowa gałąź dla roku przestępnego jest potrzebna tylko dla lutego.


4

Aby wyeliminować zamieszanie, prawdopodobnie utworzyłbym ciąg miesiąca na podstawie, ponieważ obecnie jest oparty na 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

Z moment.js możesz użyć metody 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

Składnia ES6

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

zwroty

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

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

1
Dodając nową odpowiedź do starszego pytania z 14 istniejącymi odpowiedziami, naprawdę ważne jest, aby zwrócić uwagę, jakiego nowego aspektu pytania dotyczy twoja odpowiedź. Czy to tylko składnia ES6?
Jason Aller

Rozumiem. doda kontekst do odpowiedzi od teraz.
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

Biorąc pod uwagę lata przestępne:

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

Miły. Łatwe do obejrzenia. Propozycje [ertie] do użycia mapy wbudowanej / wartości z kluczem natychmiastowym.
Cody

1

Bezpośrednie obliczenia jednowierszowe (bez obiektu 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

Odchylenie z miesiącami od 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

Jeśli chcesz określić liczbę dni w bieżącym miesiącu obiektu Date, rozważ następującą metodę:

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

Następnie możesz uruchomić to w ten sposób:

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

W jednej linii:

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

Może być nieco przesadzone w porównaniu z wybraną odpowiedzią :) Ale oto jest:

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

Powyższy kod znalazłem tutaj: 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));

Powyższy kod znalazłem tutaj: https://github.com/datejs/Datejs/blob/master/src/core.js


1

Jeśli zamierzasz przekazać zmienną daty, może to być pomocne

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

daysInThisMonth = getDaysInMonth(new Date());

console.log(daysInThisMonth);


-1

Być może nie jest to najbardziej eleganckie rozwiązanie, ale łatwe do zrozumienia i utrzymania; i jest przetestowany w walce.

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;
},
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.