К счастью, этот вопрос не определяет, требуется ли номер текущего дня, оставляя место для этого ответа.
Также у некоторых ответов (также на другие вопросы) были проблемы високосного года илииспользовал объект Date.Хотя javascript Date object
охватывает примерно 285616 лет (100 000 000 дней) по обе стороны от 1 января 1970 года, я был сыт по горло всевозможными неожиданными несоответствиями в разных браузерах (особенно в год 0–99).Мне также было любопытно, как его вычислить.
Поэтому я написал простой и, прежде всего, маленький алгоритм для вычисления правильного ( Proleptic Григорианский / Астрономический / ISO 8601: 2004 (пункт 4.3.2.1), поэтому год 0
существует и является високосным годом и поддерживается отрицательных лет )день года на основе год , месяц и день .
Обратите внимание, что в обозначениях AD/BC
год 0 нашей эры / BC не существует:вместо этого год 1 BC
является високосным годом!ЕСЛИ вам нужно учесть нотацию BC, то просто сначала вычтите один год из (в противном случае положительного) значения года !!
Я изменил (для javascript) алгоритм short-circuit bitmask-modulo leapYear и придумал магическое число, чтобы выполнить побитовый поиск смещений (который исключает jan и feb, поэтому требуется 10 * 3 бита (30 бит меньше 31 бита, поэтому мы можем безопасносохраните другой символ в битах вместо >>>
)).
Обратите внимание, что ни месяц, ни день не могут быть 0
.Это означает, что если вам нужно это уравнение только для текущего дня (используя его .getMonth()
), вам просто нужно удалить --
из --m
.
Обратите внимание, это предполагаетдействительная дата (хотя проверка ошибок - это всего лишь несколько символов).
function dayNo(y,m,d){
return --m*31-(m>1?(1054267675>>m*3-6&7)-(y&3||!(y%25)&&y&15?0:1):0)+d;
}
<!-- some examples for the snippet -->
<input type=text value="(-)Y-M-D" onblur="
var d=this.value.match(/(-?\d+)[^\d]+(\d\d?)[^\d]+(\d\d?)/)||[];
this.nextSibling.innerHTML=' Day: ' + dayNo(+d[1], +d[2], +d[3]);
" /><span></span>
<br><hr><br>
<button onclick="
var d=new Date();
this.nextSibling.innerHTML=dayNo(d.getFullYear(), d.getMonth()+1, d.getDate()) + ' Day(s)';
">get current dayno:</button><span></span>
Это версия с правильной проверкой диапазона.
function dayNo(y,m,d){
return --m>=0 && m<12 && d>0 && d<29+(
4*(y=y&3||!(y%25)&&y&15?0:1)+15662003>>m*2&3
) && m*31-(m>1?(1054267675>>m*3-6&7)-y:0)+d;
}
<!-- some examples for the snippet -->
<input type=text value="(-)Y-M-D" onblur="
var d=this.value.match(/(-?\d+)[^\d]+(\d\d?)[^\d]+(\d\d?)/)||[];
this.nextSibling.innerHTML=' Day: ' + dayNo(+d[1], +d[2], +d[3]);
" /><span></span>
Снова одна строка, но я разбил ее на 3 строки для удобства чтения (и последующего объяснения).
Последняя строка идентична функции, описанной выше, однако (идентичный) алгоритм leapYear перемещен в предыдущую секцию короткого замыкания (до вычисления числа дня), поскольку также необходимо знать, сколькодней в месяце в данном (високосном) году.
Средняя линия вычисляет правильное смещение число (для максимального количества дней) для данного месяца в данном (високосном) году, используя другое магическое число: с 31-28=3
и 3
это всего 2 бита, затем 12*2=24
бит, мы можем хранить все 12 месяцев.Поскольку сложение может быть быстрее, чем вычитание, мы добавляем смещение (вместо того, чтобы вычитать его из 31
).Чтобы избежать принятия решения о високосном году в феврале, мы изменяем этот волшебный номер поиска на лету.
Это оставляет нам (довольно очевидную) первую строку: он проверяет, что месяц и дата находятся в допустимых пределах.ограничивает и гарантирует нам возвращаемое значение false
при ошибке диапазона (обратите внимание, что эта функция также не должна иметь возможность возвращать 0, поскольку 1 января 0000 все еще день 1.), обеспечивая простую проверку ошибок: if(r=dayNo(/*y, m, d*/)){}
.
Если использовать этот способ (где месяц и день не могут быть 0
), то можно изменить --m>=0 && m<12
на m>0 && --m<12
(сохранение другого символа).
Причина, по которой я набралФрагмент в его текущем виде таков, что для значений месяца на основе 0 нужно просто удалить --
из --m
.
Extra:
Примечание. Не используйте алгоритм дня за месяцесли вам нужен только максимальный день в месяц.В этом случае есть более эффективный алгоритм (потому что нам нужен только leepYear, когда месяц февраль). Я написал в ответ на этот вопрос: Как лучше всего определить количество дней в месяце с помощью javascript? .