Обчисліть останній день місяця в JavaScript


277

Якщо ви вказали 0як dayValueв, Date.setFullYearви отримуєте останній день попереднього місяця:

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

Існує посилання на цю поведінку в Mozilla . Це надійна функція крос-браузера чи варто переглянути альтернативні методи?


Ви не маєте на увазі вказаний останній день місяця? У листопаді 30 днів і 31 жовтня.
Кріс Серра

16
Місячні місяці базуються на JavaScript, тому 11 грудня
Грег,

2
@TheCloudlessSky - спробуйте це у своїй консолі ... (2008,11,0) - нульовий день грудня, а тому останній день листопада
Кен,

@Ken - Так - я не розумів, що є "0":) ... було рано вранці.
TheCloudlessSky

Відповіді:


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

Різниці у виході обумовлені різницею в toString()реалізації, а не тому, що дати відрізняються.

Звичайно, тільки тому, що вказані вище браузери використовують 0 як останній день попереднього місяця, це не означає, що вони будуть продовжувати це робити, або що браузери, які не перераховані в списку, будуть робити це, але це надає достовірності вірі в те, що він повинен працювати однаково у кожному браузері.


19
Це, здається, працює чудово. З цікавості, що ви використовуєте для запуску javascript на всіх цих двигунах? У вас все налаштування чи якийсь інструмент?
неонський

5
ви можете використовувати d.getDate (), щоб отримати фактичний день.
риноп

35
"тільки тому, що браузери ... використовують 0 як останній день попереднього місяця, не означає, що вони продовжать робити це". Так, це вимагається, ECMA-262.
RobG

3
Будь ласка , зверніть увагу , що використання new Dateє так набагато повільніше , ніж інші методи розрахунку , що він навіть не з'являється на перфорація графіку : jsperf.com/days-in-month-perf-test/6
Віднесені Coding

4
Він не працює для Chrome 48.0.2564.116. Можливо, цей шлях перестав бути "стандартним".
xarlymg89

77

Я б використав проміжну дату з першого дня наступного місяця і повернув би дату з попереднього дня:

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

Відповідно до специфікації ECMAScript , використання конструктора "Дата", як ви вказали, є дійсним. Дотримуючись алгоритму, визначеного функцією "MakeDay", він повинен добре вирішити проблему.
Пабло Кабрера

1
це найкраще рішення ІМО. Я спробував прийняти відповідь, але в ньому є помилка під час отримання останнього поточного місяця. Він повертає сьогоднішню дату. Не впевнений, чому це відбувається, хоча.
Гоголь

1
Я не можу спростувати помилку. Це дає мені правильну дату у всіх браузерах:today = new Date(); new Date(today.getFullYear(), today.getMonth()+1, 0).toString();
orad

Це створює об'єкт Date за останній день місяця із часом, встановленим в останній мілісекунді (тобто 23: 59: 59.999). Краще просто скористатися методом в ОП і зберегти зайвий крок та об'єкт Дата.
RobG

@RobG: Я згоден! хоча моє рішення може бути простішим для розуміння, оскільки поняття використання 0 за останній день місяця, на мою думку, трохи незграбне.
karlipoppins

72

Я вважаю це найкращим рішенням для мене. Нехай об’єкт Date обчислить його для вас.

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

Якщо встановити параметр дня 0, це на один день менше першого дня місяця, який є останнім днем ​​попереднього місяця.


1
Це добре, я помітив, що обрана відповідь пропонує те саме. Це найшвидший і надійний спосіб і працює незалежно від типу календаря. Наприклад, якби Date реалізував щось інше, ніж григоріанський календар, він би все ще працював. Див. Intldate.codeplex.com для прикладу негригоріанської реалізації об'єкта Date.
орад

1
@orad: Остерігайтеся того, щоб стверджувати, що щось є "найшвидшим", оскільки цей метод насправді значно повільніше, ніж деякі альтернативи. Використовуючи new Dateце так набагато повільніше навіть не з'являється на перфорації графіку : jsperf.com/days-in-month-perf-test/6
Віднесені Coding

