Tính ngày cuối cùng của tháng bằng JavaScript


276

Nếu bạn cung cấp 0như là dayValuetrong Date.setFullYearbạn nhận được vào ngày cuối cùng của tháng trước:

d = new Date(); d.setFullYear(2008, 11, 0); //  Sun Nov 30 2008

Có tài liệu tham khảo hành vi này tại mozilla . Đây có phải là một tính năng đa trình duyệt đáng tin cậy hay tôi nên xem xét các phương pháp thay thế?


Ý bạn là ngày cuối cùng của tháng được chỉ định? Có 30 ngày vào tháng 11 và 31 vào tháng 10.
Chris Serra

16
Các tháng không dựa trên javascript nên 11 là tháng 12
Greg

2
@TheCloudlessSky - hãy thử nó trong bảng điều khiển của bạn ... (2008,11,0) là ngày số 0 của tháng 12, và do đó là ngày cuối cùng của tháng 11
Ken

@Ken - Vâng - Tôi không nhận ra có "0" :) ... còn quá sớm vào buổi sáng.
TheCloudlessSky

Câu trả lời:


423
var month = 0; // January
var d = new Date(2008, month + 1, 0);
alert(d); // last day in January

IE 6:                     Thu Jan 31 00:00:00 CST 2008
IE 7:                     Thu Jan 31 00:00:00 CST 2008
IE 8: Beta 2:             Thu Jan 31 00:00:00 CST 2008
Opera 8.54:               Thu, 31 Jan 2008 00:00:00 GMT-0600
Opera 9.27:               Thu, 31 Jan 2008 00:00:00 GMT-0600
Opera 9.60:               Thu Jan 31 2008 00:00:00 GMT-0600
Firefox 2.0.0.17:         Thu Jan 31 2008 00:00:00 GMT-0600 (Canada Central Standard Time)
Firefox 3.0.3:            Thu Jan 31 2008 00:00:00 GMT-0600 (Canada Central Standard Time)
Google Chrome 0.2.149.30: Thu Jan 31 2008 00:00:00 GMT-0600 (Canada Central Standard Time)
Safari for Windows 3.1.2: Thu Jan 31 2008 00:00:00 GMT-0600 (Canada Central Standard Time)

Sự khác biệt đầu ra là do sự khác biệt trong việc toString()thực hiện, không phải vì ngày khác nhau.

Tất nhiên, chỉ vì các trình duyệt được xác định ở trên sử dụng 0 là ngày cuối cùng của tháng trước không có nghĩa là họ sẽ tiếp tục làm như vậy hoặc các trình duyệt không được liệt kê sẽ làm như vậy, nhưng nó cho vay sự tin cậy rằng nó sẽ hoạt động cùng một cách trong mọi trình duyệt.


19
Điều đó dường như làm việc hoàn toàn tốt. Vì tò mò, bạn đang sử dụng gì để chạy javascript trên tất cả các công cụ này? Có tất cả mọi thứ được thiết lập hoặc một số loại công cụ?
neonski

5
bạn có thể sử dụng d.getDate () để có được ngày thực tế.
rynop

35
"Chỉ vì các trình duyệt mà sử dụng 0 là ngày cuối cùng của tháng trước không có nghĩa là họ sẽ tiếp tục làm như vậy". Có, họ được yêu cầu làm như vậy bởi ECMA-262.
RobG

3
Hãy lưu ý rằng việc sử dụng new Datequá chậm hơn nhiều so với phương pháp tính khác mà nó thậm chí không xuất hiện trên bảng xếp hạng về hiệu suất : jsperf.com/days-in-month-perf-test/6
Cuốn Mã hóa

4
Nó không hoạt động với tôi trên Chrome 48.0.2564.116. Có lẽ, cách này đã không còn là 'tiêu chuẩn'.
xarlymg89

77

Tôi sẽ sử dụng một ngày trung gian với ngày đầu tiên của tháng tiếp theo và trả lại ngày từ ngày hôm trước:

int_d = new Date(2008, 11+1,1);
d = new Date(int_d - 1);

Theo đặc tả ECMAScript , việc sử dụng hàm tạo "Ngày" như bạn đã chỉ ra là hợp lệ. Theo thuật toán được chỉ định bởi chức năng "MakeDay", nó sẽ xử lý vấn đề này một cách độc đáo.
Pablo Cabrera

