javascript, чтобы найти високосный год

Как заставить работать приведенный ниже код, когда у меня февраль? В настоящее время он приближается к текущему дню, а затем останавливается, прежде чем перейти к условию «если», чтобы определить, високосный ли год.

 if (month == 2) {
    if (day == 29) {
        if (year % 4 != 0 || year % 100 == 0 && year % 400 != 0) {
            field.focus();
             field.value = month +'/' +  '';
        }
    }
    else if (day > 28) {
        field.focus();
             field.value = month +'/' +  '';
    }
}

person Juan Almonte    schedule 17.11.2011    source источник
comment
Как остановить? Есть ошибка?   -  person Pekka    schedule 18.11.2011
comment
он никогда не оценивает год, чтобы увидеть, является ли он високосным, он переходит прямо к field.focus и field.value, является ли он високосным годом или нет   -  person Juan Almonte    schedule 18.11.2011
comment
Ваши условия выглядят немного странно - поскольку они написаны сейчас, вы проверяете только day на значения 29 или больше (на основе предложений day == 29 и day > 28 if). Я предполагаю, что вы хотели написать day <= 28, но в этом случае вы можете отказаться от второго предложения else if и напрямую использовать предложение else. Также может быть безопаснее добавить дополнительный набор скобок в предложение о високосном году: if (year % 4 != 0 || (year % 100 == 0 && year % 400 != 0))   -  person JW8    schedule 18.11.2011
comment
Возможно, вам потребуется показать некоторый окружающий код, показывающий, как устанавливаются эти переменные. Если вы вообще используете объект Date, помните, что он использует месяцы с отсчетом от нуля.   -  person nnnnnn    schedule 18.11.2011


Ответы (12)


Безопаснее использовать объекты даты для материала datetime, например

isLeap = new Date(year, 1, 29).getMonth() == 1

Поскольку люди продолжают спрашивать, как именно это работает, это связано с тем, как JS вычисляет значение даты из года, месяца и дня (подробности здесь). По сути, он сначала вычисляет первое число месяца, а затем добавляет к нему N -1 дней. Поэтому, когда мы запрашиваем 29 февраля невисокосного года, результатом будет 1 февраля + 28 дней = 1 марта:

> new Date(2015, 1, 29)
< Sun Mar 01 2015 00:00:00 GMT+0100 (CET)

В високосный год 1 + 28 = 29 февраля:

> new Date(2016, 1, 29)
< Mon Feb 29 2016 00:00:00 GMT+0100 (CET)

В приведенном выше коде я установил дату 29 февраля и посмотрел, произошел ли перенос. Если нет (месяц по-прежнему 1, т.е. февраль), это високосный год, в противном случае - невисокосный.

person georg    schedule 17.11.2011

По сравнению с new Date() это примерно в 100 раз быстрее!

Обновление:

В этой последней версии используется битовый тест нижних 3 бит (кратно ли 4), а также проверка того, что год кратен 16 (нижние 4 бита в двоичном формате равен 15) и кратен 25.

ily = function(y) {return !(y & 3 || !(y % 25) && y & 15);};

http://jsperf.com/ily/15

Это снова немного быстрее, чем моя предыдущая версия (ниже):

ily = function(yr) {return !((yr % 4) || (!(yr % 100) && (yr % 400)));};

http://jsperf.com/ily/7

Это также на 5% быстрее по сравнению с и без того быстрой версией условного оператора от broc.seib

Результаты теста скорости: http://jsperf.com/ily/6

Ожидаемые результаты логического теста:

alert(ily(1900)); // false
alert(ily(2000)); // true
alert(ily(2001)); // false
alert(ily(2002)); // false
alert(ily(2003)); // false
alert(ily(2004)); // true
alert(ily(2100)); // false
alert(ily(2400)); // true
person Gone Coding    schedule 24.10.2013

isLeap = !(new Date(year, 1, 29).getMonth()-1)

... вычитание на единицу должно работать даже быстрее, чем сравнение на большинстве архитектур ЦП.

person bofs    schedule 01.04.2013
comment
Если бы вам потребовалось вычислять 1000 из них в секунду, я мог бы согласиться, однако удобочитаемость должна превосходить скорость, когда соответствующая разница в скорости между ними практически незначительна. - person Gone Coding; 24.10.2013
comment
Просто провел несколько тестов скорости, и new Date примерно в 100 раз медленнее, чем при использовании логической логики (скажем, что-то вроде !((yr % 4) || (!(yr % 100) && (yr % 400)))). Вы могли бы сказать, что теперь я выбросил читабельность с этим ради скорости, но 100 раз, возможно, того стоит :) - person Gone Coding; 24.10.2013

Правильно и быстро:

ily = function(yr) { return (yr%400)?((yr%100)?((yr%4)?false:true):false):true; }

Если вы находитесь в цикле или подсчитываете наносекунды, это на две величины быстрее, чем прохождение вашего года через новый объект Date (). Сравните производительность здесь: http://jsperf.com/ily

