Javascript berechnet den Tag des Jahres (1 - 366)

118

Wie berechne ich mit Javascript den Tag des Jahres von 1 bis 366? Beispielsweise:

  • Der 3. Januar sollte der 3. Januar sein .
  • Der 1. Februar sollte 32 sein .
Kirk Woll
quelle
4
var days = new Date().getFullYear() % 4 == 0 ? 366 : 365;
Alex Turpin
Aber ich bin mir wirklich nicht sicher, was du meinst. Sie möchten nur die Anzahl der Tage im Jahr? Oder zwischen zwei Terminen?
Alex Turpin
16
fyi @ xeon06, Schaltjahrberechnung ist etwas komplizierter als das Ändern um 4. Siehe: Schaltjahralgorithmus
Matt Felzani
4
@ Xeon06: Das stimmt nur die meiste Zeit. Aus Wikipedia : Jahre , die durch 100 teilbar sind , sind keine Schaltjahre, wenn sie nicht durch 400 teilbar sind auch gleichmäßig, in welchem Fall sie sind Schaltjahre.
Cameron
Na ja, ich stehe korrigiert da. @minitech scheint dann die richtige Antwort zu haben.
Alex Turpin

Antworten:

137

Folgende OP-Bearbeitung:

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

Bearbeiten: Der obige Code schlägt fehl, wenn nowein Datum zwischen dem 26. März und dem 29. Oktober liegt und nowdie Zeit vor 1 Uhr morgens liegt (z. B. 00:59:59). Dies liegt daran, dass der Code die Sommerzeit nicht berücksichtigt. Sie sollten dies kompensieren :

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

Alex Turpin
quelle
5
Math.floorgab mir durchweg ein Ergebnis von 1 Tag weniger als erwartet nach einem bestimmten Tag im April. Math.ceilhat wie erwartet funktioniert, aber ich habe gesehen, dass empfohlen wird, dass Sie Math.roundanstelle von beiden verwenden.
Baacke
3
Die Tageskomponente ist Basis-1. dh um den 1. Januar dieses Jahres darzustellen, würden Sie verwenden new Date(2014, 0, 1), und nicht new Date(2014, 0, 0)wie Sie hier haben. Ist das beabsichtigt? Vielleicht ist es das, was dafür verantwortlich ist, dass wir eines Tages frei sind und new Date(2014, 0, 0)zurückkehren werden 12/31/2013.
Kirk Woll
1
Vielleicht verwenden .setUTCHoursund Date.UTC()für eine zuverlässigere Lösung.
Noyo
6
@AlexTurpin, @ T30: Ich weiß, dass dies ein bisschen alt ist, aber wenn Sie sich fragen ... das Problem wird durch die Sommerzeit verursacht, die im März beginnt. Dies liegt daran, dass Sie, wenn Sie die Differenz zwischen Mitternacht eines Datums vor der Sommerzeit und Mitternacht eines Datums nach der Sommerzeit nehmen, keine Millisekunden haben, die gleichmäßig durch 1000 * 60 * 60 * 24 teilbar sind (genau eine Stunde Pause). . Die einfachste Lösung ist die Verwendung von ceilanstatt floor, dies gibt Ihnen ein Nummerierungssystem, bei dem der 1. Januar = 1. Wenn Sie den 1. Januar = 0 möchten (wie floores Ihnen geben würde), subtrahieren Sie einfach 1 von Ihrem Endergebnis.
Warren R.
2
Um Zeitzonen und Sommerzeit zu berücksichtigen, ändern Sie Zeile 3 in: var diff = now - start + (start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000;
Marlon
46

Dies funktioniert bei Änderungen der Sommerzeit in allen Ländern (der oben genannte "Mittag" funktioniert in Australien nicht):

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;
};
Joe Orost
quelle
1
Stimmen Sie zu, dass die akzeptierte Antwort Fehler im Zusammenhang mit der Sommerzeit enthält. Die obige Lösung ist besser und schneller. Hier ist eine Variation davon, die ich auf jsPerf jsperf.com/date-getdayofyear-perf
Shyam Habarakada
@ShyamHabarakada: Der Code in Ihrem Benchmark ist fehlerhaft und getDay()muss in geändert werden getDate(). Ersteres gibt den Wochentag zurück (0 = Sonntag..6 = Samstag), nicht den Tag.
CodeManX
32

Ich finde es sehr interessant, dass niemand UTC in Betracht gezogen hat, da es nicht der Sommerzeit unterliegt. Daher schlage ich Folgendes vor:

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

Sie können es folgendermaßen testen:

[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`));

Welche Ergebnisse für das Schaltjahr 2016 (überprüft mit 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
user2501097
quelle
Dies kann überlaufen, da die Anzahl der Millisekunden zu groß ist.
knt5784
@ knt5784 Die Mathematik kann möglicherweise überlaufen, aber sein Beispiel zeigt, dass der größtmögliche reale Wert einwandfrei funktioniert. Sie sollten dies also in Ordnung verwenden, es sei denn, es gibt ein browserbasiertes Problem mit dem Ganzzahlüberlauf.
Per Fagrell
Ich persönlich mag diesen Ansatz. Viel sauberer (und sehr clever!), Um Sommerzeitprobleme zu vermeiden. Wenn sich jemand fragt, wie man von DOY zurück auf das Datum konvertiert, ist es viel einfacher. Grundsätzlich erstellen Sie einfach ein Datum von Januar DOYth. Zum Beispiel am 59. Januar === 28. Februar. Der Schalttag wird gut gehandhabt. function doyToDate(doy, year) { return new Date(year, 0, doy); }
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())
kennebec
quelle
3
Dies würde keine Flusen passieren ... Ändern eines Objekts, das nicht Ihnen gehört, insbesondere eines globalen. Dies würde auch bei Planeten mit extremer Neigung fehlschlagen, bei denen die Sommerzeit mehr als 12 Stunden beträgt. Aber realistischer, wenn Sie für einen Browser codieren, der das Ändern der Zeitzone des Date-Objekts ermöglicht, könnte die Zeitzone von j1 ​​Australien und die Zeitzone von Alaska Alaska sein, wodurch die Rundung unterbrochen wird.
Ray Foss
11

Glücklicherweise gibt diese Frage nicht an, ob die Nummer des aktuellen Tages erforderlich ist, sodass Platz für diese Antwort bleibt.
Auch einige Antworten (auch auf andere Fragen) hatten Schaltjahrprobleme oder verwendeten das Date-Objekt. Obwohl die javascript Date objectetwa 285.616 Jahre Abdeckungen (100.000.000 Tage) auf beiden Seiten vom 1. Januar 1970 wurde ich mit allen möglichen unerwarteten Zeitpunkt satt Inkonsistenzen in verschiedenen Browsern (insbesondere die Jahre 0 bis 99). Ich war auch neugierig, wie man es berechnet.

So habe ich eine einfache und vor allem schrieb kleinen Algorithmus zur Berechnung der korrekten ( proleptische Gregorian / astronomisches / ISO 8601: 2004 (Abschnitt 4.3.2.1), so Jahr0 existiert und ein Schaltjahr und Tag des Jahres negative Jahre unterstützt werden ) basierend auf Jahr , Monat und Tag .
Beachten Sie, dass in der AD/BCNotation das Jahr 0 AD / BC nicht existiert: Stattdessen 1 BCist das Jahr das Schaltjahr! WENN Sie die BC-Notation berücksichtigen müssen, subtrahieren Sie einfach zuerst ein Jahr vom (ansonsten positiven) Jahreswert !!

Ich habe (für Javascript) den Kurzschluss-Bitmasken-Modulo-Schaltjahr-Algorithmus modifiziert und mir eine magische Zahl ausgedacht , um eine bitweise Suche nach Offsets durchzuführen (ohne Jan und Februar, sodass 10 * 3 Bits benötigt werden (30 Bits sind weniger als) 31 Bit, damit wir sicher ein anderes Zeichen in der Bitverschiebung speichern können, anstatt >>>)).

Beachten Sie, dass weder Monat noch Tag sein dürfen 0. Das bedeutet , dass , wenn Sie diese Gleichung müssen nur für den aktuellen Tag (Fütterung es mit .getMonth()) brauchen Sie nur das entfernen --aus --m.

Beachten Sie, dass dies ein gültiges Datum voraussetzt (obwohl die Fehlerprüfung nur einige Zeichen mehr ist).

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>


Hier ist die Version mit korrekter Bereichsvalidierung.

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>

Wieder eine Zeile, aber ich habe sie zur besseren Lesbarkeit (und folgenden Erläuterungen) in drei Zeilen aufgeteilt.

Die letzte Zeile ist identisch mit der obigen Funktion, jedoch wird der (identische) Schaltjahr-Algorithmus in einen vorherigen Kurzschlussabschnitt (vor der Berechnung der Tageszahl) verschoben, da auch bekannt sein muss, wie viele Tage ein Monat in einem hat gegebenes (Schalt-) Jahr.

Die mittlere Zeile berechnet die korrekte Versatzzahl (für die maximale Anzahl von Tagen) für einen bestimmten Monat in einem bestimmten (Schalt-) Jahr unter Verwendung einer anderen magischen Zahl: Da 31-28=3und 3nur 2 Bits und dann 12*2=24Bits sind, können wir alle 12 Monate speichern. Da die Addition schneller als die Subtraktion sein kann, addieren wir den Offset (anstatt ihn zu subtrahieren 31). Um einen Schaltjahr-Entscheidungszweig für Februar zu vermeiden, ändern wir diese magische Suchnummer im laufenden Betrieb.

Damit bleibt uns die (ziemlich offensichtliche) erste Zeile: Sie überprüft, ob Monat und Datum innerhalb der gültigen Grenzen liegen, und stellt sicher, dass bei einem falseBereichsfehler ein Rückgabewert angezeigt wird (beachten Sie, dass diese Funktion auch 0 nicht zurückgeben kann, da 1 Januar 0000 ist noch Tag 1.) und bietet eine einfache Fehlerprüfung : if(r=dayNo(/*y, m, d*/)){}.
Wenn auf diese Weise verwendet werden (wo Monat und Tag können nicht sein 0), dann kann man ändern , --m>=0 && m<12um m>0 && --m<12(Speicher ein anderes Zeichen).
Der Grund , warum ich das Snippet getippt in seiner derzeitigen Form ist , dass für die Monatswerte-0 basiert, man muss nur das Entfernen --von--m .

Extra:
Beachten Sie, dass Sie den Algorithmus für diesen Tag pro Monat nicht verwenden, wenn Sie nur den maximalen Tag pro Monat benötigen. In diesem Fall gibt es einen effizienteren Algorithmus (da wir nur leepYear benötigen, wenn der Monat Februar ist). Als Antwort auf diese Frage habe ich Folgendes gepostet: Wie lässt sich die Anzahl der Tage in einem Monat am besten mit Javascript bestimmen? .

GitaarLAB
quelle
1
Ich habe es zur Vereinfachung der Verwendung in eine Datumsfunktion geworfen. Zugegeben, die Inkonsistenzen bei Date () sind immer noch ein Problem, aber ich verwende Jahre 2015+ und hoffe, dass sie konsistent sind. Der arme JSHint ist beim Versuch, Ihren Code zu validieren, gestorben, 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
Ich bin froh, dass es dir gefallen hat. Dieses Algo ist 2 ^ 31-1 Jahre lang vollständig getestet (satte 2147483647, das ist> 7500-mal der Bereich des Datumsobjekts von Javascript) auf beiden Seiten von 0. (Es könnte für 2 ^ 32 funktionieren, aber das habe ich nicht getestet noch). Auch könnten Sie meine Antwort wieder lesen: Sie abrasieren kann +1aus , this.getMonth()+1wenn Sie entfernen die --aus --m. EDIT Also, ich würde (für eine Bibliothek) tun: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
Das habe ich eigentlich gerade gemacht, als ich es mir angesehen habe! Mir wurde klar, dass ich eine hinzufügte und sie dann sofort subtrahierte. Ich denke, dass 2^31 - 2016js in den nächsten Jahren wahrscheinlich etwas veraltet sein wird.
Freshvolk
@Freshvolk: lol, weshalb ich es nie über 2 ^ 31 hinaus getestet habe. :)Aber bis dahin wird es zumindest vorhersehbare und konsistente Ergebnisse liefern, haha. EDIT , nur aus theoretischen Gründen, mit dem langsameren konventionellen All-Modulo-Algo für Leapyear kann der Bereich auf 2 ^ 53 erweitert werden. Der Monatssuchalgo ist nicht der begrenzende Faktor.
GitaarLAB
5

Wenn Sie das Rad nicht neu erfinden möchten, können Sie die hervorragende Bibliothek date-fns (node.js) verwenden:

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

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

Nun, wenn ich Sie richtig verstehe, wollen Sie 366 in einem Schaltjahr, sonst 365, oder? Ein Jahr ist ein Schaltjahr, wenn es gleichmäßig durch 4 teilbar ist, aber nicht durch 100, es sei denn, es ist auch durch 400 teilbar:

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

Nach dem Update bearbeiten:

In diesem Fall glaube ich nicht, dass es eine eingebaute Methode gibt. Sie müssen dies tun:

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

(Ja, das habe ich tatsächlich gemacht, ohne zu kopieren oder einzufügen. Wenn es einen einfachen Weg gibt, werde ich verrückt sein.)

Ry-
quelle
Mein einfacher Weg ist es, einfach die magische Nummer 1054267675 zu verwenden und es einen Tag zu nennen. Ich bin viel zu faul, um all das zu :)
tippen
4

Dies ist eine einfache Methode, um den aktuellen Tag im Jahr zu ermitteln, und es sollten problemlos Schaltjahre berücksichtigt werden:

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

Die Hauptaktion dieses Codes besteht darin, die Anzahl der im aktuellen Jahr verstrichenen Millisekunden zu ermitteln und diese Zahl dann in Tage umzuwandeln. Die Anzahl der im aktuellen Jahr verstrichenen Millisekunden kann ermittelt werden, indem die Anzahl der Millisekunden der ersten Sekunde des ersten Tages des aktuellen Jahres, die mit new Date(new Date().getYear()+1900, 0, 1, 0, 0, 0)(Javascript) oder new Date(new Date().getYear(), 0, 1, 0, 0, 0)(Google Apps Script) ermittelt wurde, von den Millisekunden abgezogen wird der 23. Stunde des aktuellen Tages, die mit gefunden wurde new Date().setHours(23). Mit der Einstellung des aktuellen Datums auf die 23. Stunde soll sichergestellt werden, dass der Tag des Jahres korrekt gerundet wird Math.round().

Sobald Sie die Anzahl der Millisekunden des aktuellen Jahres haben, können Sie diese Zeit in Tage umrechnen, indem Sie durch 1000 dividieren, um Millisekunden in Sekunden umzuwandeln, dann durch 60 teilen, um Sekunden in Minuten umzuwandeln, und dann durch 60 teilen, um Minuten in Stunden umzurechnen. und schließlich durch 24 teilen, um Stunden in Tage umzuwandeln.

Hinweis: Dieser Beitrag wurde bearbeitet, um Unterschiede zwischen JavaScript und JavaScript zu berücksichtigen, die in Google Apps Script implementiert sind. Außerdem wurde mehr Kontext für die Antwort hinzugefügt.

Liz Page-Gould
quelle
Können Sie bitte ein bisschen mehr erklären, als nur zu sagen, dass es funktioniert?
Stephen Reindl
Ja! Es tut mir leid, dass ich überhaupt nicht näher darauf eingegangen bin. Der Ausdruck in der Anweisung "Math.round" ermittelt die Anzahl der Millisekunden im aktuellen Jahr, indem der erste Tag des Jahres von den Millisekunden der letzten Stunde des aktuellen Tages des Jahres subtrahiert wird. Die Anzahl der Millisekunden wird dann durch 1000 geteilt, um sie in Sekunden umzuwandeln, 60, um sie in Minuten umzuwandeln, 60, um sie in Stunden umzuwandeln, und 24, um sie in Tage umzuwandeln. Der Ausdruck wird in eine "Math.round ()" - Funktion eingeschlossen, sodass er für den Tag des Jahres auf eine Ganzzahl gerundet wird.
Liz Page-Gould
Ich sollte auch hinzufügen, dass diese Lösung im Wesentlichen dieselbe ist wie die "akzeptierte" Lösung, außer dass sie alles in einer Codezeile erledigt.
Liz Page-Gould
Wie berücksichtigt dies die Sommerzeit? Würde das nicht ein bisschen abwerfen?
Dan Oswalt
Nein, die Sommerzeit hat keinen Einfluss auf diese Berechnung, da die Sommerzeit die Auflösung von Stunden hat und dieser Code die Anzahl der Tage im Jahr berechnet. Da ich die .setHoursMethode für das erste Datumsobjekt verwendet und die Uhrzeit mit dem zweiten Datumsobjekt angegeben habe, wirkt sich eine Änderung von 1 Stunde gegenüber der Sommerzeit nicht auf die Zeiten der in dieser Berechnung verwendeten Datumsobjekte aus.
Liz Page-Gould
4

Ich denke, das ist einfacher:

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!
Sean
quelle
3

Diese Methode berücksichtigt Zeitzonenprobleme und Sommerzeit

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

(nahm von hier )

Siehe auch diese Geige

Andriy F.
quelle
Das ist ein bisschen ineffizient, aber es funktioniert perfekt. Sie können einfach die Zeit der Objekte abrufen und setDate das Datum auf Tag 1 ändern. Beide werden perfekt unterstützt. Die Idee ist, dass Sie sich nicht in Zeitzonen bewegen. Dies setzt auch voraus, dass die Sommerzeit weniger als 12 Stunden beträgt ... was auf der Erde eine sichere Annahme ist.
Ray Foss
2

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

optimiert die Antwort weiter.

Darüber hinaus kann durch Ändern von setHours (23) oder der vorletzten Null später auf einen anderen Wert ein Tag des Jahres in Bezug auf eine andere Zeitzone bereitgestellt werden. Zum Beispiel, um eine in Amerika befindliche Ressource aus Europa abzurufen.

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

Das ist meine Lösung

Spiel es
quelle
Ich benutze den 31. Dezember des Vorjahres, um den 01. Januar = DOY 01 zu machen. Außerdem habe ich festgestellt, dass der 10. März den gleichen DOY wie der 11. März hat, weil einer 69 und der andere 69,9 Jahre alt war, beide Fußböden auf 69. Durch Math.round wurde dies stattdessen behoben . Ich glaube, entweder der 10. März oder der 11. März ist die Sommerzeitumschaltung, die dazu führt, dass der 11. März nicht ganz DOY 70 ist.
user3015682
0

Ich habe eine lesbare erstellt, die den Trick sehr schnell erledigt und JS-Datumsobjekte mit unterschiedlichen Zeitzonen verarbeitet.

Ich habe einige Testfälle für Zeitzonen, Sommerzeit, Schaltsekunden und Schaltjahre aufgenommen.

PS ECMA-262 ignoriert im Gegensatz zu UTC Schaltsekunden. Wenn Sie dies in eine Sprache konvertieren, die echte UTC verwendet, können Sie einfach 1 hinzufügen 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"
);

Ray Foss
quelle
0

Ich möchte eine Lösung bereitstellen, die Berechnungen durchführt und die Tage für jeden vorherigen Monat hinzufügt:

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

Auf diese Weise müssen Sie die Details der Schaltjahre und der Sommerzeit nicht verwalten.

Manix
quelle
0

Eine Alternative mit UTC-Zeitstempeln. Wie andere angemerkt haben, ist der Tag, an dem der 1. Monat angezeigt wird, 1 statt 0. Der Monat beginnt jedoch bei 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);
emctwoo
quelle
0

Sie können Parameter als Datumsnummer in der setDateFunktion übergeben:

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)
Ilyas Karim
quelle
0

Dies kann für diejenigen nützlich sein, die den Tag des Jahres als Zeichenfolge benötigen und über eine jQuery-Benutzeroberfläche verfügen.

Sie können jQuery UI Datepicker verwenden:

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

Darunter funktioniert es genauso wie bei einigen der bereits erwähnten Antworten ( (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())
Adrian G.
quelle
0

Für diejenigen unter uns, die eine schnelle alternative Lösung suchen.

(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");
})();

Die Größe der Monate des Jahres und die Art und Weise, wie Schaltjahre funktionieren, passen perfekt dazu, unsere Zeit mit der Sonne in Einklang zu halten. Heck, es funktioniert so perfekt, dass wir nur hier und da nur Sekunden einstellen . Unser derzeitiges System der Schaltjahre ist seit dem 24. Februar 1582 in Kraft in Kraft und wird wahrscheinlich auf absehbare Zeit in Kraft bleiben.

Die Sommerzeit kann sich jedoch stark ändern. Es kann sein, dass in 20 Jahren ein Land die Zeit um einen ganzen Tag oder ein anderes Extrem für die Sommerzeit ausgleicht. Ein ganzer DST-Tag wird mit ziemlicher Sicherheit nie stattfinden, aber die DST ist dennoch sehr in der Luft und unentschlossen. Somit ist die obige Lösung nicht nur sehr, sehr schnell, sondern auch zukunftssicher.

Das obige Code-Snippet läuft sehr schnell. Mein Computer kann 65536 Daten in ~ 52 ms in Chrome verarbeiten.

Jack Giffin
quelle
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);

user7331530
quelle
0

Dies ist eine Lösung, die die problematischen Probleme mit Datumsobjekten und Zeitzonen vermeidet. Es ist erforderlich, dass Ihr Eingabedatum das Format "JJJJ-TT-MM" hat. Wenn Sie das Format ändern möchten, ändern Sie die Funktion 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)
    }
}
Yogistra Anderson
quelle
-1

Ich mache mir immer Sorgen, wenn ich Mathematik mit Datumsfunktionen mische (es ist so leicht, ein Schaltjahr und andere Details zu übersehen). Angenommen, Sie haben:

var d = new Date();

Ich würde vorschlagen, Folgendes zu verwenden: Tage werden gespeichert in day:

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

Ich kann keinen Grund erkennen, warum dies nicht gut funktionieren würde (und ich wäre nicht so besorgt über die wenigen Iterationen, da dies nicht so intensiv genutzt wird).

Martin Ekblom
quelle
-1

/ * BENUTZEN SIE DIESES 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");
Pankaj Yadav
quelle