1
Đây là giải pháp tốt nhất IMO. Tôi đã thử câu trả lời được chấp nhận nhưng nó có một số lỗi khi tìm nạp cuối cùng của tháng hiện tại. Nó trả về ngày hôm nay. Không chắc chắn tại sao điều đó xảy ra mặc dù.
Gogol

1
Tôi không thể sửa lỗi. Điều này cho tôi ngày chính xác trong tất cả các trình duyệt:today = new Date(); new Date(today.getFullYear(), today.getMonth()+1, 0).toString();
orad

Điều này tạo ra một đối tượng Ngày cho ngày cuối cùng của tháng với thời gian được đặt thành mili giây cuối cùng (tức là 23: 59: 59.999). Tốt hơn là chỉ sử dụng phương thức trong OP và lưu thêm bước và đối tượng Date.
RobG

@RobG: tôi đồng ý! mặc dù giải pháp của tôi có thể dễ hiểu hơn, vì quan niệm về việc sử dụng 0 cho ngày cuối cùng của tháng cảm thấy hơi khó hiểu theo quan điểm của tôi.
karlipoppin

72

Tôi thấy đây là giải pháp tốt nhất cho tôi. Hãy để đối tượng Date tính toán nó cho bạn.

var today = new Date();
var lastDayOfMonth = new Date(today.getFullYear(), today.getMonth()+1, 0);

Đặt tham số ngày thành 0 có nghĩa là một ngày ít hơn ngày đầu tiên của tháng là ngày cuối cùng của tháng trước.


1
Không sao, tôi nhận thấy câu trả lời được chọn cũng gợi ý như vậy. Đây là cách nhanh nhất và đáng tin cậy nhất và hoạt động bất kể loại lịch. Ví dụ: nếu Ngày triển khai một cái gì đó ngoài lịch Gregorian thì nó vẫn hoạt động. Xem intldate.codeplex.com để biết ví dụ về việc triển khai đối tượng Date của người Gregorian.
orad

1
@orad: Coi chừng yêu cầu một cái gì đó "là nhanh nhất" vì phương pháp này thực sự chậm hơn đáng kể so với một số lựa chọn thay thế. Sử dụng new Datequá chậm hơn nó thậm chí không xuất hiện trên bảng xếp hạng về hiệu suất : jsperf.com/days-in-month-perf-test/6
Cuốn Mã hóa

@TrueBlueAussie OK. Tôi đã cho rằng nó nhanh hơn vì nó là bản địa. Nhưng bạn nói đúng, nó không nhanh. Cảm ơn vì đã thực sự thử nghiệm nó. Dù sao, giải pháp này hoạt động tốt nhất đối với tôi vì nó ngắn gọn và dễ đọc và không giống như tất cả các giải pháp khác không bị ràng buộc với lịch Gregorian.
orad

"không giống như tất cả các giải pháp khác không bị ràng buộc với Lịch Gregorian" !!! Thuật toán này trả về các giá trị giống như của tôi trong các năm 1-4000. jsfiddle.net/2973x9m3/3 Phạm vi ngày bổ sung nào bạn cho rằng điều này sẽ hỗ trợ (sẽ được sử dụng)? :)
Mã hóa đã qua

1
Ngày JS gốc chỉ sử dụng lịch Gregorian. Nhưng bạn có thể giả định nó với một số triển khai khác để có được các loại lịch khác. Ví dụ, xem IntlDate . Nếu bạn có một công cụ chọn ngày sử dụng các đối tượng Ngày để tạo chế độ xem hàng tháng, thì không quan tâm đến việc triển khai Ngày nào (nguyên gốc hoặc bị chế giễu) mà nó đang sử dụng miễn là chúng có cùng giao diện. Vì vậy, sử dụng giao diện được chia sẻ cho phép chuyển đổi giữa các loại Lịch khác nhau mà không cần phải biết có bao nhiêu ngày trong một tháng trên mỗi lịch.
orad

24

Về mặt máy tính, new Date()regular expressioncác giải pháp là chậm! Nếu bạn muốn một lớp lót siêu nhanh (và siêu khó hiểu), hãy thử cái này (giả sử mlà ở Jan=1định dạng). Tôi tiếp tục thử các thay đổi mã khác nhau để có hiệu suất tốt nhất.

Phiên bản nhanh nhất hiện tại của tôi :

