Javascript calcola il giorno dell'anno (1 - 366)


119

Come si usa javascript per calcolare il giorno dell'anno, da 1 a 366? Per esempio:

  • Il 3 gennaio dovrebbe essere il 3 .
  • Il 1 febbraio dovrebbe essere 32 .

4
var days = new Date().getFullYear() % 4 == 0 ? 366 : 365;
Alex Turpin

Ma davvero non sono sicuro di cosa intendi. Vuoi solo il numero di giorni dell'anno? O tra due date?
Alex Turpin

16
fyi @ xeon06, il calcolo dell'anno bisestile è un po 'più complicato della modifica di 4. vedi: algoritmo anno bisestile
Matt Felzani

4
@ Xeon06: è corretto solo la maggior parte delle volte. Da Wikipedia : gli anni divisibili per 100 non sono anni bisestili, a meno che non siano anche divisibili per 400, nel qual caso sono anni bisestili.
Cameron

Ah beh mi correggo. @minitech sembra quindi avere la risposta giusta.
Alex Turpin

Risposte:


138

A seguito della modifica dell'OP:

var now = new Date();
var start = new Date(now.getFullYear(), 0, 0);
var diff = now - start;
var oneDay = 1000 * 60 * 60 * 24;
var day = Math.floor(diff / oneDay);
console.log('Day of year: ' + day);

Modifica: il codice precedente non funzionerà quando nowè una data compresa tra il 26 marzo e il 29 ottobre e nowl'ora è prima dell'01: 00 (ad esempio 00:59:59). Ciò è dovuto al fatto che il codice non tiene conto dell'ora legale. Dovresti compensare questo:

var now = new Date();
var start = new Date(now.getFullYear(), 0, 0);
var diff = (now - start) + ((start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000);
var oneDay = 1000 * 60 * 60 * 24;
var day = Math.floor(diff / oneDay);
console.log('Day of year: ' + day);


5
Math.floorcostantemente mi ha dato un risultato di 1 giorno in meno del previsto dopo un certo giorno di aprile. Math.ceilha funzionato come previsto, ma ho visto che è consigliabile utilizzare al Math.roundposto di entrambi.
Baacke

3
La componente giorno è base 1. cioè per rappresentare il 1 ° gennaio di quest'anno, useresti new Date(2014, 0, 1), e non new Date(2014, 0, 0)come hai qui. È intenzionale? Forse questo è ciò che spiega l'essere fuori un giorno come new Date(2014, 0, 0)tornerà 12/31/2013.
Kirk Woll

1
Forse utilizzare .setUTCHourse Date.UTC()per una soluzione più affidabile.
Noyo

6
@AlexTurpin, @ T30: So che è un po 'vecchio, ma se ti stavi chiedendo ... il problema è causato dall'ora legale che inizia a marzo. Questo perché quando prendi la differenza tra la mezzanotte di una data prima dell'ora legale e la mezzanotte di una data dopo l'ora legale non avrai un numero di millisecondi uniformemente divisibile per 1000 * 60 * 60 * 24 (sarà esattamente un'ora di pausa) . La soluzione più semplice è usare ceilpiuttosto che floor, questo ti darà un sistema di numerazione in cui Jan 1st = 1. Se vuoi Jan 1st = 0 (come floorti darebbe), sottrai 1 dal tuo risultato finale.
Warren R.

2
Per tenere conto dei fusi orari e dell'ora legale, cambia la linea 3 con: var diff = now - start + (start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000;
Marlon

46

Funziona con i cambiamenti dell'ora legale in tutti i paesi (il "mezzogiorno" sopra non funziona in Australia):

Date.prototype.isLeapYear = function() {
    var year = this.getFullYear();
    if((year & 3) != 0) return false;
    return ((year % 100) != 0 || (year % 400) == 0);
};

// Get Day of Year
Date.prototype.getDOY = function() {
    var dayCount = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
    var mn = this.getMonth();
    var dn = this.getDate();
    var dayOfYear = dayCount[mn] + dn;
    if(mn > 1 && this.isLeapYear()) dayOfYear++;
    return dayOfYear;
};

1
D'accordo che ci sono bug relativi all'ora legale nella risposta accettata. La soluzione di cui sopra è migliore ed è più veloce. Ecco una variazione che ho testato su jsPerf jsperf.com/date-getdayofyear-perf
Shyam Habarakada

@ShyamHabarakada: il codice nel tuo benchmark è rotto, getDay()deve essere cambiato in getDate(). Il primo restituisce il giorno della settimana (0 = domenica..6 = sabato), non il giorno.
CodeManX

32

Trovo molto interessante che nessuno abbia preso in considerazione l'utilizzo di UTC poiché non è soggetto a DST. Pertanto, propongo quanto segue:

function daysIntoYear(date){
    return (Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()) - Date.UTC(date.getFullYear(), 0, 0)) / 24 / 60 / 60 / 1000;
}

Puoi testarlo con quanto segue:

[new Date(2016,0,1), new Date(2016,1,1), new Date(2016,2,1), new Date(2016,5,1), new Date(2016,11,31)]
    .forEach(d => 
        console.log(`${d.toLocaleDateString()} is ${daysIntoYear(d)} days into the year`));

Quali uscite per l'anno bisestile 2016 (verificate utilizzando http://www.epochconverter.com/days/2016 ):

1/1/2016 is 1 days into the year
2/1/2016 is 32 days into the year
3/1/2016 is 61 days into the year
6/1/2016 is 153 days into the year
12/31/2016 is 366 days into the year

Questo potrebbe traboccare perché il numero di millisecondi è troppo grande.
knt5784

@ knt5784 La matematica potrebbe essere in grado di traboccare, ma il suo esempio mostra che il valore reale più grande possibile funziona bene, quindi dovresti essere a posto usando questo a meno che non ci sia un problema basato sul browser con overflow di numeri interi.
Per Fagrell

Personalmente mi piace questo approccio. Modo molto più pulito (e molto intelligente!) Per evitare problemi con l'ora legale. Se qualcuno si sta chiedendo come convertire da DOY fino ad oggi, è molto più semplice. Fondamentalmente, devi solo creare una data di gennaio DOYth. Ad esempio, 59 gennaio === 28 febbraio. Il giorno bisestile viene gestito correttamente. function doyToDate(doy, year) { return new Date(year, 0, doy); }
Kip

@ knt5784 Non c'è rischio di overflow di millisecondi con questo codice, almeno non per altri 200.000 anni. La data più grande supportata da Date è new Date(8640000000000000), che è ancora inferiore a Number.MAX_SAFE_INTEGER. vedi questa risposta: stackoverflow.com/a/11526569/18511
Kip

18
Date.prototype.dayOfYear= function(){
    var j1= new Date(this);
    j1.setMonth(0, 0);
    return Math.round((this-j1)/8.64e7);
}

alert(new Date().dayOfYear())

3
Questo non passerebbe lint ... Modificare un oggetto che non è tuo, specialmente uno globale. Ciò fallirebbe anche nei pianeti con un'inclinazione estrema in cui l'ora legale supera le 12 ore. Ma più realisticamente, se stai codificando per un browser che consente di modificare il fuso orario dell'oggetto Date, il fuso orario di j1 potrebbe essere l'Australia e questo fuso orario potrebbe essere l'Alaska, interrompendo l'arrotondamento.
Ray Foss

11

Per fortuna questa domanda non specifica se è richiesto il numero del giorno corrente , lasciando spazio a questa risposta.
Anche alcune risposte (anche su altre domande) avevano problemi di anno bisestile o utilizzavano l'oggetto Date. Sebbene javascript Date objectcopra circa 285616 anni (100.000.000 giorni) su entrambi i lati del 1 gennaio 1970, ero stufo di tutti i tipi di incongruenze di date inaspettate tra browser diversi (in particolare dall'anno 0 a 99). Ero anche curioso di sapere come calcolarlo.

Quindi ho scritto un semplice e soprattutto piccolo algoritmo per calcolare il giorno dell'anno corretto ( Proleptic Gregorian / Astronomical / ISO 8601: 2004 (clausola 4.3.2.1), quindi l' anno0 esiste ed è un anno bisestile e gli anni negativi sono supportati ) giorno dell'anno basato su anno , mese e giorno .
Notare che in AD/BCnotazione, l'anno 0 d.C. / BC non esiste: invece l'anno 1 BCè l'anno bisestile! SE è necessario tenere conto della notazione BC, sottrarre prima un anno dal valore dell'anno (altrimenti positivo) !!

