2011-11-17 34 views
17

Come posso ottenere il codice qui sotto per funzionare quando ho un mese di febbraio? Attualmente sta arrivando al giorno e poi si ferma prima di arrivare al se per determinare se è un anno bisestile.javascript per trovare anno bisestile

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

"Arresto" come? C'è un errore? –

+0

non valuta mai l'anno per vedere se è un anno bisestile va dritto al field.focus e field.value se è un anno bisestile o no –

+0

Le tue condizioni sono un po 'strane - come sono attualmente scritte ora, si controlla solo 'giorno' per i valori di 29 o maggiori (in base alle clausole' day == 29' e 'day> 28' if). Suppongo che tu intendessi scrivere 'day <= 28', ma se questo è il caso, potresti rilasciare la seconda clausola' else if' e usare direttamente una clausola 'else'. Potrebbe anche essere più sicuro aggiungere un'ulteriore serie di parentesi alla clausola bisestile: 'if (year% 4! = 0 || (year% 100 == 0 && year% 400! = 0))' – JW8

risposta

99

E 'più sicuro di utilizzare Date objects per le cose di datetime, ad esempio,

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

Dal momento che la gente continua a chiedere su come esattamente funziona, ha a che fare con il modo in JS calcola il valore di data di anno-mese-giorno (dettagli here). Fondamentalmente, prima calcola il primo del mese e poi aggiunge N -1 giorni ad esso. Così, quando stiamo chiedendo per il 29 febbraio in un anno non bisestile, il risultato sarà il 1 febbraio + 28 giorni = 1 ° marzo:

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

Su un anno bisestile, il 1 ° + 28 = 29 febbraio :

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

Nel codice di cui sopra, ho impostato la data al 29 febbraio e se un roll-over ha avuto luogo. In caso contrario (il mese è ancora 1, cioè febbraio), questo è un anno bisestile, altrimenti uno non bisestile.

+14

Mucca santa. Che hack. ':' –

+1

** Demo live: ** http://jsfiddle.net/bJ4cH/ –

+0

hack molto grande! –

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

... la sottrazione di uno dovrebbe funzionare anche più velocemente rispetto alla maggior parte delle architetture CPU.

+0

Se dovessi calcolare 1000 di questi al secondo, potrei essere d'accordo, tuttavia la leggibilità dovrebbe aumentare rapidamente quando la differenza di velocità in questione è virtualmente trascurabile. –

+0

Ho appena eseguito alcuni test di velocità e 'new Date' è circa 100 volte più lento rispetto all'utilizzo della logica booleana (dì qualcosa come'! ((Yr% 4) || (! (Yr% 100) && (yr% 400))) ').Si potrebbe dire che ora ho gettato la leggibilità fuori dalla finestra con questo per motivi di velocità, ma 100 volte può valerne la pena :) –

6

corretto e veloce:

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

Se ci si trova in un loop o contare i nanosecondi, questo è due grandezze più veloce di gestire l'anno attraverso un new Date() dell'oggetto. Confronta le prestazioni qui: http://jsperf.com/ily

+2

Poiché si tratta solo di combinare valori booleani con risultati booleani, è possibile esprimere questo senza gli operatori condizionali ma just && 's, ||' s e cortocircuito. Anche circa il 5% più veloce: http://jsperf.com/ily/6 –

1

Io uso questo perché odio dover continuare a riferirsi a gennaio come 0 e febbraio come 1. Per me e PHP e date leggibili, febbraio = 2. So che non importa in quanto il numero non cambia mai, ma mantiene semplicemente il mio cervello a pensare lo stesso attraverso un codice diverso.

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

Rispetto all'utilizzo new Date() questo è è di circa 100 volte più veloce!

Aggiornamento:

Questa ultima versione utilizza un test po 'dei 3 bit di fondo (è un multiplo di 4), nonché un assegno per l'anno di essere un multiplo di 16 (in basso a 4 bit in binario è 15) e di essere un multiplo di 25.

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

http://jsperf.com/ily/15

e 'leggermente più veloce di nuovo rispetto al mio precedente versione (qui di seguito):

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

http://jsperf.com/ily/7

E 'anche 5% più veloce rispetto alla versione all'operatore già veloce condizionale da Broc.SEIB

velocità I risultati dei test: http://jsperf.com/ily/6

attesi i risultati dei test di logica:

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

Meglio calcolo storica degli anni bisestili.

Il codice seguente tiene conto che gli anni bisestili sono stati introdotti nel 45BC con il calendario giuliano e che la maggior parte del mondo occidentale ha adottato il calendario gregoriano nel 1582 e quello 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; 
}; 

la Gran Bretagna e le sue colonie hanno adottato il calendario gregoriano nel 1752, quindi se siete più anglo centric questa versione è migliore (Si suppone la Gran Bretagna ha adottato il calendario giuliano con la conquista romana a partire dal 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); 

questo può aiutare a ottenere se l'anno di ingresso è un anno bisestile o meno.

in forma di true o false

JavaScript Basics w3resource

1

Si può facilmente fare questo lavoro chiamando .isLeapYear() da 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>