Cách tốt nhất để xác định số ngày trong tháng với JavaScript là gì?


107

Tôi đang sử dụng chức năng này nhưng tôi muốn biết cách hiệu quả và chính xác nhất để có được nó.

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

Câu trả lời:


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.

Ngày 0 là ngày cuối cùng trong tháng trước. Bởi vì hàm tạo tháng dựa trên 0, điều này hoạt động tốt. Hơi khó, nhưng về cơ bản đó là những gì bạn đang làm bằng cách trừ đi 32.


42
cú pháp này đã làm tôi bối rối trong một thời gian. Để thực hiện theo mô hình JS Tôi sẽ khuyên bạn nên thực hiện các thủ thuật như thế này:return new Date(year, month + 1, 0).getDate();
fguillen

2
Thật không may, điều này không thành công đối với các ngày trước năm 1000 sau Công nguyên, nơi bạn chỉ có thể đặt năm chính xác bằng cách sử dụng SetFullYear (). Để làm cho nó chống đạn, hãy sử dụng Date mới (2000+ (năm% 2000), tháng, 0) .getDate ()
Noel Walters

4
Lưu ý cho tương lai của tôi: phương trình fguillen với dấu '+ 1' cho 28 ngày khi năm là 2014 và tháng là 1 (trong JavaScript Date-object có nghĩa là tháng 2). Có lẽ muốn đi với điều đó cho ít ngạc nhiên nhất. Nhưng thật là một ý tưởng tuyệt vời từ FlySwat!
Harry Pehkonen

@ NoelWalters — bạn nói đúng rằng một số trình duyệt chuyển đổi không chính xác các năm có hai chữ số thành các ngày tính bằng đồng 20 (vì vậy các ngày trước năm 100 sau Công nguyên, không phải năm 1000 sau Công nguyên), tuy nhiên, bản sửa lỗi của bạn không khắc phục được điều đó trong các trình duyệt đó. Cách duy nhất để đặt năm hai chữ số một cách đáng tin cậy là sử dụng setFullYear : var d=new Date();d.setFullYear(year, month, date);.
RobG

1
Nếu month12 thì sao? Hàm tạo không nên Datenhận giá trị từ 0 đến 11 ?
anddero

8

Nếu bạn gọi hàm này thường xuyên, có thể hữu ích khi lưu giá trị vào bộ nhớ cache để có hiệu suất tốt hơn.

Đây là phiên bản bộ nhớ đệm của câu trả lời 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
Quy trình nội bộ C / C ++ có chậm đến mức yêu cầu bộ nhớ đệm không?
Pete Alvin

1
@PeteAlvin Nó phụ thuộc vào việc triển khai Date(vì vậy không có câu trả lời chung cho câu hỏi đó) và tần suất mã của bạn sẽ gọi mã dayInMonthvới các giá trị giống nhau. Vì vậy, câu trả lời hợp lý duy nhất là: lập hồ sơ mã của bạn và điểm chuẩn cho nó!
dolmen

1
Tôi thích nó! Nhưng thay vì sử dụng một đối tượng mới cache, tôi sử dụng localStorage.
andrew

5

Một số câu trả lời (cũng cho các câu hỏi khác) có vấn đề về năm nhuận hoặc sử dụng đối tượng Ngày. Mặc dù javascript Date objectbao gồm khoảng 285616 năm (100.000.000 ngày) ở cả hai phía của ngày 1 tháng 1 năm 1970, tôi đã chán ngấy với tất cả các loại mâu thuẫn ngày không mong muốn trên các trình duyệt khác nhau (đáng chú ý nhất là năm 0 đến năm 99). Tôi cũng tò mò làm thế nào để tính toán nó.

Vì vậy, tôi đã viết một thuật toán đơn giản và trên hết, nhỏ để tính toán chính xác ( Proleptic Gregorian / Astronomical / ISO 8601: 2004 (điều khoản 4.3.2.1), do đó năm0 tồn tại và là năm nhuận và năm âm được hỗ trợ ) số ngày cho một tháng và năm nhất định.
Nó sử dụng thuật toán bitmask-modulo leapYear ngắn mạch (được sửa đổi một chút cho js) và thuật toán mod-8 tháng phổ biến.

Lưu ý rằng trong AD/BCký hiệu, năm 0 AD / BC không tồn tại: thay vào đó năm 1 BClà năm nhuận!
NẾU bạn cần tính toán ký hiệu BC thì chỉ cần trừ đi một năm của giá trị năm (nếu không là dương) trước !! (Hoặc trừ năm 1cho các phép tính năm khác.)

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>

Lưu ý, các tháng phải dựa trên 1!

Lưu ý, đây là một thuật toán khác, sau đó phép tra cứu số ma thuật mà tôi đã sử dụng trong Javascript của mình sẽ tính toán câu trả lời ngày trong năm (1 - 366) , vì ở đây nhánh phụ cho năm nhuận chỉ cần cho tháng Hai.


4

Để loại bỏ sự nhầm lẫn, tôi có thể sẽ làm cho chuỗi tháng dựa trên nó hiện đang là 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

Với moment.js, bạn có thể sử dụng phương thức 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

Đây là đi

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

2

Cú pháp ES6

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

trả lại

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

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

1
Khi thêm một câu trả lời mới cho một câu hỏi cũ hơn với 14 câu trả lời hiện có, điều thực sự quan trọng là lưu ý khía cạnh mới của câu hỏi mà câu trả lời của bạn đề cập đến. Nó chỉ là cú pháp ES6?
Jason Aller

hiểu rồi. sẽ thêm ngữ cảnh vào câu trả lời từ bây giờ.
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

Xét các năm nhuận:

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

Đẹp. Dễ nhìn. Đề xuất [ertie] cho việc sử dụng Bản đồ nội tuyến / Giá trị được khóa ngay lập tức.
Cody

1

Tính toán trực tiếp một lớp (không có đối tượng Ngày):

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

Sự thay đổi với các tháng dựa trên 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

Nếu bạn muốn số ngày trong tháng hiện tại của đối tượng Ngày, hãy xem xét phương pháp sau:

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

Sau đó, bạn có thể chạy nó như thế này:

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

Trong một dòng:

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

Có thể hơi bị giết khi so sánh với câu trả lời đã chọn :) Nhưng đây là:

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

Tôi đã tìm thấy mã ở trên tại đây: 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));

Tôi đã tìm thấy đoạn mã trên tại đây: https://github.com/datejs/Datejs/blob/master/src/core.js


1

Nếu bạn định chuyển một biến ngày, điều này có thể hữu ích

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

daysInThisMonth = getDaysInMonth(new Date());

console.log(daysInThisMonth);


-1

Có lẽ không phải là giải pháp thanh lịch nhất, nhưng dễ hiểu và dễ bảo trì; và, nó đã được thử nghiệm trong trận chiến.

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;
},
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.