Ho modificato (per javascript) l' algoritmo bitmask-modulo leapYear di cortocircuito e ho creato un numero magico per eseguire una ricerca un po 'saggia degli offset (che esclude jan e feb, quindi necessitano di 10 * 3 bit (30 bit è inferiore a 31 bit, quindi possiamo salvare in sicurezza un altro carattere su bitshift invece di >>>)).

Nota che né il mese né il giorno possono esserlo 0. Ciò significa che se hai bisogno di questa equazione solo per il giorno corrente (alimentandola usando .getMonth()) devi solo rimuovere --da --m.

Nota che questo presuppone una data valida (sebbene il controllo degli errori sia solo qualche carattere in più).

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>


Ecco la versione con la corretta convalida dell'intervallo.

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>

Di nuovo, una riga, ma l'ho divisa in 3 righe per leggibilità (e spiegazione successiva).

L'ultima riga è identica alla funzione sopra, tuttavia l'algoritmo leapYear (identico) viene spostato in una sezione di cortocircuito precedente (prima del calcolo del numero di giorni), perché è anche necessario sapere quanti giorni ha un mese in un dato (bisestile) anno.

La linea centrale calcola il numero di offset corretto (per il numero massimo di giorni) per un dato mese in un dato anno (bisestile) utilizzando un altro numero magico: poiché 31-28=3e 3è solo 2 bit, quindi 12*2=24bit, possiamo memorizzare tutti i 12 mesi. Poiché l'addizione può essere più veloce della sottrazione, aggiungiamo l'offset (invece di sottrarlo da 31). Per evitare un ramo decisionale di un anno bisestile per febbraio, modifichiamo quel numero magico di ricerca al volo.

Questo ci lascia con la prima riga (abbastanza ovvia): controlla che il mese e la data siano entro limiti validi e ci garantisce un falsevalore di ritorno sull'errore di intervallo (nota che anche questa funzione non dovrebbe essere in grado di restituire 0, perché 1 gen 0000 è ancora giorno 1.), che fornisce un facile controllo degli errori: if(r=dayNo(/*y, m, d*/)){}.
Se utilizzato in questo modo (dove mese e giorno potrebbero non essere 0), è possibile passare --m>=0 && m<12a m>0 && --m<12(salvando un altro carattere).
Il motivo per cui ho digitato lo snippet nella sua forma attuale è che per i valori del mese basati su 0, è sufficiente rimuovere il file --da --m.

Extra:
Nota, non utilizzare l'algoritmo di questo giorno al mese se hai bisogno solo del numero massimo di giorni al mese. In quel caso c'è un algoritmo più efficiente (perché abbiamo solo bisogno di leepYear quando il mese è febbraio) Ho postato come risposta a questa domanda: Qual è il modo migliore per determinare il numero di giorni in un mese con javascript? .


1
L'ho inserito in una funzione data per facilità d'uso. Le incongruenze date () sono ancora un problema, ma sto usando gli anni 2015+, quindi spero che siano coerenti. Il povero JSHint è morto cercando di convalidare il tuo codice hahah. Date.prototype.dayNo = function(){ var y = this.getFullYear(); var m = this.getMonth()+1; var d = this.getDate(); return --m*31-(m>1?(1054267675>>m*3-6&7)-(y&3||!(y%25)&&y&15?0:1):0)+d; };
freshvolk

