Рассчитать последний день месяца в 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

Ответы:

425
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);
karlipoppins
источник
Согласно спецификации ECMAScript , использование конструктора «Date», как вы указали, является допустимым. Следуя алгоритму, указанному функцией «MakeDay», он должен хорошо решить проблему.
Пабло Кабрера
1
это лучшее решение ИМО. Я попробовал принятый ответ, но у него есть какая-то ошибка при извлечении последнего из текущего месяца. Возвращает сегодняшнюю дату. Не уверен, почему это происходит, хотя.
Гоголь
1
Я не могу воспроизвести ошибку. Это дает мне правильную дату во всех браузерах:today = new Date(); new Date(today.getFullYear(), today.getMonth()+1, 0).toString();
orad
Это создает объект Date для последнего дня месяца с временем, установленным на последнюю миллисекунду (то есть 23: 59: 59.999). Лучше просто использовать метод в OP и сохранить дополнительный шаг и объект Date.
RobG
@RobG: я согласен! хотя мое решение может быть проще для понимания, так как, по моему мнению, понятие использования 0 для последнего дня месяца кажется немного неуклюжим.
karlipoppins
72

Я считаю, что это лучшее решение для меня. Пусть объект Date рассчитает это для вас.

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

Установка параметра дня в 0 означает, что на один день меньше первого дня месяца, который является последним днем ​​предыдущего месяца.

Orad
источник
1
Это нормально, я заметил, что выбранный ответ предлагает то же самое. Это самый быстрый и надежный способ, который работает независимо от типа календаря. Например, если бы Date реализовал что-то кроме григорианского календаря, он все равно работал бы. См. Intldate.codeplex.com для примера не-григорианской реализации объекта Date.
orad
1
@orad: Остерегайтесь претендовать на что-то «самое быстрое», так как этот метод на самом деле значительно медленнее, чем некоторые альтернативы. Используя new Dateэто так гораздо медленнее даже не появляется на перфорации графике : jsperf.com/days-in-month-perf-test/6
Унесенные Coding
@TrueBlueAussie ОК. Я предполагал, что это было быстрее, потому что это было родным. Но ты прав, это не быстро. Спасибо за тестирование. В любом случае, это решение лучше всего подходит для меня, потому что оно лаконично и читабельно и в отличие от всех других решений не связано с григорианским календарем.
Орад
«в отличие от всех других решений не связан с григорианским календарем» !!! Этот алгоритм возвращает те же значения, что и у меня для 1-4000 лет. jsfiddle.net/2973x9m3/3 Какой дополнительный диапазон дат вы заявляете, что он поддержит (что будет полезно )? :)
Ушел кодирование
1
Родной JS Date использует только григорианский календарь. Но вы можете поиграть с другой реализацией, чтобы получить другие типы календаря. Например, см. IntlDate . Если у вас есть средство выбора даты, которое использует объекты Date для создания ежемесячных представлений, то не имеет значения, какую реализацию Date (нативную или фиктивную) она использует, если у них одинаковый интерфейс. Таким образом, использование общего интерфейса позволяет переключаться между различными типами Календаря без необходимости знать, сколько дней в месяце в каждом календаре.
Орад
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, чтобы найти високосный год, этот ответ здесь Проверка високосного года с использованием побитовых операторов (удивительная скорость), а также следующей двоичной логики.

Быстрый урок в бинарных месяцах:

Если вы интерпретируете индекс желаемых месяцев (Jan = 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
Gone Coding
@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

lebreeze
источник
2
Найджел изменил это до еще более краткого решения. Смотрите его пост.
Орад
Месяц начинается с нуля, т. Е. Jan = 0. То же, что и getMonth ().
Моос
16

Небольшая модификация решения, предоставленная lebreeze :

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 spec:

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)}
artsylar
источник
5
Помните, однако, что месяцы начинаются с нуля, поэтому прохождение «8», поскольку месяц действительно сентябрь, а не август.
Стив Дж
3

Это работает для меня. Укажем последний день данного года и месяца:

var d = new Date(2012,02,0);
var n = d.getDate();
alert(n);
Kreeverp
источник
1
будьте осторожны с 0 перед «2», это будет интерпретировано как восьмеричное.
Вальфрат
1

Этот работает хорошо:

Date.prototype.setToLastDateInMonth = function () {

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

    return this;
}
Josue
источник
1

Это даст вам текущий месяц первый и последний день.

Если вам нужно изменить год, удалите 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)); 
}
Ashish
источник
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

Tofandel
источник
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())

Gungnir
источник