วิธีใดที่ดีที่สุดในการกำหนดจำนวนวันในหนึ่งเดือนด้วย 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
น่าเสียดายที่สิ่งนี้ล้มเหลวสำหรับวันที่ก่อน 1,000 โฆษณาซึ่งคุณสามารถกำหนดปีได้อย่างถูกต้องโดยใช้ SetFullYear () เพื่อให้หลักฐานแสดงหัวข้อย่อยใช้วันที่ใหม่ (2000+ (ปี% 2000), เดือน, 0) .getDate ()
Noel Walters

4
หมายเหตุถึงตัวตนในอนาคตของฉัน: สมการของ fguillen ที่มี '+ 1' จะให้ 28 วันเมื่อปีคือ 2014 และเดือนคือ 1 (ซึ่งใน JavaScript Date-object หมายถึงกุมภาพันธ์) อาจต้องการไปกับสิ่งนั้นอย่างน้อยประหลาดใจ แต่เป็นความคิดที่ยอดเยี่ยมจาก FlySwat!
Harry Pehkonen

@ NoelWalters คุณถูกต้องที่เบราว์เซอร์บางตัวแปลงปีสองหลักเป็นวันที่ในศตวรรษที่ 20 อย่างไม่ถูกต้อง (ดังนั้นวันที่ก่อน 100 AD ไม่ใช่ 1,000 AD) อย่างไรก็ตามการแก้ไขของคุณไม่ได้แก้ไขในเบราว์เซอร์เหล่านั้น วิธีเดียวที่จะตั้งค่าได้อย่างน่าเชื่อถือสองปีหลักคือการใช้setFullYearvar 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 ++ ภายในช้ามากจนต้องใช้แคชหรือไม่?
Pete Alvin

1
@PeteAlvin มันขึ้นอยู่กับการนำไปใช้Date(ดังนั้นจึงไม่มีคำตอบที่เป็นสากลสำหรับคำถามนั้น) และความถี่ที่รหัสของคุณจะเรียกdayInMonthด้วยค่าเดียวกัน ดังนั้นคำตอบเดียวที่สมเหตุสมผลคือ: กำหนดรหัสของคุณและเปรียบเทียบมัน!
dolmen

1
ฉันชอบมัน! แต่แทนที่จะใช้วัตถุใหม่cacheฉันใช้localStorage.
andrew

5

บางคำตอบ (รวมถึงคำถามอื่น ๆ ) มีปัญหาปีอธิกสุรทินหรือใช้วัตถุวันที่ แม้ว่าจาวาสคริปต์จะDate objectครอบคลุมประมาณ 285616 ปี (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-based!

โปรดทราบว่านี่เป็นอัลกอริทึมที่แตกต่างจากนั้นการค้นหาหมายเลขวิเศษที่ฉันใช้ใน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 หรือไม่?
Jason Aller

เข้าใจแล้ว จะเพิ่มบริบทให้กับคำตอบนับจากนี้
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] สำหรับการใช้ค่า Inline-Map / ทันทีที่คีย์
Cody

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;
},
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.