Lieto che ti sia piaciuto. Questo algoritmo è completamente testato per 2 ^ 31-1 anni (un enorme 2147483647, che è> 7500 volte l'intervallo dell'oggetto data di javascript) su entrambi i lati di 0. ( Potrebbe funzionare per 2 ^ 32, ma non l'ho testato ancora). Inoltre, potresti leggere di nuovo la mia risposta: puoi raderti +1da this.getMonth()+1se rimuovi --da --m. EDIT Quindi, farei (per una libreria):Date.prototype.dayNo = function(){ var y=this.getFullYear(), m=this.getMonth(); return m*31-(m>1?(1054267675>>m*3-6&7)-(y&3||!(y%25)&&y&15?0:1):0)+this.getDate(); };
GitaarLAB

In realtà l'ho fatto solo mentre lo stavo guardando! Mi sono reso conto che ne stavo aggiungendo uno e poi lo sottraevo immediatamente. Penso che quando arriveremo ad 2^31 - 2016anni da adesso, probabilmente sarà un po 'obsoleto.
freshvolk

@Freshvolk: lol, motivo per cui non l'ho mai testato oltre 2 ^ 31 :)Ma fino ad allora, fornirà almeno risultati prevedibili e coerenti ahah. EDIT , solo per amor di teoria, usando l'algoritmo all-modulo convenzionale più lento per l'anno bisestile, l'intervallo può essere esteso a 2 ^ 53. L'algoritmo di ricerca mensile non è il fattore limitante.
GitaarLAB

5

Se non vuoi reinventare la ruota, puoi usare l'eccellente libreria date-fns (node.js):

var getDayOfYear = require('date-fns/get_day_of_year')

var dayOfYear = getDayOfYear(new Date(2017, 1, 1)) // 1st february => 32

4

Bene, se ti ho capito bene, vuoi 366 su un anno bisestile, 365 altrimenti, giusto? Un anno è bisestile se è uniformemente divisibile per 4 ma non per 100 a meno che non sia divisibile anche per 400:

function daysInYear(year) {
    if(year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)) {
        // Leap year
        return 366;
    } else {
        // Not a leap year
        return 365;
    }
}

Modifica dopo l'aggiornamento:

In tal caso, non credo che ci sia un metodo integrato; dovrai fare questo:

function daysInFebruary(year) {
    if(year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)) {
        // Leap year
        return 29;
    } else {
        // Not a leap year
        return 28;
    }
}

function dateToDay(date) {
    var feb = daysInFebruary(date.getFullYear());
    var aggregateMonths = [0, // January
                           31, // February
                           31 + feb, // March
                           31 + feb + 31, // April
                           31 + feb + 31 + 30, // May
                           31 + feb + 31 + 30 + 31, // June
                           31 + feb + 31 + 30 + 31 + 30, // July
                           31 + feb + 31 + 30 + 31 + 30 + 31, // August
                           31 + feb + 31 + 30 + 31 + 30 + 31 + 31, // September
                           31 + feb + 31 + 30 + 31 + 30 + 31 + 31 + 30, // October
                           31 + feb + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, // November
                           31 + feb + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, // December
                         ];
    return aggregateMonths[date.getMonth()] + date.getDate();
}

(Sì, in realtà l'ho fatto senza copiare o incollare. Se c'è un modo semplice, sarò pazzo)


Il mio modo più semplice è usare il numero magico 1054267675 e chiamarlo un giorno, sono un po 'pigro per digitare tutto questo:)
GitaarLAB

4

Questo è un modo semplice per trovare il giorno corrente dell'anno e dovrebbe tenere conto degli anni bisestili senza problemi:

Javascript:

Math.round((new Date().setHours(23) - new Date(new Date().getYear()+1900, 0, 1, 0, 0, 0))/1000/60/60/24);

Javascript in Google Apps Script:

Math.round((new Date().setHours(23) - new Date(new Date().getYear(), 0, 1, 0, 0, 0))/1000/60/60/24);

L'azione principale di questo codice è trovare il numero di millisecondi trascorsi nell'anno corrente e quindi convertire questo numero in giorni. Il numero di millisecondi trascorsi nell'anno in corso può essere trovato sottraendo il numero di millisecondi del primo secondo del primo giorno dell'anno corrente, che si ottiene con new Date(new Date().getYear()+1900, 0, 1, 0, 0, 0)(Javascript) o new Date(new Date().getYear(), 0, 1, 0, 0, 0)(Google Apps Script), dai millisecondi della 23a ora del giorno corrente, che è stato trovato con new Date().setHours(23). Lo scopo di impostare la data corrente sulla 23a ora è garantire che il giorno dell'anno sia arrotondato correttamente di Math.round().

