Количество дней в любом месяце

Как я могу написать функцию JavaScript, которая принимает число от 1 до 12, представляющее месяцы года, и затем возвращает количество дней в этом месяце?

Ответ 1

function getDaysInMonth(m, y) {
   return /8|3|5|10/.test(--m)?30:m==1?(!(y%4)&&y%100)||!(y%400)?29:28:31;
}

Ответ 2

Попробуйте следующее:

function numberOfDays(year, month) {
    var d = new Date(year, month, 0);
    return d.getDate();
}

Из-за високосных лет вам тоже нужно пройти год.

Ответ 3

Тридцать дней в сентябре,
Апрель, Июнь и Ноябрь,
Все остальные тридцать один,
Только за февраль,
Который имеет двадцать восемь дней ясно,
И двадцать девять в каждый високосный год.

< 3 Wikipedia

Ответ 4

Ответ любимого Джеймса. Немного переформатирован для заинтересованных.

function getDaysInMonth(m, y)
{
    // months in JavaScript start at 0 so decrement by 1 e.g. 11 = Dec
    --m;

    // if month is Sept, Apr, Jun, Nov return 30 days
    if( /8|3|5|10/.test( m ) ) return 30;

    // if month is not Feb return 31 days
    if( m != 1 ) return 31;

    // To get this far month must be Feb ( 1 )
    // if the year is a leap year then Feb has 29 days
    if( ( y % 4 == 0 && y % 100 != 0 ) || y % 400 == 0 ) return 29;

    // Not a leap year. Feb has 28 days.
    return 28;
}

Fiddle здесь

Ответ 5

Всем известно, что подсчет сэндвича Чак-костяшка бьет простую поэзию в любой день месяца week..

Chuck Norris' Fist. Count the knucle's.

Если вы не можете получить это, чтобы скомпилировать и запустить (например, поэзию), тогда читайте дальше.


Без операций регулярного выражения и минус 2 по модулю, также без проблем с високовом годом или объекта Date.
Хотя javascript Date object охватывает примерно 285616 лет (100 000 000 дней) по обе стороны от 1 января 1970 года, мне надоели все виды неожиданной даты несоответствия в разных браузерах (наиболее заметно от 0 до 99). Мне также было любопытно, как его вычислить.

Итак, я написал простой и, прежде всего, небольшой алгоритм (легко избивающий ответ Джеймса), чтобы вычислить правильный (Proleptic Gregorian/Astronomical/ISO 8601: 2004 (раздел 4.3.2.1), поэтому year 0 существует и является високосным годом, а отрицательные годы поддерживаются) количество дней для данного месяца и года.
Он использует алгоритм короткого замыкания с битовой маской - 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" placeholder="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>

Ответ 6

В компьютерных терминах решения new Date() и regular expression медленны! Если вы хотите супер-быстрый (и супер-критический) однострочный, попробуйте этот (при условии, что m находится в формате Jan=1 в соответствии с вопросом):

Единственная реальная конкуренция за скорость - от @GitaarLab, поэтому я создал JSPerf для головы для тестирования: http://jsperf.com/days-in-month-head-to-head/5

Я продолжаю пробовать разные изменения кода, чтобы получить лучшую производительность.

Текущая версия

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

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

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) почти во всех браузерах.


Предыдущие версии:

Это удалило один тест !, изменив значения (небольшое увеличение):

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

Это удалит любые ненужные скобки:

function getDaysInMonth2(m, y) {
    return m === 2 ? !(y % 4 || !(y % 100) && (y % 400)) ? 29 : 28 : 30 + (m + (m >> 3) & 1);
}

Это было меньше, чем +, что было чуть быстрее, чем XOR (^)

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

Это был мой оригинальный удар:

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

Он работает на основе моего високосного года здесь: 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 (в 23 раза быстрее, чем принятый ответ).


Обновление:. Я провел сравнение двух верхних ответов + последних (@James, @Caleb и @GitaarLAB) с этим, чтобы гарантировать, что они дали согласованные результаты, и все 4 возвращают одинаковые значения для все месяцы за все годы с года 1 до 4000: http://jsfiddle.net/TrueBlueAussie/8Lmpnpz4/6/. Год 0 одинаковый для всех, кроме @Caleb.