@TrueBlueAussie ОК. Я припускав, що це швидше, бо він рідний. Але ти маєш рацію, це не швидко. Дякуємо, що насправді протестували. У будь-якому випадку це рішення найкраще працює для мене, оскільки воно є стислим і читабельним і на відміну від усіх інших рішень не пов'язане з григоріанським календарем.
орд

"на відміну від усіх інших рішень не пов'язаний з григоріанським календарем" !!! Цей алгоритм повертає ті ж значення, що і мій, протягом 1-4000 років. jsfiddle.net/2973x9m3/3 Який додатковий діапазон дат ти стверджуєш, що це підтримуватиме (що було б корисно )? :)
Пройшло кодування

1
Native JS Date використовує лише григоріанський календар. Але ви можете знущатися з іншою реалізацією, щоб отримати інші типи календаря. Наприклад, див. IntlDate . Якщо у вас є інструмент вибору дати, який використовує об'єкти дати для створення щомісячних представлень даних, не важливо, яку дату імплементації (нативної чи знущається) вона використовує, якщо вони мають однаковий інтерфейс. Тож використання спільного інтерфейсу дозволяє перемикатися між різними типами календаря, не знаючи, скільки днів у місяці в кожному календарі.
орд

25

У комп'ютерній термінології, new Date()і regular expressionрішення повільно! Якщо ви хочете надшвидкий (і супер-криптичний) однопластовий, спробуйте цей (припустимо m, що у Jan=1форматі). Я намагаюся змінити різні коди, щоб досягти найкращої продуктивності.

Моя поточна найшвидша версія:

Переглянувши це пов'язане питання Перевірка року у високосному періоді за допомогою побітових операторів (дивовижна швидкість) та виявивши, що представляє собою магічне число 25 та 15, я придумав цей оптимізований гібрид відповідей:

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

Зважаючи на зміщення бітів, це, очевидно, передбачає, що ваші m& yпараметри є цілими числами, оскільки передача чисел як рядків призведе до дивних результатів.

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

Результати JSPerf: http://jsperf.com/days-in-month-head-to-head/5

З якої - то причини, (m+(m>>3)&1)є більш ефективним , ніж (5546>>m&1)на майже всі браузери.

Єдина справжня конкуренція за швидкість - це від @GitaarLab, тому я створив JSPerf з головою до голови, щоб перевірити: http://jsperf.com/days-in-month-head-to-head/5


Це працює на основі моєї відповіді високосного року тут: javascript, щоб знайти високосний рік, ця відповідь тут. Перевірити рік випуску за допомогою побітових операторів (дивовижна швидкість) , а також наступної бінарної логіки.

Швидкий урок у двійкові місяці:

Якщо ви інтерпретуєте індекс бажаних місяців (січ = 1) у двійковій формі, ви помітите, що місяці, що мають 31 день, або мають біт 3 прозорих, і біт 0 встановлений, або біт 3 встановлений і біт 0 ясний.

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

Це означає, що ви можете змістити значення 3 місця на >> 3, XOR біти з оригіналом ^ mі побачити, чи є результат, 1або 0 в бітовій позиції 0, використовуючи & 1. Примітка: Виходить +трохи швидше, ніж XOR ( ^) і (m >> 3) + mдає такий же результат у біті 0.

Результати JSPerf : http://jsperf.com/days-in-month-perf-test/6


Оригінал альго та повна історія (див. Коментарі): stackoverflow.com/questions/1810984/number-of-days-in-any-month/… з наступним stackoverflow.com/questions/1810984/number-of-days-in-any -місяць /…
GitaarLAB

1
@GitaarLAB: Ви вже згадали, і це ніколи не було таким, як ваше, як ви добре знаєте. Поступове оновлення алгоритмів один одного - це не те саме, що "оригінальний алго". Я також доклав багато зусиль до цієї відповіді: P
Пройшло кодування