Una volta ottenuto il numero di millisecondi dell'anno corrente, puoi convertire questo tempo in giorni dividendo per 1000 per convertire i millisecondi in secondi, quindi dividendo per 60 per convertire i secondi in minuti, quindi dividendo per 60 per convertire i minuti in ore, e infine dividendo per 24 per convertire le ore in giorni.

Nota: questo post è stato modificato per tenere conto delle differenze tra JavaScript e JavaScript implementato in Google Apps Script. Inoltre, è stato aggiunto più contesto per la risposta.


Puoi spiegare un po 'di più oltre a dire che funziona?
Stephen Reindl

Sì! Mi dispiace di non aver fornito maggiori dettagli in primo luogo. L'espressione all'interno dell'istruzione "Math.round" trova il numero di millisecondi nell'anno corrente sottraendo il primo giorno dell'anno dai millisecondi dell'ultima ora del giorno corrente dell'anno. Il numero di millisecondi viene quindi diviso per 1000 per convertire in secondi, 60 per convertire in minuti, 60 per convertire in ore e 24 per convertire in giorni. L'espressione è racchiusa in una funzione "Math.round ()" in modo che venga arrotondata a un numero intero per il giorno dell'anno.
Liz Page-Gould

Dovrei anche aggiungere che questa soluzione è essenzialmente la stessa della soluzione "accettata", tranne che fa tutto in una riga di codice.
Liz Page-Gould

Come fa questo conto per l'ora legale? Non lo sbaglierebbe un po '?
Dan Oswalt

No, l'ora legale non influirà su questo calcolo, perché l'ora legale ha la risoluzione delle ore e questo codice calcola il numero di giorni dell'anno. Inoltre, poiché ho utilizzato il .setHoursmetodo sul primo oggetto data e ho specificato l'ora del giorno con il secondo oggetto data, una modifica di 1 ora dall'ora legale non influirà sugli orari degli oggetti Date utilizzati in questo calcolo.
Liz Page-Gould

4

Penso che questo sia più semplice:

var date365 = 0;

var currentDate = new Date();
var currentYear = currentDate.getFullYear();
var currentMonth = currentDate.getMonth(); 
var currentDay = currentDate.getDate(); 

var monthLength = [31,28,31,30,31,30,31,31,30,31,30,31];

var leapYear = new Date(currentYear, 1, 29); 
if (leapYear.getDate() == 29) { // If it's a leap year, changes 28 to 29
    monthLength[1] = 29;
}

for ( i=0; i < currentMonth; i++ ) { 
    date365 = date365 + monthLength[i];
}
date365 = date365 + currentDay; // Done!

3

Questo metodo tiene conto del problema del fuso orario e dell'ora legale

function dayofyear(d) {   // d is a Date object
    var yn = d.getFullYear();
    var mn = d.getMonth();
    var dn = d.getDate();
    var d1 = new Date(yn,0,1,12,0,0); // noon on Jan. 1
    var d2 = new Date(yn,mn,dn,12,0,0); // noon on input date
    var ddiff = Math.round((d2-d1)/864e5);
    return ddiff+1; 
}

(preso da qui )

Vedi anche questo violino


Questo è un po 'inefficiente, ma funziona perfettamente. Potresti semplicemente ottenere l'ora degli oggetti e setDate cambiare la data al giorno 1. Entrambi sono perfettamente supportati. L'idea è che non ti muoverai nei fusi orari. Ciò presuppone anche che l'ora legale sia inferiore a 12 ore ... il che è un presupposto sicuro sulla terra.
Ray Foss

2

Math.round ((new Date (). SetHours (23) - new Date (new Date (). GetFullYear (), 0, 1, 0, 0, 0)) / 1000/86400);

ottimizza ulteriormente la risposta.

Inoltre, modificando setHours (23) o il penultimo zero in un secondo momento su un altro valore, è possibile fornire il giorno dell'anno relativo a un altro fuso orario. Ad esempio, per recuperare dall'Europa una risorsa situata in America.


1
Math.floor((Date.now() - Date.parse(new Date().getFullYear(), 0, 0)) / 86400000)