Sau khi xem câu hỏi liên quan này Kiểm tra năm nhuận bằng cách sử dụng các toán tử bitwise (tốc độ đáng kinh ngạc) và khám phá ra con số ma thuật 25 & 15 được thể hiện là gì, tôi đã đưa ra câu trả lời được tối ưu hóa này:

function getDaysInMonth(m, y) {
    return m===2 ? y & 3 || !(y%25) && y & 15 ? 28 : 29 : 30 + (m+(m>>3)&1);
}

Với sự dịch chuyển bit, điều này rõ ràng giả định rằng các tham số m& của bạn yđều là số nguyên, vì việc truyền số dưới dạng chuỗi sẽ dẫn đến kết quả kỳ lạ.

JSFiddle: http://jsfiddle.net/TrueBlueAussie/H89X3/22/

Kết quả của JSPerf: http://jsperf.com/days-in-month-head-to-head/5

Đối với một số lý do, (m+(m>>3)&1)là hiệu quả hơn (5546>>m&1)trên hầu hết tất cả các trình duyệt.

Sự cạnh tranh thực sự duy nhất về tốc độ là từ @GitaarLab, vì vậy tôi đã tạo ra một tệp JSPerf trực tiếp để chúng tôi thử nghiệm trên: http://jsperf.com/days-in-month-head-to-head/5


Nó hoạt động dựa trên câu trả lời năm nhuận của tôi ở đây: javascript để tìm năm nhuận câu trả lời này ở đây Kiểm tra năm nhuận bằng cách sử dụng các toán tử bitwise (tốc độ đáng kinh ngạc) cũng như logic nhị phân sau.

Một bài học nhanh trong tháng nhị phân:

Nếu bạn diễn giải chỉ số của các tháng mong muốn (tháng 1 = 1) theo nhị phân, bạn sẽ nhận thấy rằng các tháng có 31 ngày có bit 3 rõ ràng và bit 0 được đặt, hoặc bit 3 được đặt và bit 0 rõ ràng.

Jan = 1  = 0001 : 31 days
Feb = 2  = 0010
Mar = 3  = 0011 : 31 days
Apr = 4  = 0100
May = 5  = 0101 : 31 days
Jun = 6  = 0110
Jul = 7  = 0111 : 31 days
Aug = 8  = 1000 : 31 days
Sep = 9  = 1001
Oct = 10 = 1010 : 31 days
Nov = 11 = 1011
Dec = 12 = 1100 : 31 days

Điều đó có nghĩa là bạn có thể thay đổi giá trị 3 vị trí với >> 3, XOR các bit với bản gốc ^ mvà xem kết quả là 1hoặc 0 ở vị trí bit 0 bằng cách sử dụng & 1. Lưu ý: Hóa ra +là nhanh hơn một chút so với XOR ( ^) và (m >> 3) + mcho kết quả tương tự trong bit 0.

Kết quả của JSPerf : http://jsperf.com/days-in-month-perf-test/6



1
@GitaarLAB: Bạn đã có một đề cập và điều này không bao giờ chính xác như của bạn, như bạn đã biết. Cập nhật tăng dần của các thuật toán khác không giống như "thuật toán gốc". Tôi cũng đã nỗ lực rất nhiều cho câu trả lời này: P
Gone Coding

@TrueBlueAussie: Tôi chỉ muốn hướng người đọc tương lai đến kho thông tin khác của chúng tôi (Tôi đã liên kết cả hai câu trả lời của chúng tôi để bất kỳ ai quan tâm hoặc muốn thực hiện một lần nữa có thể nhìn vào lịch sử chỉnh sửa của chúng tôi để xem khi nào chúng tôi đã làm tại sao ). Tôi vẫn còn nhớ ngày thi đấu trọn vẹn của chúng tôi! :)Phiên bản trả lời đầu tiên tôi đã đăng thực sự là một bộ dấu ngoặc không cần thiết, đã bị xóa (mà tôi ghi có cho bạn) để chúng tôi có thể cạo một ký tự và kết thúc với ký tự này. Tôi vẫn biết ơn vì ngày vui đó, chúc mừng!
GitaarLAB

1
Hãy đề cập đến điều đó ymcác biến phải là số nguyên không phải là chuỗi! Nó gây ra các tính toán sai, ví dụ cho tháng hai, nó trả về 30. Tôi đã phải sử dụng parseInt()hàm để làm cho nó hoạt động.
thay vì

21

