Как я могу написать функцию 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
Тридцать дней в сентябре,
Апрель, Июнь и Ноябрь,
Все остальные тридцать один,
Только за февраль,
Который имеет двадцать восемь дней ясно,
И двадцать девять в каждый високосный год.
Ответ 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..
Если вы не можете получить это, чтобы скомпилировать и запустить (например, поэзию), тогда читайте дальше.
Без операций регулярного выражения и минус 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];
}
Ответ 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);
}