2011-11-17 43 views
17

Jak mogę uzyskać poniższy kod do pracy, gdy mam miesiąc lutego? Obecnie dochodzi do dnia, a następnie zatrzymuje się przed dotarciem do niego, czy w celu ustalenia, czy jest to rok przestępny.javascript znaleźć rok przestępny

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

"Zatrzymanie" jak? Czy wystąpił błąd? –

+0

nigdy nie ocenia roku, aby sprawdzić, czy jest rokiem przestępnym, przechodzi bezpośrednio do field.focus i field.value, czy jest rokiem przestępnym czy nie. –

+0

Twoje warunki wyglądają trochę dziwnie - tak jak są obecnie napisane, sprawdzasz tylko "dzień" dla wartości 29 lub wyższych (w oparciu o klauzule "day == 29" i "day> 28"). Zakładam, że chciałeś napisać 'dzień <= 28', ale jeśli tak jest, możesz odrzucić drugą klauzulę" else if "i bezpośrednio użyć klauzuli" else ". Może być również bezpieczniej dodać dodatkowy zestaw nawiasów do twojej klauzuli "rok przestępny": 'if (year% 4! = 0 || (year% 100 == 0 && year% 400! = 0))' – JW8

Odpowiedz

99

Bezpieczniejsze jest używanie Date objects do przechowywania danych, np.

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

Ponieważ ludzie pytają o tym, jak dokładnie to działa, że ​​ma do czynienia z tym, jak JS oblicza wartość daty z rok-miesiąc-dzień (szczegóły here). Zasadniczo najpierw oblicza pierwszy miesiąc, a następnie dodaje N -1 dni. Więc kiedy pytamy o 29 lutego w roku przestępnym nie, wynik będzie 01 lutego + 28 dni = 1-ci Marzec:

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

na rok przestępny, 1. + 28 = 29 lutego :

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

W powyższym kodzie ustawiłem datę na 29 lutego i sprawdzam, czy nastąpiło przewrócenie. Jeśli nie (miesiąc to nadal 1, to jest luty), jest to rok przestępny, w przeciwnym razie nie jest to skok.

+14

Święta krowa. Co za hack. ':)' –

+1

** Demo na żywo: ** http://jsfiddle.net/bJ4cH/ –

+0

bardzo dobry hack! –

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

... odejmowanie o jeden powinno działać jeszcze szybciej niż porównanie na większości architektur procesorów.

+0

Jeśli byłbyś zobowiązany do obliczenia 1000 sekund na sekundę, to mógłbym się zgodzić, jednak czytelność powinna przyspieszyć, gdy różnica prędkości jest praktycznie pomijalna między nimi. –

+0

Po prostu uruchomiłem kilka testów prędkości i 'nowa data' jest około 100 razy wolniejsza niż przy użyciu logiki boolowskiej (powiedz coś w stylu'! ((Yr% 4) || (! (Yr% 100) && (yr% 400)))).Możesz powiedzieć, że teraz wyrzuciłem czytelność przez okno dla tego ze względu na szybkość, ale 100 razy może być tego warte :) –

6

prawidłową i szybką:

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

Jeśli jesteś w pętli lub licząc nanosekund, to dwie wielkości szybciej niż prowadzenie roku przez nową datę() obiektu. Porównaj wydajność tutaj: http://jsperf.com/ily

+2

Ponieważ jest to po prostu łączenie wartości boolowskiej z wynikami boolowskimi, możesz wyrazić to bez operatorów warunkowych, ale just && 's, ||' s i zwarcie. Również około 5% szybciej: http://jsperf.com/ily/6 –

1

Używam tego, ponieważ nienawidzę ciągłego powoływania się na styczeń jako 0 i luty jako 1. Dla mnie i PHP oraz czytelne daty, luty = 2. Wiem, że to nie ma znaczenia, ponieważ liczba nigdy się nie zmienia, ale po prostu sprawia, że ​​mój mózg myśli tak samo w różnych kodach.

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

porównaniu z korzystaniem new Date() to jest około 100 razy szybciej!

Aktualizacja:

Ta najnowsza wersja używa BTST dna 3 bitów (jest wielokrotnością 4), a także czek na rok będącej wielokrotnością 16 (na dole 4 bity w binarnym jest 15) i jest wielokrotnością 25.

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

http://jsperf.com/ily/15

jest nieco szybciej niż mój znowu poprzedniej wersji (poniżej):

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

http://jsperf.com/ily/7

Jest również 5% szybciej w porównaniu do już szybko warunkowej wersji operatora przez Broc.Seib

prędkości Wyniki badań: http://jsperf.com/ily/6

oczekiwanymi wynikami testów logicznych:

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 
0

Lepsze historyczny obliczeniowe lat przestępnych.

Poniższy kod bierze pod uwagę, że lata przestępne zostały wprowadzone w 45BC z kalendarzem juliańskim, i że większość świata zachodniego przyjęła kalendarz gregoriański w 1582 r. I że 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; 
}; 

Brytania i jej kolonie przyjęła kalendarz gregoriański w 1752 roku, więc jeśli jesteś bardziej Anglo centric ta wersja jest lepsza (Będziemy zakładać Brytania przyjęła kalendarza juliańskiego z rzymskiego podboju począwszy od 43CE).

isLeap = function(yr) { 
    if (yr > 1752) return !((yr % 4) || (!(yr % 100) && (yr % 400))); 
    if (yr >= 43) return !(yr % 4); 
    return false; 
}; 
0
year = window.prompt("Input a Year : "); 
x = (year % 100 === 0) ? (year % 400 === 0) : (year % 4 === 0); 
console.log(x); 

to może pomóc uzyskać, jeśli wejście rok jest rokiem przestępnym czy nie.

w postaci true lub false

JavaScript Basics w3resource

1

Można to łatwo zrobić, aby pracować nazywając .isLeapYear() z 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>