Đồng nghiệp của tôi vấp phải những điều sau đây có thể là một giải pháp dễ dàng hơn

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

bị đánh cắp từ http://snippets.dzone.com/posts/show/2099


2
Nigel đã sửa đổi điều này thành giải pháp ngắn gọn hơn. Xem bài viết của anh ấy.
orad

Tháng là không dựa trên, tức là tháng 1 = 0. Giống như getMonth ().
Moos

16

Một sửa đổi nhỏ cho giải pháp được cung cấp bởi lebreeze :

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

Điều này sẽ return new Date(iYear, 1 + iMonth, 0).getDate();tương đương với giải pháp của @ lebreeze.
Moos

6

Gần đây tôi đã phải làm một cái gì đó tương tự, đây là những gì tôi nghĩ ra:

/**
* Returns a date set to the begining of the month
* 
* @param {Date} myDate 
* @returns {Date}
*/
function beginningOfMonth(myDate){    
  let date = new Date(myDate);
  date.setDate(1)
  date.setHours(0);
  date.setMinutes(0);
  date.setSeconds(0);   
  return date;     
}

/**
 * Returns a date set to the end of the month
 * 
 * @param {Date} myDate 
 * @returns {Date}
 */
function endOfMonth(myDate){
  let date = new Date(myDate);
  date.setMonth(date.getMonth() +1)
  date.setDate(0);
  date.setHours(23);
  date.setMinutes(59);
  date.setSeconds(59);
  return date;
}

Vượt qua nó trong một ngày và nó sẽ trả về một ngày được đặt thành đầu tháng hoặc cuối tháng.

Các begninngOfMonthchức năng là khá tự giải thích, nhưng những gì đang diễn ra trong trong endOfMonthchức năng là tôi đang incrementing tháng đến vào tháng tới, và sau đó sử dụng setDate(0)để quay trở lại ngày đến ngày cuối cùng của tháng trước đó là một phần của setDate spec:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setDate https://www.w3schools.com/jsref/jsref_setdate.asp

Sau đó, tôi đặt giờ / phút / giây vào cuối ngày, để nếu bạn đang sử dụng một loại API nào đó đang mong đợi một phạm vi ngày, bạn sẽ có thể nắm bắt toàn bộ ngày hôm đó. Phần đó có thể vượt xa những gì bài viết gốc đang yêu cầu nhưng nó có thể giúp người khác tìm kiếm một giải pháp tương tự.

Chỉnh sửa: Bạn cũng có thể đi thêm một dặm và đặt mili giây setMilliseconds()nếu bạn muốn chính xác hơn.


4

thử cái này

lastDateofTheMonth = new Date(year, month, 0)

thí dụ:

new Date(2012, 8, 0)

đầu ra:

Date {Fri Aug 31 2012 00:00:00 GMT+0900 (Tokyo Standard Time)}

5
Tuy nhiên, hãy nhớ rằng các tháng đó dựa trên số không, vì vậy, vượt qua "8" vì tháng thực sự là tháng 9, không phải tháng 8.
Steve J

3

Điều này làm việc cho tôi. Sẽ cung cấp ngày cuối cùng của năm và tháng nhất định:

var d = new Date(2012,02,0);
var n = d.getDate();
alert(n);

hãy cẩn thận với số 0 ở phía trước "2", nó sẽ được hiểu là số bát phân.
Walfrat

1

Điều này hoạt động độc đáo:

Date.prototype.setToLastDateInMonth = function () {

    this.setDate(1);
    this.setMonth(this.getMonth() + 1);
    this.setDate(this.getDate() - 1);

    return this;
}

1

Điều này sẽ cung cấp cho bạn tháng hiện tại đầu tiên và ngày cuối cùng.

Nếu bạn cần thay đổi 'năm', hãy xóa d.getFullYear () và đặt năm của bạn.

Nếu bạn cần thay đổi 'tháng', hãy xóa d.getMonth () và đặt năm của bạn.

var d = new Date();
var days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
var fistDayOfMonth = days[(new Date(d.getFullYear(), d.getMonth(), 1).getDay())];
	var LastDayOfMonth = days[(new Date(d.getFullYear(), d.getMonth() + 1, 0).getDay())]; 
console.log("First Day :" + fistDayOfMonth); 
console.log("Last Day:" + LastDayOfMonth);
alert("First Day :" + fistDayOfMonth); 
alert("Last Day:" + LastDayOfMonth);