person broc.seib    schedule 14.06.2013
comment
Поскольку это просто комбинирование логических сравнений с логическими результатами, вы можете выразить это без условных операторов, а только с &&, || и коротким замыканием. Также примерно на 5% быстрее: jsperf.com/ily/6 - person Gone Coding; 24.10.2013
comment
Вы уже знаете, что такое отрицание? - person Frondor; 23.07.2018

Лучшее историческое вычисление високосных лет.

В приведенном ниже коде учтено, что високосные годы были введены в 45 г. до н.э. по юлианскому календарю, и что большая часть западного мира приняла григорианский календарь в 1582 г. до н.э., и что 0CE = 1 г. до н.э.

isLeap = function(yr) {
  if (yr > 1582) return !((yr % 4) || (!(yr % 100) && (yr % 400)));
  if (yr >= 0) return !(yr % 4);
  if (yr >= -45) return !((yr + 1) % 4);
  return false;
};

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

isLeap = function(yr) {
  if (yr > 1752) return !((yr % 4) || (!(yr % 100) && (yr % 400)));
  if (yr >= 43) return !(yr % 4);
  return false;
};
person spirographer    schedule 02.10.2015
comment
+ за уроки истории. Теперь вопрос: разве високосные годы не вводились с обратной силой? - person inetphantom; 23.08.2018

Я использую это, потому что ненавижу постоянно называть январь 0, а февраль - 1. Для меня, PHP и удобочитаемых дат февраль = 2. Я знаю, что на самом деле это не имеет значения, поскольку число никогда не меняется, но оно просто заставляет мой мозг думать одинаково для разных кодов.

var year = 2012;
var isLeap = new Date(year,2,1,-1).getDate()==29;
person Adam    schedule 09.08.2013

Вы можете легко заставить это работать, позвонив .isLeapYear() из _ 2_:

var notLeapYear = moment('2018-02-29')
console.log(notLeapYear.isLeapYear()); // false

var leapYear = moment('2020-02-29')
console.log(leapYear.isLeapYear()); // true
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.21.0/moment.min.js"></script>

person guijob    schedule 06.03.2018

все в одной строке ????

const isLeapYear = (year) => (year % 100 === 0 ? year % 400 === 0 : year % 4 === 0);

console.log(isLeapYear(2016)); // true
console.log(isLeapYear(2000)); // true
console.log(isLeapYear(1700)); // false
console.log(isLeapYear(1800)); // false
console.log(isLeapYear(2020)); // true
person Durdona A.    schedule 05.07.2020

Псевдокод

if year is not divisible by 4 then not leap year
else if year is not divisible by 100 then leap year
else if year is divisible by 400 then leap year
else not leap year

JavaScript

function isLeapYear (year) {
    return year % 4 == 0 && ( year % 100 != 0 || year % 400 == 0 )
}

Использование приведенного выше кода гарантирует, что вы выполняете только одну проверку на year, если year не делится на 4 Просто добавляя скобки, вы сохраняете 2 проверки на year, которые не делятся на 4

person Daut    schedule 04.02.2019

Другой вариант - проверить, есть ли в этом году дата 29 февраля. Если на нем есть эта дата, значит, это високосный год.

ES6

// Months are zero-based integers between 0 and 11, where Febuary = 1
const isLeapYear = year => new Date(year, 1, 29).getDate() === 29;

Тесты

> isLeapYear(2016);
< true
> isLeapYear(2019);
< false
person Robert Todar    schedule 04.09.2019

Ожидается, что JavaScript получит новый API даты / времени, который предоставляет новый глобальный объект - Temporal . Этот глобальный объект предоставляет разработчикам JS более удобный способ работы с датами и временем. В настоящее время это предложение этапа 3, и мы надеемся, что вскоре оно будет доступно для использования.

Временной API предоставляет удобное свойство для проверки високосных лет - inLeapYear . Это возвращает true, если конкретная дата - високосный год, иначе false. Ниже мы используем with() для преобразования даты, возвращаемой plainDateISO, в один с нашим конкретным годом:

const isLeap = year => Temporal.now.plainDateISO().with({year}).inLeapYear;
console.log(isLeap(2020)); // true
console.log(isLeap(2000)); // true
console.log(isLeap(1944)); // true

console.log(isLeap(2021)); // false
console.log(isLeap(1999)); // false

Если вы просто хотите проверить, является ли текущая системная дата високосным годом, вы можете опустить .with():

// true if this year is a leap year, false if it's not a leap year
const isLeap = Temporal.now.plainDateISO().inLeapYear; 
person Nick Parsons    schedule 25.06.2021

person    schedule
comment
Хотя этот код может ответить на вопрос, предоставление дополнительного контекста относительно того, как и / или почему он решает проблему, улучшит долгосрочную ценность ответа. - person Carol-Theodor Pelu; 19.01.2021