Apa cara terbaik untuk menentukan jumlah hari dalam sebulan dengan JavaScript?

107

Saya telah menggunakan fungsi ini tetapi saya ingin tahu cara apa yang paling efisien dan akurat untuk mendapatkannya.

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

Jawaban:

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.

Hari ke 0 adalah hari terakhir di bulan sebelumnya. Karena konstruktor bulan berbasis 0, ini berfungsi dengan baik. Sedikit hack, tapi pada dasarnya itulah yang Anda lakukan dengan mengurangi 32.

FlySwat
sumber
42
sintaks ini telah membingungkan saya untuk sementara waktu. Untuk mengikuti pola JS, saya akan merekomendasikan untuk menerapkan trik seperti ini:return new Date(year, month + 1, 0).getDate();
fguillen
2
Sayangnya ini gagal untuk tanggal sebelum 1000 M di mana Anda hanya dapat mengatur tahun dengan benar menggunakan SetFullYear (). Untuk membuatnya anti peluru, gunakan Tanggal baru (2000+ (tahun% 2000), bulan, 0). GetDate ()
Noel Walters
4
Catatan untuk diri saya di masa depan: persamaan fguillen dengan '+ 1' memberikan 28 hari ketika tahun 2014 dan bulan adalah 1 (yang, dalam JavaScript Date-object, berarti Februari). Mungkin ingin melakukannya dengan sedikit keheranan. Tapi ide yang sangat bagus dari FlySwat!
Harry Pehkonen
@ NoelWalters — Anda benar bahwa beberapa browser secara tidak benar mengubah dua digit tahun menjadi tanggal di abad ke-20 (jadi tanggal sebelum 100 M, bukan 1000 M), namun perbaikan Anda tidak memperbaikinya di browser tersebut. Satu-satunya cara untuk andal mengatur dua digit tahun adalah dengan menggunakan setFullYear : var d=new Date();d.setFullYear(year, month, date);.
RobG
1
Bagaimana jika monthyang 12 ? Bukankah seharusnya Datekonstruktor mengambil nilai dari 0 hingga 11 ?
anddero
8

Jika Anda sering memanggil fungsi ini, mungkin berguna untuk menyimpan nilai dalam cache untuk kinerja yang lebih baik.

Berikut adalah versi cache dari jawaban 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();
    }
})();
dolmen
sumber
6
Apakah rutin C / C ++ internal sangat lambat sehingga perlu disimpan dalam cache?
Pete Alvin
1
@PeteAlvin Tergantung pada implementasi Date(jadi tidak ada jawaban universal untuk pertanyaan itu) dan seberapa sering kode Anda akan memanggil dayInMonthdengan nilai yang sama. Jadi satu-satunya jawaban yang masuk akal adalah: buat profil kode Anda dan tolok ukurnya!
dolmen
1
Saya suka itu! Namun alih-alih menggunakan objek baru cache,, saya menggunakan localStorage.
Andrew
5

Beberapa jawaban (juga pada pertanyaan lain) memiliki masalah tahun kabisat atau menggunakan objek Tanggal. Meskipun javascript Date objectmencakup kira-kira 285616 tahun (100.000.000 hari) di kedua sisi tanggal 1 Januari 1970, saya muak dengan semua jenis inkonsistensi tanggal yang tidak terduga di berbagai browser (terutama tahun 0 hingga 99). Saya juga penasaran bagaimana cara menghitungnya.

Jadi saya menulis yang sederhana dan di atas segalanya, algoritma kecil untuk menghitung jumlah hari yang benar ( Proleptic Gregorian / Astronomical / ISO 8601: 2004 (klausul 4.3.2.1), jadi tahun0 ada dan merupakan tahun kabisat dan tahun negatif didukung ) jumlah hari untuk bulan dan tahun tertentu.
Ini menggunakan algoritma bitmask-modulo leapYear sirkuit pendek (sedikit dimodifikasi untuk js) dan algoritma umum mod-8 bulan.

Perhatikan bahwa dalam AD/BCnotasi, tahun 0 M / SM tidak ada: sebagai gantinya tahun 1 BCadalah tahun kabisat!
JIKA Anda perlu menghitung notasi BC maka kurangi satu tahun dari nilai tahun (jika tidak positif) dulu !! (Atau kurangi tahun dari 1untuk perhitungan tahun selanjutnya.)

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>

Perhatikan, bulan harus berbasis 1!

Catatan, ini adalah algoritma yang berbeda maka pencarian angka ajaib yang saya gunakan dalam Javascript saya menghitung hari dalam setahun (1 - 366) jawaban, karena di sini cabang tambahan untuk tahun kabisat hanya diperlukan untuk bulan Februari.

GitaarLAB
sumber
4

Untuk menghilangkan kebingungan saya mungkin akan membuat string bulan berbasis karena saat ini berbasis 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
Jaybeecave
sumber
4

Dengan moment.js Anda dapat menggunakan metode daysInMonth ():

moment().daysInMonth(); // number of days in the current month
moment("2012-02", "YYYY-MM").daysInMonth() // 29
moment("2012-01", "YYYY-MM").daysInMonth() // 31
artem_p
sumber
2

Ini dia

new Date(2019,2,0).getDate(); //28
new Date(2020,2,0).getDate(); //29
Masum Billah
sumber
2

Sintaks ES6

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

kembali

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

console.log( d(2020, 6) );
// 30
RASG
sumber
1
Saat menambahkan jawaban baru untuk pertanyaan lama dengan 14 jawaban yang ada, sangat penting untuk memperhatikan aspek baru apa dari pertanyaan yang menjadi alamat jawaban Anda. Apakah ini hanya sintaks ES6?
Jason Aller
mengerti. akan menambahkan konteks pada jawaban mulai sekarang.
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
        }
Tony Li
sumber
1

Mempertimbangkan tahun kabisat:

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];
}
Yash
sumber
Bagus. Mudah dilihat. Prop [ertie] untuk penggunaan Nilai Inline-Map / Immediately-Keyed.
Cody
1

Perhitungan langsung satu baris (tanpa objek Tanggal):

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

Variasi dengan bulan berbasis 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);
}
Tomas Langkaas
sumber
1

Jika Anda menginginkan jumlah hari di bulan saat ini dari objek Tanggal, pertimbangkan metode berikut:

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

Kemudian Anda dapat menjalankannya seperti ini:

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!
mrplants
sumber
1

Dalam satu baris:

// 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;
}
Shl
sumber
1

Mungkin agak berlebihan jika dibandingkan dengan jawaban yang dipilih :) Tapi ini dia:

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

Saya menemukan kode di atas di sini: 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));

Saya menemukan kode di atas di sini: https://github.com/datejs/Datejs/blob/master/src/core.js

Syed
sumber
1

Jika Anda akan meneruskan variabel tanggal, ini mungkin membantu

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

daysInThisMonth = getDaysInMonth(new Date());

console.log(daysInThisMonth);

sanka sanjeeva
sumber
-1

Mungkin bukan solusi yang paling elegan, tetapi mudah dipahami dan dipelihara; dan, itu teruji dalam pertempuran.

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;
},
kmiklas
sumber