Другое обновление:

Если абсолютная скорость была единственной целью, и вы не против потерять память, то сохранение результатов за определенный промежуток лет в двумерной таблице, вероятно, является самым быстрым способом:

function DIM(m, y) { //TrueBlueAussie
    return m===2?(y%4||!(y%100)&&(y%400))?28:29:30+(m+(m>>3)&1);
}
array = new Array(4000);
for (var y = 1; y < 4000; y++){
    array[y] = [];
    for (var m = 1; m < 13; m++)
    {
        array[y][m] = DIM(m, y);
    }
}

// This just does a lookup into the primed table - wasteful, but fast
function getDaysInMonth2(m, y){
    return array[y][m];
}

JSPerf: http://jsperf.com/days-in-month-head-to-head/5

Ответ 7

В духе того, чтобы не делать домашнее задание для вас, я представляю версию в POVRay (извините, а не JS). Я сделал много лет назад.

В POVRay булевых переменных нет. Метод, который я придумал, заключался в создании полинома в 'm', который давал ответ > 0 в течение месяцев с 31 днями и < 0 в течение месяцев с 30 днями.

#declare m0 = (m-0.5)*(m-1.5)*(m-2.5)*(m-3.5)*(m-4.5)*(m-5.5);
#declare m0 = m0*(m-6.5)*(m-8.5)*(m-9.5)*(m-10.5)*(m-11.5);
#if (m0 > 0)
  #declare maxdays = 31;
#else
  #declare maxdays = 30;
#end

Сложная часть - решить, когда год високосный год. Это полный тест на високосные годы. Большинство людей знают о четырехлетнем правиле, а с 2000 года некоторые знают о правилах на 100 и 400 лет, там нет правила на 4000 лет.

#declare LEAPYEAR = 2.0;
#if (mod(YEAR,4.0)=0)
  #declare LEAPYEAR = 1.0;
  #if (mod(YEAR,100.0)=0)
    #declare LEAPYEAR = 2.0;
  #end
  #if (mod(YEAR,400.0)=0
    #declare LEAPYEAR = 1.0;
  #end
#end
#if (MONTH = 2.0)
  #declare maxdays = maxdays - LEAPYEAR;
#end
#if (DAY > maxdays)
  #declare MONTH = MONTH + 1;
  #declare DAY = DAY - maxdays;
#end
#if (MONTH > 12)
  #declare YEAR = YEAR + 1;
  #declare MONTH = MONTH - 12;
#end

Ответ 8

Ответ любимого Джеймса, а также объяснение Бруно. Однако раздражался чрезмерно загадочный характер решения. Итак, вот одно и то же решение, но очищено от ненужного шифрования.

function getDaysInMonth(m, y) {
   return /4|6|9|11/.test(m)?30:m==2?(!(y%4)&&y%100)||!(y%400)?29:28:31;
}

Особенности

  • Кажется, нет необходимости уменьшать месяц - javascript не имеет к этому никакого отношения, поскольку мы используем его только для сравнения, поэтому для ясности я использовал реальные номера месяца.

  • Зачем писать номер апрель, июнь, сентябрь и ноябрь? Это просто запутанным.

  • * По желанию мы можем увеличить месяц (++m), чтобы получить версию, которая принимает (new Date()).getMonth() как входной

Ответ 9

Я столкнулся с этим вопросом, играя с хобби-проектом C/С++/С# . Таким образом, хотя этот ответ может быть не уместным для OP, остальные ответы/комментарии, похоже, касаются JavaScript "гольф"; что немного черное искусство из-за капризов JS JIT, но, тем не менее, весело.

Стоя на плечах GitaarLAB, TrueBlueAussie и др., я предлагаю:

return m===2?y&3||!(y%25)&&y&15?28:29:30|(m+(m>>3));

Ответ 10

попробуйте следующее:

function DaysinMonth(aDate)  {
    return aDate.setMonth(aDate.getMonth()+1, 0).getDate();
}    

Ответ 11

Попробуйте следующее:

function daysInMonth(year, month) {
    var isLeap = ( (!(year % 4)) && ( (year % 100) || (!(year % 400)) ) );

    if (month == 2)
        return (isLeap) ? 29 : 28;
    return 30 + (month % 2);
}