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

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

 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 +'/' +  '';
    }
}

Ответ 1

Безопаснее использовать Объекты Date для данных 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)

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

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

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

Ответ 2

По сравнению с использованием 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

Ответ 3

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

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

Ответ 4

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

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

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

Ответ 5

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

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

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;
};

Ответ 6

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

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

Ответ 7

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

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>

Ответ 8

Псевдокод

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

Ответ 9

Другой вариант - узнать, есть ли в этом году дата 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