1

Thử cái này:

function _getEndOfMonth(time_stamp) {
    let time = new Date(time_stamp * 1000);
    let month = time.getMonth() + 1;
    let year = time.getFullYear();
    let day = time.getDate();
    switch (month) {
        case 1:
        case 3:
        case 5:
        case 7:
        case 8:
        case 10:
        case 12:
            day = 31;
            break;
        case 4:
        case 6:
        case 9:
        case 11:
            day = 30;
            break;
        case 2:
            if (_leapyear(year))
                day = 29;
            else
                day = 28;
            break
    }
    let m = moment(`${year}-${month}-${day}`, 'YYYY-MM-DD')
    return m.unix() + constants.DAY - 1;
}

function _leapyear(year) {
    return (year % 100 === 0) ? (year % 400 === 0) : (year % 4 === 0);
}

1

Chức năng dưới đây cung cấp cho ngày cuối cùng của tháng:

function getLstDayOfMonFnc(date) {
  return new Date(date.getFullYear(), date.getMonth(), 0).getDate()
}

console.log(getLstDayOfMonFnc(new Date(2016, 2, 15))) // Output : 29
console.log(getLstDayOfMonFnc(new Date(2017, 2, 15))) // Output : 28
console.log(getLstDayOfMonFnc(new Date(2017, 11, 15))) // Output : 30
console.log(getLstDayOfMonFnc(new Date(2017, 12, 15))) // Output : 31

Tương tự như vậy, chúng ta có thể có được ngày đầu tiên của tháng:

function getFstDayOfMonFnc(date) {
  return new Date(date.getFullYear(), date.getMonth(), 1).getDate()
}

console.log(getFstDayOfMonFnc(new Date(2016, 2, 15))) // Output : 1


0
function getLastDay(y, m) {
   return 30 + (m <= 7 ? ((m % 2) ? 1 : 0) : (!(m % 2) ? 1 : 0)) - (m == 2) - (m == 2 && y % 4 != 0 || !(y % 100 == 0 && y % 400 == 0)); 
}

0
const today = new Date();

let beginDate = new Date();

let endDate = new Date();

// fist date of montg

beginDate = new Date(

  `${today.getFullYear()}-${today.getMonth() + 1}-01 00:00:00`

);

// end date of month 

// set next Month first Date

endDate = new Date(

  `${today.getFullYear()}-${today.getMonth() + 2}-01 :23:59:59`

);

// deducting 1 day

endDate.setDate(0);

0

đặt tháng bạn cần hẹn hò và sau đó đặt ngày về 0, vì vậy tháng bắt đầu bằng 1 - 31 trong chức năng ngày sau đó lấy ngày cuối cùng ^^

var last = new Date(new Date(new Date().setMonth(7)).setDate(0)).getDate();
console.log(last);


0

Đây là một câu trả lời bảo tồn GMT và thời gian của ngày đầu tiên

var date = new Date();

var first_date = new Date(date); //Make a copy of the date we want the first and last days from
first_date.setUTCDate(1); //Set the day as the first of the month

var last_date = new Date(first_date); //Make a copy of the calculated first day
last_date.setUTCMonth(last_date.getUTCMonth() + 1); //Add a month
last_date.setUTCDate(0); //Set the date to 0, this goes to the last day of the previous month

console.log(first_date.toJSON().substring(0, 10), last_date.toJSON().substring(0, 10)); //Log the dates with the format yyyy-mm-dd


0

Tôi biết đó chỉ là vấn đề ngữ nghĩa, nhưng cuối cùng tôi đã sử dụng nó trong hình thức này.

var lastDay = new Date(new Date(2008, 11+1,1) - 1).getDate();
console.log(lastDay);

Vì các hàm được giải quyết từ đối số bên trong, bên ngoài, nên nó hoạt động như nhau.

Sau đó, bạn có thể chỉ cần thay thế năm và tháng / năm bằng các chi tiết cần thiết, cho dù đó là từ ngày hiện tại. Hoặc một tháng / năm cụ thể.


0

Nếu bạn cần chính xác vào cuối tháng tính bằng milisecond (ví dụ: trong dấu thời gian):

d = new Date()
console.log(d.toString())
d.setDate(1)
d.setHours(23, 59, 59, 999)
d.setMonth(d.getMonth() + 1)
d.setDate(d.getDate() - 1)
console.log(d.toString())

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.