Javascript calcule le jour de l'année (1-366)


119

Comment utiliser javascript pour calculer le jour de l'année, de 1 à 366? Par exemple:

  • Le 3 janvier devrait être le 3 .
  • Le 1er février devrait avoir 32 ans .

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

Mais vraiment je ne suis pas sûr de ce que tu veux dire. Vous voulez juste le nombre de jours dans l'année? Ou entre deux dates?
Alex Turpin

16
fyi @ xeon06, le calcul des années bissextiles est un peu plus compliqué que la modification par 4. voir: algorithme des années bissextiles
Matt Felzani

4
@ Xeon06: Ce n'est correct que la plupart du temps. De Wikipedia : Les années qui sont divisibles de manière égale par 100 ne sont pas des années bissextiles, à moins qu'elles ne soient également divisibles par 400, auquel cas ce sont des années bissextiles.
Cameron

Ah ben je me tiens corrigé. @minitech semble alors avoir la bonne réponse.
Alex Turpin

Réponses:


138

Suite à la modification de 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);

Edit: Le code ci - dessus échouera quand nowest une date entre le 26 mars et le 29 octobre et nowl'heure de est avant 1h du matin (par exemple 00:59:59). Cela est dû au fait que le code ne prend pas en compte l'heure d'été. Vous devez compenser cela:

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.floorm'a toujours donné un résultat de 1 jour de moins que prévu après un certain jour en avril. Math.ceila fonctionné comme prévu, mais j'ai vu qu'il soit conseillé d'utiliser à la Math.roundplace de l'un ou l'autre.
baacke

3
La composante jour est la base-1. c'est-à-dire pour représenter le 1er janvier de cette année, vous utiliseriez new Date(2014, 0, 1), et non new Date(2014, 0, 0)comme vous l'avez ici. Est-ce intentionnel? C'est peut-être ce qui explique le fait d'être parti d'un jour comme new Date(2014, 0, 0)cela reviendra 12/31/2013.
Kirk Woll

1
Peut-être utiliser .setUTCHourset Date.UTC()pour une solution plus fiable.
Noyo

6
@AlexTurpin, @ T30: Je sais que c'est un peu vieux, mais si vous vous posiez la question ... le problème est dû à l'heure d'été à partir de mars. En effet, lorsque vous prenez la différence entre minuit d'une date avant l'heure d'été et minuit d'une date après l'heure d'été, vous n'aurez pas un nombre de millisecondes divisibles de manière égale par 1000 * 60 * 60 * 24 (ce sera exactement une heure de repos) . La solution la plus simple est d'utiliser ceilplutôt que floor, cela vous donnera un système de numérotation où le 1er janvier = 1. Si vous voulez que le 1er janvier = 0 (comme floorvous le donnez), soustrayez simplement 1 de votre résultat final.
Warren R.