@TrueBlueAussie: Я хотів лише вказати майбутнім читачам на нашу скарбницю більше інформації (я зв'язав обидві наші відповіді, щоб кожен, хто хвилює або хоче взяти ще один, переглянув нашу історію редагування, щоб побачити, коли ми зробили що і чому ). Я все ще приємно пам'ятаю наш повний день змагань! :)Найперша версія відповіді, яку я опублікував, справді мала непотрібний набір дужок, які були видалені (за що я вам зарахований), щоб ми могли поголити персонажа і закінчити цей. Я все ще вдячний за той веселий день, ура!
GitaarLAB

1
Прохання вказати , що yі mзмінні повинні бути цілим числом не рядок! Це спричиняє неправильні розрахунки, наприклад, за лютий він повертається 30. Мені довелося використовувати parseInt()функцію, щоб вона працювала.
замість

21

Мій колега натрапив на таке, що може бути простішим рішенням

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

викрадено з http://snippets.dzone.com/posts/show/2099


2
Найджел змінив це на ще більш стисле рішення. Дивіться його пост.
orad

Місяць заснований на нулі, тобто Jan = 0. Те саме, що і getMonth ().
Моос

16

Невелика зміна розчину, що надається лебрізом :

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

Це має бути return new Date(iYear, 1 + iMonth, 0).getDate();еквівалентним рішенням @ lebreeze.
Моос

6

Нещодавно мені довелося зробити щось подібне, ось що я придумав:

/**
* 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;
}

Передайте його в дату, і вона поверне дату, встановлену або на початок місяця, або на кінець місяця.

Ця begninngOfMonthфункція досить сама собою пояснює, але те, що відбувається в endOfMonthфункції, полягає в тому, що я збільшую місяць до наступного місяця, а потім використовую, setDate(0)щоб повернути день до останнього дня попереднього місяця, який є частиною специфікація setDate:

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

Потім я встановлюю годину / хвилини / секунди до кінця дня, так що якщо ви використовуєте якийсь API, який очікує діапазон дат, ви зможете зафіксувати весь останній день. Ця частина може вийти за рамки того, що просить початковий пост, але це може допомогти іншому, хто шукає подібне рішення.

Редагувати: Ви також можете пройти додаткову милю і встановити мілісекунди, setMilliseconds()якщо хочете бути дуже точними.


4

спробуйте це.

lastDateofTheMonth = new Date(year, month, 0)

приклад:

new Date(2012, 8, 0)

вихід:

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

5
Пам’ятайте, хоча, що місяці базуються на нулі, тож проходить «8», як місяць справді вересень, а не серпень.
Steve J

3

Це працює для мене. Вкаже останній день даного року та місяця:

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

1
будьте обережні з 0 перед "2", це буде інтерпретуватися як вісімковий.
Вальфрат

1

Цей чудово працює:

Date.prototype.setToLastDateInMonth = function () {

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

    return this;
}

1

Це дасть вам поточний місяць перший та останній день.

Якщо вам потрібно змінити 'year', видаліть d.getFullYear () та встановіть свій рік.

Якщо вам потрібно змінити "місяць", видаліть d.getMonth () та встановіть рік.

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

Спробуйте це:

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

Нижче функція дає останній день місяця:

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

Аналогічно ми можемо отримати перший день місяця:

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

встановити місяць, який вам потрібно дати, а потім встановити нуль, тому місяць почніть з 1 - 31 у функції дати, тоді отримайте останній день ^^

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


0

Ось відповідь, яка зберігає GMT та час початкової дати

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

Я знаю, що це лише питання семантики, але я в кінцевому підсумку використовував її в такій формі.

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

Оскільки функції вирішуються з внутрішнього аргументу, назовні, він працює так само.

Потім ви можете просто замінити рік та місяць / рік необхідними реквізитами, будь то з поточної дати. Або конкретний місяць / рік.


0

Якщо вам потрібен точний кінець місяця в мілісекундах (наприклад, у часовій позначці):

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.