questa è la mia soluzione


Uso il 31 dicembre dell'anno precedente per rendere Jan 01 = DOY 01. Inoltre ho scoperto che il 10 marzo ha lo stesso DOY dell'11 marzo perché uno era 69 e l'altro 69,9 qualcosa, entrambi i pavimenti a 69. Facendo Math.round invece risolto questo problema . Credo che il 10 marzo o l'11 marzo sia l'ora legale che fa sì che l'11 marzo non sia del tutto DOY 70.
user3015682

0

Ne ho creato uno leggibile e farà il trucco molto rapidamente, oltre a gestire oggetti JS Date con fusi orari diversi.

Ho incluso alcuni casi di test per fusi orari, ora legale, secondi intercalari e anni bisestili.

PS ECMA-262 ignora i secondi intercalari, a differenza di UTC. Se dovessi convertirlo in una lingua che utilizza UTC reale, potresti semplicemente aggiungere 1 a oneDay.

// returns 1 - 366
findDayOfYear = function (date) {
  var oneDay = 1000 * 60 * 60 * 24; // A day in milliseconds
  var og = {                        // Saving original data
    ts: date.getTime(),
    dom: date.getDate(),            // We don't need to save hours/minutes because DST is never at 12am.
    month: date.getMonth()
  }
  date.setDate(1);                  // Sets Date of the Month to the 1st.
  date.setMonth(0);                 // Months are zero based in JS's Date object
  var start_ts = date.getTime();    // New Year's Midnight JS Timestamp
  var diff = og.ts - start_ts;

  date.setDate(og.dom);             // Revert back to original date object
  date.setMonth(og.month);          // This method does preserve timezone
  return Math.round(diff / oneDay) + 1; // Deals with DST globally. Ceil fails in Australia. Floor Fails in US.
}

// Tests
var pre_start_dst = new Date(2016, 2, 12);
var on_start_dst = new Date(2016, 2, 13);
var post_start_dst = new Date(2016, 2, 14);

var pre_end_dst_date = new Date(2016, 10, 5);
var on_end_dst_date = new Date(2016, 10, 6);
var post_end_dst_date = new Date(2016, 10, 7);

var pre_leap_second = new Date(2015, 5, 29);
var on_leap_second = new Date(2015, 5, 30);
var post_leap_second = new Date(2015, 6, 1);

// 2012 was a leap year with a leap second in june 30th
var leap_second_december31_premidnight = new Date(2012, 11, 31, 23, 59, 59, 999);

var january1 = new Date(2016, 0, 1);
var january31 = new Date(2016, 0, 31);

var december31 = new Date(2015, 11, 31);
var leap_december31 = new Date(2016, 11, 31);

alert( ""
  + "\nPre Start DST: " + findDayOfYear(pre_start_dst) + " === 72"
  + "\nOn Start DST: " + findDayOfYear(on_start_dst) + " === 73"
  + "\nPost Start DST: " + findDayOfYear(post_start_dst) + " === 74"
      
  + "\nPre Leap Second: " + findDayOfYear(pre_leap_second) + " === 180"
  + "\nOn Leap Second: " + findDayOfYear(on_leap_second) + " === 181"
  + "\nPost Leap Second: " + findDayOfYear(post_leap_second) + " === 182"
      
  + "\nPre End DST: " + findDayOfYear(pre_end_dst_date) + " === 310"
  + "\nOn End DST: " + findDayOfYear(on_end_dst_date) + " === 311"
  + "\nPost End DST: " + findDayOfYear(post_end_dst_date) + " === 312"
      
  + "\nJanuary 1st: " + findDayOfYear(january1) + " === 1"
  + "\nJanuary 31st: " + findDayOfYear(january31) + " === 31"
  + "\nNormal December 31st: " + findDayOfYear(december31) + " === 365"
  + "\nLeap December 31st: " + findDayOfYear(leap_december31) + " === 366"
  + "\nLast Second of Double Leap: " + findDayOfYear(leap_second_december31_premidnight) + " === 366"
);


0

Vorrei fornire una soluzione che esegue calcoli aggiungendo i giorni per ogni mese precedente:

function getDayOfYear(date) {
    var month = date.getMonth();
    var year = date.getFullYear();
    var days = date.getDate();
    for (var i = 0; i < month; i++) {
        days += new Date(year, i+1, 0).getDate();
    }
    return days;
}
var input = new Date(2017, 7, 5);
console.log(input);
console.log(getDayOfYear(input));

In questo modo non devi gestire i dettagli degli anni bisestili e dell'ora legale.


0

Un'alternativa che utilizza i timestamp UTC. Inoltre, come altri hanno notato, il giorno che indica il primo mese è 1 anziché 0. Tuttavia, il mese inizia da 0.

var now = Date.now();
var year =  new Date().getUTCFullYear();
var year_start = Date.UTC(year, 0, 1);
var day_length_in_ms = 1000*60*60*24;
var day_number = Math.floor((now - year_start)/day_length_in_ms)
console.log("Day of year " + day_number);

0

È possibile passare il parametro come numero di data nella setDatefunzione:

var targetDate = new Date();
targetDate.setDate(1);

// Now we can see the expected date as: Mon Jan 01 2018 01:43:24
console.log(targetDate);

targetDate.setDate(365);

// You can see: Mon Dec 31 2018 01:44:47
console.log(targetDate)

0

Questo potrebbe essere utile a coloro che hanno bisogno del giorno dell'anno come stringa e hanno a disposizione l'interfaccia utente jQuery.

Puoi usare jQuery UI Datepicker:

day_of_year_string = $.datepicker.formatDate("o", new Date())

Sotto funziona allo stesso modo di alcune delle risposte già menzionate ( (date_ms - first_date_of_year_ms) / ms_per_day):

function getDayOfTheYearFromDate(d) {
    return Math.round((new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime() 
- new Date(d.getFullYear(), 0, 0).getTime()) / 86400000);
}

day_of_year_int = getDayOfTheYearFromDate(new Date())

0

Per quelli tra noi che desiderano una rapida soluzione alternativa.

(function(){"use strict";
function daysIntoTheYear(dateInput){
    var fullYear = dateInput.getFullYear()|0;
	// "Leap Years are any year that can be exactly divided by 4 (2012, 2016, etc)
 	//	except if it can be exactly divided by 100, then it isn't (2100, 2200, etc)
 	//		except if it can be exactly divided by 400, then it is (2000, 2400)"
	// (https://www.mathsisfun.com/leap-years.html).
    var isLeapYear = ((fullYear & 3) | (fullYear/100 & 3)) === 0 ? 1 : 0;
	// (fullYear & 3) = (fullYear % 4), but faster
    //Alternative:var isLeapYear=(new Date(currentYear,1,29,12)).getDate()===29?1:0
    var fullMonth = dateInput.getMonth()|0;
    return ((
        // Calculate the day of the year in the Gregorian calendar
        // The code below works based upon the facts of signed right shifts
        //    • (x) >> n: shifts n and fills in the n highest bits with 0s 
        //    • (-x) >> n: shifts n and fills in the n highest bits with 1s
        // (This assumes that x is a positive integer)
        (31 & ((-fullMonth) >> 4)) + // January // (-11)>>4 = -1
        ((28 + isLeapYear) & ((1-fullMonth) >> 4)) + // February
        (31 & ((2-fullMonth) >> 4)) + // March
        (30 & ((3-fullMonth) >> 4)) + // April
        (31 & ((4-fullMonth) >> 4)) + // May
        (30 & ((5-fullMonth) >> 4)) + // June
        (31 & ((6-fullMonth) >> 4)) + // July
        (31 & ((7-fullMonth) >> 4)) + // August
        (30 & ((8-fullMonth) >> 4)) + // September
        (31 & ((9-fullMonth) >> 4)) + // October
        (30 & ((10-fullMonth) >> 4)) + // November
        // There are no months past December: the year rolls into the next.
        // Thus, fullMonth is 0-based, so it will never be 12 in Javascript

        (dateInput.getDate()|0) // get day of the month

    )&0xffff);
}
// Demonstration:
var date = new Date(2100, 0, 1)
for (var i=0; i<12; i=i+1|0, date.setMonth(date.getMonth()+1|0))
    console.log(date.getMonth()+":\tday "+daysIntoTheYear(date)+"\t"+date);
date = new Date(1900, 0, 1);
for (var i=0; i<12; i=i+1|0, date.setMonth(date.getMonth()+1|0))
    console.log(date.getMonth()+":\tday "+daysIntoTheYear(date)+"\t"+date);

// Performance Benchmark:
console.time("Speed of processing 65536 dates");
for (var i=0,month=date.getMonth()|0; i<65536; i=i+1|0)
    date.setMonth(month=month+1+(daysIntoTheYear(date)|0)|0);
console.timeEnd("Speed of processing 65536 dates");
})();