2
Pour prendre en compte les fuseaux horaires et l'heure d'été, changez la ligne 3 en: var diff = now - start + (start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000;
Marlon

46

Cela fonctionne avec les changements d'heure d'été dans tous les pays (le "midi" ci-dessus ne fonctionne pas en Australie):

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
Convenez qu'il y a des bogues liés à l'heure d'été dans la réponse acceptée. La solution ci-dessus est meilleure et plus rapide. En voici une variante que j'ai testée sur jsPerf jsperf.com/date-getdayofyear-perf
Shyam Habarakada

@ShyamHabarakada: le code de votre benchmark est cassé, getDay()doit être changé en getDate(). Le premier renvoie le jour de la semaine (0 = dimanche..6 = samedi), pas le jour.
CodeManX

32

Je trouve très intéressant que personne n'ait envisagé d'utiliser UTC car il n'est pas soumis à l'heure d'été. Par conséquent, je propose ce qui suit:

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

Vous pouvez le tester avec les éléments suivants:

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

Quelles sorties pour l'année bissextile 2016 (vérifiées via 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

Cela peut déborder car le nombre de millisecondes est trop grand.
knt5784

@ knt5784 Le calcul peut être en mesure de déborder, mais son exemple montre que la plus grande valeur possible du monde réel fonctionne correctement, vous devriez donc être d'accord pour l'utiliser à moins qu'il y ait un problème basé sur le navigateur avec un dépassement d'entier.
Per Fagrell

J'aime personnellement cette approche. Un moyen beaucoup plus propre (et très intelligent!) D'éviter les problèmes d'heure d'été. Si quelqu'un se demande comment convertir de DOY à ce jour, c'est beaucoup plus simple. Fondamentalement, vous créez simplement une date de janvier DOYth. Par exemple, le 59 janvier === le 28 février. Le jour bissextile est bien géré. function doyToDate(doy, year) { return new Date(year, 0, doy); }
Kip le

@ knt5784 Il n'y a aucun risque de dépassement de milliseconde avec ce code, du moins pas avant 200 000 ans. La plus grande date prise en charge par Date est new Date(8640000000000000), qui est toujours inférieure à Number.MAX_SAFE_INTEGER. voir cette réponse: 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
Cela ne passerait pas de charpie ... Modifier un objet qui n'est pas le vôtre, spécialement un objet global. Cela échouerait également dans les planètes avec une inclinaison extrême où l'heure d'été est supérieure à 12 heures. Mais plus réaliste, si vous codez pour un navigateur qui permet de changer le fuseau horaire de l'objet Date, le fuseau horaire de j1 pourrait être l'Australie et ce fuseau horaire pourrait être l'Alaska, cassant l'arrondi.
Ray Foss

11

Heureusement , cette question ne précise pas si le numéro du courant jour est nécessaire, laissant place à cette réponse.
De plus, certaines réponses (également sur d'autres questions) avaient des problèmes d'année bissextile ou utilisaient l'objet Date. Bien que le javascript Date objectcouvre environ 285616 ans (100 000 000 jours) de chaque côté du 1er janvier 1970, j'en avais marre de toutes sortes d' incohérences de date inattendues entre différents navigateurs (notamment les années 0 à 99). J'étais également curieux de savoir comment le calculer.

J'ai donc écrit un algorithme simple et surtout petit pour calculer le jour correct de l'année ( Proleptic Gregorian / Astronomical / ISO 8601: 2004 (clause 4.3.2.1), donc l' année0 existe et est une année bissextile et les années négatives sont prises en charge ). basé sur l' année , le mois et le jour .
Notez qu'en AD/BCnotation, l'année 0 AD / BC n'existe pas: à la place, l'année 1 BCest l'année bissextile! SI vous devez tenir compte de la notation BC, soustrayez simplement une année de la valeur de l'année (sinon positive) en premier !!

J'ai modifié (pour javascript) l' algorithme de court-circuit bitmask-modulo leapYear et est venu avec un nombre magique pour faire une recherche par bit des décalages (qui exclut jan et feb, nécessitant donc 10 * 3 bits (30 bits est moins que 31 bits, nous pouvons donc enregistrer en toute sécurité un autre caractère sur le décalage de bits au lieu de>>> )).

Notez qu'aucun mois ou jour ne peut l'être 0. Cela signifie que si vous avez besoin de cette équation juste pour le courant jour (alimentation à l'aide .getMonth()) il vous suffit de retirer la --de--m .

Notez que cela suppose une date valide (bien que la vérification des erreurs ne soit que quelques caractères de plus).

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>


Voici la version avec la validation de plage correcte .

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>

Encore une fois, une ligne, mais je l'ai divisée en 3 lignes pour la lisibilité (et l'explication suivante).

La dernière ligne est identique à la fonction ci-dessus, mais l'algorithme (identique) de leapYear est déplacé vers une section de court-circuit précédente (avant le calcul du nombre de jours), car il est également nécessaire de savoir combien de jours un mois a dans un donnée (bissextile) année.

La ligne médiane calcule le numéro de décalage correct (pour un nombre maximum de jours) pour un mois donné dans une année (bissextile) donnée en utilisant un autre nombre magique: puisque 31-28=3et 3est juste 2 bits, puis 12*2=24bits, nous pouvons stocker les 12 mois. Puisque l'addition peut être plus rapide que la soustraction, nous ajoutons le décalage (au lieu de le soustraire 31). Pour éviter une branche de décision d'année bissextile pour février, nous modifions ce numéro de recherche magique à la volée.

Cela nous laisse avec la première ligne (assez évidente): elle vérifie que le mois et la date sont dans des limites valides et nous assure une falsevaleur de retour en cas d'erreur de plage (notez que cette fonction ne devrait pas non plus pouvoir renvoyer 0, car 1 jan 0000 est encore jour 1.), fournissant facile vérification d'erreur: if(r=dayNo(/*y, m, d*/)){}.
S'il est utilisé de cette façon (où le mois et le jour peuvent ne pas être 0), alors on peut changer --m>=0 && m<12en m>0 && --m<12(enregistrer un autre caractère).
La raison pour laquelle j'ai tapé l'extrait dans sa forme actuelle est que pour les valeurs de mois basées sur 0, il suffit de supprimer le --de --m.

Extra:
Remarque, n'utilisez pas l'algorithme de ce jour par mois si vous n'avez besoin que d'un maximum de jours par mois. Dans ce cas, il existe un algorithme plus efficace (car nous n'avons besoin de leepYear que lorsque le mois est février) J'ai posté comme réponse à cette question: Quelle est la meilleure façon de déterminer le nombre de jours dans un mois avec javascript? .


1
Je l'ai jeté dans une fonction de date pour une utilisation facile. Certes, les incohérences Date () sont toujours un problème, mais j'utilise les années 2015+, donc j'espère qu'elles sont cohérentes. Le pauvre JSHint est mort en essayant de valider votre code 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

Content que tu aies aimé. Cet algorithme est entièrement testé pendant 2 ^ 31-1 ans (un énorme 2147483647, soit> 7500 fois la plage de l'objet date de javascript) des deux côtés de 0. (Cela pourrait fonctionner pendant 2 ^ 32, mais je n'ai pas testé cela encore). En outre, vous pouvez lire ma réponse à nouveau: vous pouvez raser à +1partir this.getMonth()+1si vous retirez le --de --m. EDIT Donc, je ferais (pour une bibliothèque):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

En fait, je viens de le faire quand je le regardais! J'ai réalisé que j'en ajoutais un, puis je le soustrais immédiatement. Je pense que d'ici quelques 2^31 - 2016années, js sera probablement un peu dépassé.
freshvolk

@Freshvolk: lol, c'est pourquoi je ne l'ai jamais testé au-delà de 2 ^ 31 :)Mais d'ici là, cela donnera au moins des résultats prévisibles et cohérents haha. EDIT , juste pour la théorie, en utilisant l'algo tout-modulo conventionnel plus lent pour leapyear, la plage peut être étendue à 2 ^ 53. L'algo de recherche mensuelle n'est pas le facteur limitant.
GitaarLAB

5

Si vous ne voulez pas réinventer la roue, vous pouvez utiliser l'excellente bibliothèque 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

Eh bien, si je vous comprends bien, vous voulez 366 sur une année bissextile, 365 sinon, non? Une année est une année bissextile si elle est divisible par 4 mais pas par 100, sauf si elle est également divisible par 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;
    }
}

Modifier après la mise à jour:

Dans ce cas, je ne pense pas qu'il existe une méthode intégrée; vous devrez faire ceci:

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

(Oui, je l'ai fait sans copier ni coller. S'il y a un moyen facile, je serai fou)


Mon moyen facile consiste simplement à utiliser le numéro magique 1054267675 et à l'appeler un jour, je suis :)
trop

4

C'est un moyen simple de trouver le jour actuel de l'année, et il devrait tenir compte des années bissextiles sans problème:

Javascript:

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

Javascript dans Google Apps Script:

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

L'action principale de ce code est de trouver le nombre de millisecondes qui se sont écoulées dans l'année en cours, puis de convertir ce nombre en jours. Le nombre de millisecondes qui se sont écoulées dans l'année en cours peut être trouvé en soustrayant le nombre de millisecondes de la première seconde du premier jour de l'année en cours, obtenu avec new Date(new Date().getYear()+1900, 0, 1, 0, 0, 0)(Javascript) ou new Date(new Date().getYear(), 0, 1, 0, 0, 0)(Google Apps Script), des millisecondes de la 23e heure de la journée en cours, qui a été trouvée avec new Date().setHours(23). Le réglage de la date actuelle à la 23e heure a pour but de garantir que le jour de l'année est correctement arrondi de Math.round().

Une fois que vous avez le nombre de millisecondes de l'année en cours, vous pouvez convertir cette heure en jours en divisant par 1000 pour convertir les millisecondes en secondes, puis en divisant par 60 pour convertir les secondes en minutes, puis en divisant par 60 pour convertir les minutes en heures, et enfin en divisant par 24 pour convertir les heures en jours.

Remarque: Ce message a été modifié pour tenir compte des différences entre JavaScript et JavaScript mis en œuvre dans Google Apps Script. En outre, plus de contexte a été ajouté pour la réponse.


Pouvez-vous s'il vous plaît expliquer un peu plus que simplement dire que cela fonctionne?
Stephen Reindl

Oui! Je suis désolé de ne pas avoir fourni plus de détails en premier lieu. L'expression à l'intérieur de l'instruction "Math.round" recherche le nombre de millisecondes de l'année en cours en soustrayant le premier jour de l'année des millisecondes de la dernière heure du jour en cours de l'année. Le nombre de millisecondes est ensuite divisé par 1000 pour convertir en secondes, 60 pour convertir en minutes, 60 pour convertir en heures et 24 pour convertir en jours. L'expression est encapsulée dans une fonction "Math.round ()" afin qu'elle s'arrondisse à un entier pour le jour de l'année.
Liz Page-Gould

Je dois également ajouter que cette solution est essentiellement la même que la solution «acceptée», sauf qu'elle fait tout dans une seule ligne de code.
Liz Page-Gould

Comment cela tient-il compte de l'heure d'été? Cela ne dérangerait-il pas un peu les choses?
Dan Oswalt

Non, l'heure d'été n'affecterait pas ce calcul, car l'heure d'été a la résolution des heures et ce code calcule le nombre de jours dans l'année. De plus, comme j'ai utilisé la .setHoursméthode sur le premier objet date et spécifié l'heure du jour avec le deuxième objet date, un changement de 1 heure par rapport à l'heure d'été n'affectera pas les heures des objets Date utilisés dans ce calcul.
Liz Page-Gould

4

Je pense que c'est plus simple:

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

Cette méthode prend en compte le problème du fuseau horaire et l'heure d'été

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

(pris d' ici )

Voir aussi ce violon


C'est un peu inefficace, mais cela fonctionne parfaitement. Vous pouvez simplement obtenir l'heure des objets et setDate changer la date au jour 1. Les deux sont parfaitement pris en charge. L'idée est que vous ne vous déplacerez pas dans les fuseaux horaires. Cela suppose également que l'heure d'été est inférieure à 12 heures ... ce qui est une hypothèse sûre sur terre.
Ray Foss

2

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

optimise davantage la réponse.

De plus, en remplaçant ultérieurement setHours (23) ou le dernier mais deux zéro par une autre valeur, le jour de l'année peut être associé à un autre fuseau horaire. Par exemple, pour récupérer depuis l'Europe une ressource située en Amérique.


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

c'est ma solution


J'utilise le 31 décembre de l'année précédente pour faire janvier 01 = DOY 01. J'ai également trouvé que le 10 mars a le même DOY que le 11 mars parce que l'un était 69 et l'autre 69,9 quelque chose, les deux revenant à 69. Faire Math.round a plutôt corrigé ce problème. . Je crois que le 10 mars ou le 11 mars est le changement d'heure d'été, ce qui fait que le 11 mars n'est pas tout à fait DOY 70.
user3015682

0

J'en ai créé un qui est lisible et qui fera l'affaire très rapidement, ainsi que des objets JS Date avec des fuseaux horaires disparates.

J'ai inclus pas mal de cas de test pour les fuseaux horaires, l'heure d'été, les secondes bissextiles et les années bissextiles.

PS ECMA-262 ignore les secondes intercalaires, contrairement à UTC. Si vous deviez le convertir dans une langue qui utilise le vrai UTC, vous pouvez simplement ajouter 1 à 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

Je souhaite proposer une solution qui effectue des calculs en ajoutant les jours de chaque mois précédent:

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

De cette façon, vous n'avez pas à gérer les détails des années bissextiles et de l'heure d'été.


0

Une alternative utilisant les horodatages UTC. De plus, comme d'autres l'ont noté, le jour indiquant le 1er du mois est 1 plutôt que 0. Le mois commence à 0 cependant.

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

Vous pouvez passer le paramètre comme numéro de date dans la setDatefonction:

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

Cela peut être utile à ceux qui ont besoin du jour de l'année sous forme de chaîne et qui disposent de l'interface utilisateur jQuery.

Vous pouvez utiliser jQuery UI Datepicker:

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

En dessous, cela fonctionne de la même manière que certaines des réponses déjà mentionnées ( (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

Pour ceux d'entre nous qui veulent une solution alternative rapide.

(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 taille des mois de l'année et la façon dont fonctionnent les années bissextiles s'intègrent parfaitement pour garder notre temps sur la bonne voie avec le soleil. Heck, cela fonctionne si parfaitement que tout ce que nous faisons est d' ajuster quelques secondes ici et là . Notre système actuel des années bissextiles est en vigueur depuis le 24 février 1582 et le restera probablement dans un avenir prévisible.

L'heure d'été, cependant, est très sujette à changement. Il se peut que dans 20 ans, certains pays décalent le temps d'une journée entière ou d'un autre extrême pour l'heure d'été. Une journée entière DST ne se produira presque certainement jamais, mais DST reste néanmoins très active et indécise. Ainsi, la solution ci-dessus est à l'épreuve du temps en plus d'être très très rapide.

L'extrait de code ci-dessus s'exécute très rapidement. Mon ordinateur peut traiter 65536 dates en ~ 52 ms sur 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

C'est une solution qui évite les problèmes gênants d'objet Date et de fuseau horaire, elle nécessite que votre date d'entrée soit au format "aaaa-jj-mm". Si vous souhaitez changer le format, modifiez la fonction 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

Cela m'inquiète toujours lorsque je mélange les mathématiques avec les fonctions de date (il est si facile de manquer un autre détail d'une année bissextile). Dites que vous avez:

var d = new Date();

Je suggérerais d'utiliser ce qui suit, les jours seront économisés dans day:

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

Je ne vois aucune raison pour laquelle cela ne fonctionnerait pas très bien (et je ne serais pas si inquiet des quelques itérations car cela ne sera pas utilisé de manière aussi intensive).


-1

/ * UTILISEZ CE 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");
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.