La dimensione dei mesi dell'anno e il modo in cui funzionano gli anni bisestili si adattano perfettamente a mantenere il nostro tempo in linea con il sole. Diamine, funziona così perfettamente che tutto ciò che facciamo è regolare solo pochi secondi qua e là . Il nostro attuale sistema di anni bisestili è in vigore dal 24 febbraio 1582 e probabilmente rimarrà in vigore nel prossimo futuro.

L'ora legale, tuttavia, è molto soggetta a modifiche. Può darsi che tra 20 anni qualche paese possa compensare l'ora di un'intera giornata o di qualche altro estremo per l'ora legale. Un intero giorno di DST quasi certamente non accadrà mai, ma il DST è comunque molto attivo e indeciso. Pertanto, la soluzione di cui sopra è a prova di futuro oltre ad essere molto molto veloce.

Lo snippet di codice sopra viene eseguito molto velocemente. Il mio computer può elaborare 65536 date in ~ 52 ms su Chrome.


0

const dayOfYear = date => {
    const myDate = new Date(date);
    const year = myDate.getFullYear();
    const firstJan = new Date(year, 0, 1);
    const differenceInMillieSeconds = myDate - firstJan;
    return (differenceInMillieSeconds / (1000 * 60 * 60 * 24) + 1);
};

const result = dayOfYear("2019-2-01");
console.log(result);


0

Questa è una soluzione che evita i fastidiosi problemi relativi all'oggetto Data e al fuso orario, richiede che la data di input sia nel formato "aaaa-gg-mm". Se vuoi cambiare il formato, modifica la funzione date_str_to_parts:

    function get_day_of_year(str_date){
    var date_parts = date_str_to_parts(str_date);
    var is_leap = (date_parts.year%4)==0;
    var acct_for_leap = (is_leap && date_parts.month>2);
    var day_of_year = 0;

    var ary_months = [
        0,
        31, //jan
        28, //feb(non leap)
        31, //march
        30, //april
        31, //may
        30, //june
        31, //july
        31, //aug
        30, //sep
        31, //oct
        30, //nov   
        31  //dec
        ];


    for(var i=1; i < date_parts.month; i++){
        day_of_year += ary_months[i];
    }

    day_of_year += date_parts.date;

    if( acct_for_leap ) day_of_year+=1;

    return day_of_year;

}

function date_str_to_parts(str_date){
    return {
        "year":parseInt(str_date.substr(0,4),10),
        "month":parseInt(str_date.substr(5,2),10),
        "date":parseInt(str_date.substr(8,2),10)
    }
}

-1

Mi preoccupo sempre quando mischio la matematica con le funzioni di data (è così facile perdere qualche anno bisestile altri dettagli). Di 'che hai:

var d = new Date();

Suggerirei di utilizzare quanto segue, i giorni verranno salvati in day:

for(var day = d.getDate(); d.getMonth(); day += d.getDate())
    d.setDate(0);

Non riesco a vedere alcun motivo per cui questo non funzionerebbe bene (e non sarei così preoccupato per le poche iterazioni poiché questo non sarà usato così intensamente).


-1

/ * USA QUESTO SCRIPT * /

var today = new Date();
var first = new Date(today.getFullYear(), 0, 1);
var theDay = Math.round(((today - first) / 1000 / 60 / 60 / 24) + .5, 0);
alert("Today is the " + theDay + (theDay == 1 ? "st" : (theDay == 2 ? "nd" : (theDay == 3 ? "rd" : "th"))) + " day of the year");
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.