Javascript calcula el día del año (1-366)

118

¿Cómo uso javascript para calcular el día del año, de 1 a 366? Por ejemplo:

  • El 3 de enero debería ser el 3 .
  • El 1 de febrero debería ser 32 .
Kirk Woll
fuente
4
var days = new Date().getFullYear() % 4 == 0 ? 366 : 365;
Alex Turpin
Pero realmente no estoy seguro de a qué te refieres. ¿Solo quiere la cantidad de días del año? ¿O entre dos citas?
Alex Turpin
16
fyi @ xeon06, el cálculo del año bisiesto es un poco más complicado que la modificación por 4. ver: algoritmo de año bisiesto
Matt Felzani
4
@ Xeon06: Eso es correcto solo la mayoría de las veces. De Wikipedia : Los años que son divisibles por 100 no son años bisiestos, a menos que también sean divisibles por 400, en cuyo caso son años bisiestos.
Cameron
Ah, bueno, me corrijo. @minitech parece tener la respuesta correcta entonces.
Alex Turpin

Respuestas:

137

Siguiendo la edición 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);

Editar: El código anterior fallará cuando nowsea ​​una fecha entre el 26 de marzo y el 29 de octubre y nowla hora sea antes de la 1AM (por ejemplo, 00:59:59). Esto se debe a que el código no tiene en cuenta el horario de verano. Deberías compensar esto:

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
fuente
5
Math.floorconstantemente me dio un resultado de 1 día menos de lo esperado después de cierto día de abril. Math.ceilfuncionó como se esperaba, pero he visto que se recomienda que use en Math.roundlugar de cualquiera.
baacke
3
El componente de día es base-1. es decir, para representar el 1 de enero de este año, usaría new Date(2014, 0, 1), y no new Date(2014, 0, 0)como lo tiene aquí. ¿Es eso intencional? Quizás eso es lo que explica estar fuera por un día como new Date(2014, 0, 0)volverá 12/31/2013.
Kirk Woll
1
Tal vez use .setUTCHoursy Date.UTC()para una solución más confiable.
Noyo
6
@AlexTurpin, @ T30: Sé que esto es un poco antiguo, pero si se pregunta ... el problema se debe al horario de verano que comienza en marzo. Esto se debe a que cuando toma la diferencia entre la medianoche de una fecha antes del horario de verano y la medianoche de una fecha posterior al horario de verano, no tendrá un número de milisegundos divisible uniformemente por 1000 * 60 * 60 * 24 (será exactamente una hora de descuento) . La solución más fácil es usar en ceillugar de floor, esto le dará un sistema de numeración donde 1 de enero = 1. Si quiere 1 de enero = 0 (como floorle daría), simplemente reste 1 de su resultado final.
Warren R.
2
Para tener en cuenta las zonas horarias y el horario de verano, cambie la línea 3 a: var diff = now - start + (start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000;
Marlon
46

Esto funciona con los cambios del horario de verano en todos los países (el "mediodía" anterior no funciona en 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;
};
Joe Orost
fuente
1
Acepte que hay errores relacionados con el horario de verano en la respuesta aceptada. La solución anterior es mejor y más rápida. Aquí hay una variación que probé en jsPerf jsperf.com/date-getdayofyear-perf
Shyam Habarakada
@ShyamHabarakada: el código en su punto de referencia está roto, getDay()debe cambiarse a getDate(). El primero devuelve el día de la semana (0 = domingo..6 = sábado), no el día.
CodeManX
32

Me parece muy interesante que nadie haya considerado usar UTC ya que no está sujeto a DST. Por tanto, propongo lo siguiente:

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

Puede probarlo con lo siguiente:

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

Qué salidas para el año bisiesto 2016 (verificado usando 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
usuario2501097
fuente
Esto podría desbordarse porque el número de milisegundos es demasiado grande.
knt5784
@ knt5784 Las matemáticas podrían desbordarse, pero su ejemplo muestra el mayor valor posible en el mundo real funcionando bien, por lo que debería estar bien usando esto a menos que haya un problema basado en el navegador con desbordamiento de enteros.
Per Fagrell
Personalmente, me gusta este enfoque. Una forma mucho más limpia (¡y muy inteligente!) De evitar problemas con el horario de verano. Si alguien se pregunta cómo convertir DOY hasta la fecha, es mucho más simple. Básicamente, solo crea una fecha de enero DOYth. Por ejemplo, 59 de enero = 28 de febrero. El día bisiesto se maneja bien. function doyToDate(doy, year) { return new Date(year, 0, doy); }
Kip
@ knt5784 No hay riesgo de desbordamiento de milisegundos con este código, al menos no durante otros 200.000 años. La fecha más grande admitida por Date es new Date(8640000000000000), que aún es menor que Number.MAX_SAFE_INTEGER. vea esta respuesta: 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())
Kennebec
fuente
3
Esto no pasaría pelusa ... Modificando un objeto que no es tuyo, especialmente uno global. Esto también fallaría en planetas con inclinación extrema donde el horario de verano es superior a 12 horas. Pero de manera más realista, si está codificando un navegador que permita cambiar la zona horaria del objeto Date, la zona horaria de j1 podría ser Australia y esta podría ser Alaska, rompiendo el redondeo.
Ray Foss
11

Afortunadamente, esta pregunta no especifica si se requiere el número del día actual , dejando espacio para esta respuesta.
Además, algunas respuestas (también en otras preguntas) tenían problemas de años bisiestos o usaban el objeto Date. Aunque javascript Date objectcubre aproximadamente 285616 años (100,000,000 días) a ambos lados del 1 de enero de 1970, estaba harto de todo tipo de inconsistencias de fechas inesperadas en diferentes navegadores (especialmente del año 0 al 99). También tenía curiosidad por saber cómo calcularlo.

Así que escribí un algoritmo simple y, sobre todo, pequeño para calcular el día correcto ( Proleptic Gregorian / Astronomical / ISO 8601: 2004 (cláusula 4.3.2.1), por lo que el año0 existe y es un año bisiesto y se admiten años negativos ) del año basado en año , mes y día .
Tenga en cuenta que en la AD/BCnotación, el año 0 AD / BC no existe: en su lugar, el año1 BC es el año bisiesto! SI necesita tener en cuenta la notación BC, entonces simplemente reste un año del valor anual (de lo contrario positivo) primero.

Modifiqué (para javascript) el algoritmo de cortocircuito bitmask-modulo leapYear y se me ocurrió un número mágico para hacer una búsqueda bit a bit de compensaciones (que excluye jan y feb, por lo que necesita 10 * 3 bits (30 bits es menos que 31 bits, por lo que podemos guardar con seguridad otro carácter en el desplazamiento de bits en lugar de >>>)).

Tenga en cuenta que ni el mes ni el día pueden serlo 0. Eso significa que si necesita esta ecuación solo para el día actual (alimentándola usando .getMonth()) solo necesita quitar la --de --m.

Tenga en cuenta que esto asume una fecha válida (aunque la verificación de errores es solo algunos caracteres más).

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>


Aquí está la versión con la validación de rango correcta .

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>

Nuevamente, una línea, pero la dividí en 3 líneas para facilitar la lectura (y la siguiente explicación).

La última línea es idéntica a la función anterior, sin embargo, el algoritmo leapYear (idéntico) se mueve a una sección de cortocircuito anterior (antes del cálculo del número de días), porque también es necesario saber cuántos días tiene un mes en un año (bisiesto) dado.

La línea central calcula el número de compensación correcto (para el número máximo de días) para un mes dado en un año (bisiesto) dado usando otro número mágico: dado que 31-28=3y 3es solo 2 bits, luego 12*2=24bits, podemos almacenar los 12 meses. Como la suma puede ser más rápida que la resta, sumamos el desplazamiento (en lugar de restarlo de31 ). Para evitar una rama de decisión de año bisiesto para febrero, modificamos ese número de búsqueda mágico sobre la marcha.

Eso nos deja con la primera línea (bastante obvia): verifica que el mes y la fecha estén dentro de los límites válidos y nos asegura un falsevalor de retorno en el error de rango (tenga en cuenta que esta función tampoco debería poder devolver 0, porque el 1 de enero de 0000 sigue siendo el día 1.), que proporciona un fácil comprobación de errores: if(r=dayNo(/*y, m, d*/)){}.
Si se usa de esta manera (donde el mes y el día pueden no serlo 0), entonces se puede cambiar --m>=0 && m<12a m>0 && --m<12(guardar otro carácter).
La razón por la que escribí el fragmento en su forma actual es que para los valores de mes basados ​​en 0, uno solo necesita eliminar el --de--m .

Extra:
Tenga en cuenta que no utilice el algoritmo de este día por mes si solo necesita el máximo de días por mes. En ese caso, hay un algoritmo más eficiente (porque solo necesitamos leepYear cuando el mes es febrero) que publiqué como respuesta a esta pregunta: ¿Cuál es la mejor manera de determinar la cantidad de días en un mes con javascript? .

GitaarLAB
fuente
1
Lo puse en una función de fecha para facilitar su uso. De acuerdo, las inconsistencias de Date () siguen siendo un problema, pero estoy usando años 2015+, así que espero que sean consistentes. El pobre JSHint murió tratando de validar su código jaja. 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
Me alegro de que te haya gustado. Este algoritmo se prueba completamente durante 2 ^ 31-1 años (la friolera de 2147483647, eso es> 7500 veces el rango del objeto de fecha de javascript) en ambos lados de 0. ( Podría funcionar para 2 ^ 32, pero no lo he probado todavía). Además, es posible leer de nuevo mi respuesta: puedes afeitar +1de this.getMonth()+1si se quita el --de --m. EDITAR Entonces, haría (para una biblioteca):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
¡De hecho, solo hice eso cuando lo estaba mirando! Me di cuenta de que estaba sumando uno y luego restando de inmediato. Creo que para cuando lleguemos a 2^31 - 2016años a partir de ahora, js probablemente estará un poco desactualizado.
freshvolk
@Freshvolk: lol, que es por eso que nunca lo probé más allá de 2 ^ 31 :)Pero hasta entonces, al menos dará resultados predecibles y consistentes jaja. EDITAR , solo por el bien de la teoría, utilizando el algoritmo todo módulo convencional más lento para el año bisiesto, el rango se puede extender a 2 ^ 53. El algoritmo de búsqueda de meses no es el factor limitante.
GitaarLAB
5

Si no desea reinventar la rueda, puede usar la excelente biblioteca date- fns (node.js):

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

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

Bueno, si te entiendo correctamente, quieres 366 en un año bisiesto, 365 de lo contrario, ¿verdad? Un año es bisiesto si es divisible uniformemente por 4, pero no por 100, a menos que también sea divisible por 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;
    }
}

Editar después de la actualización:

En ese caso, no creo que haya un método incorporado; necesitarás hacer esto:

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í, en realidad hice eso sin copiar ni pegar. Si hay una manera fácil, me enojaré)

Ry-
fuente
Mi manera más fácil es usar el número mágico 1054267675 y llamarlo un día, soy muy vago para escribir todo eso:)
GitaarLAB
4

Esta es una forma sencilla de encontrar el día actual del año, y debería contabilizar los años bisiestos sin ningún problema:

Javascript:

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

Javascript en Google Apps Script:

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

La acción principal de este código es encontrar el número de milisegundos que han transcurrido en el año actual y luego convertir este número en días. La cantidad de milisegundos que han transcurrido en el año en curso se puede encontrar restando la cantidad de milisegundos del primer segundo del primer día del año en curso, que se obtiene 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), de los milisegundos de la hora 23 del día actual, que se encontró con new Date().setHours(23). El propósito de establecer la fecha actual en la hora 23 es garantizar que el día del año se redondea correctamente por Math.round().

Una vez que tenga la cantidad de milisegundos del año actual, puede convertir este tiempo en días dividiendo por 1000 para convertir milisegundos en segundos, luego dividiendo por 60 para convertir segundos en minutos, luego dividiendo por 60 para convertir minutos en horas. y finalmente dividir por 24 para convertir las horas en días.

Nota: esta publicación se editó para tener en cuenta las diferencias entre JavaScript y JavaScript implementados en Google Apps Script. Además, se agregó más contexto para la respuesta.

Liz Page-Gould
fuente
¿Puede explicar un poco más que solo decir que está funcionando?
Stephen Reindl
¡Si! Lamento no haber proporcionado más detalles en primer lugar. La expresión dentro de la instrucción "Math.round" encuentra el número de milisegundos del año actual restando el primer día del año de los milisegundos de la última hora del día actual del año. El número de milisegundos se divide por 1000 para convertir a segundos, 60 para convertir a minutos, 60 para convertir a horas y 24 para convertir a días. La expresión está envuelta dentro de una función "Math.round ()" para que se redondea a un número entero para el día del año.
Liz Page-Gould
También debo agregar que esta solución es esencialmente la misma que la solución "aceptada", excepto que hace todo en una línea de código.
Liz Page-Gould
¿Cómo tiene esto en cuenta el horario de verano? ¿No lo desanimaría un poco?
Dan Oswalt
No, el horario de verano no afectaría este cálculo, porque el horario de verano tiene la resolución de horas y este código calcula el número de días del año. Además, debido a que utilicé el .setHoursmétodo en el primer objeto de fecha y especifiqué la hora del día con el segundo objeto de fecha, un cambio de 1 hora desde el horario de verano no afectará las horas de los objetos de fecha utilizados en este cálculo.
Liz Page-Gould
4

Creo que esto es más sencillo:

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
fuente
3

Este método tiene en cuenta el problema de la zona horaria y el horario de verano

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

(tomado de aquí )

Ver también este violín

Andriy F.
fuente
Esto es un poco ineficiente, pero funciona perfectamente. Podría obtener la hora de los objetos y setDate cambiar la fecha al día 1. Ambos son perfectamente compatibles. La idea es que no te muevas por zonas horarias. Esto también supone que el horario de verano es inferior a 12 horas ... lo cual es una suposición segura en la tierra.
Ray Foss
2

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

optimiza aún más la respuesta.

Además, al cambiar setHours (23) o el último cero menos dos más adelante a otro valor, puede proporcionar el día del año relacionado con otra zona horaria. Por ejemplo, para recuperar de Europa un recurso ubicado en América.

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

esta es mi solucion

Juegalo
fuente
Utilizo el 31 de diciembre del año anterior para hacer el 01 de enero = DOY 01. También descubrí que el 10 de marzo tiene el mismo DOY que el 11 de marzo porque uno tenía 69 y el otro 69.9 algo, ambos pisos a 69. Hacer Math.round solucionó esto . Creo que el 10 de marzo o el 11 de marzo es el cambio de horario de verano que hace que el 11 de marzo no sea exactamente DOY 70.
user3015682
0

He creado uno que es legible y funcionará muy rápidamente, además de manejar objetos JS Date con zonas horarias dispares.

He incluido bastantes casos de prueba para zonas horarias, DST, segundos bisiestos y años bisiestos.

PS ECMA-262 ignora los segundos intercalares, a diferencia de UTC. Si tuviera que convertir esto a un idioma que usa UTC real, podría simplemente agregar 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"
);

Ray Foss
fuente
0

Me gustaría proporcionar una solución que haga cálculos sumando los días de cada mes anterior:

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 esta manera, no tiene que administrar los detalles de los años bisiestos y el horario de verano.

manix
fuente
0

Una alternativa que usa marcas de tiempo UTC. Además, como otros señalaron, el día que indica el primer mes es 1 en lugar de 0. Sin embargo, el mes comienza en 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
fuente
0

Puede pasar el parámetro como número de fecha en la setDatefunción:

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
fuente
0

Esto podría ser útil para aquellos que necesitan el día del año como una cadena y tienen jQuery UI disponible.

Puede usar jQuery UI Datepicker:

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

Debajo funciona de la misma manera que algunas de las respuestas ya mencionadas ( (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.
fuente
0

Para aquellos entre nosotros que quieren una solución alternativa rápida.

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

El tamaño de los meses del año y la forma en que funcionan los años bisiestos encajan perfectamente para mantener nuestro tiempo encaminado con el sol. Demonios, funciona tan perfectamente que todo lo que hacemos es ajustar unos segundos aquí y allá . Nuestro sistema actual de años bisiestos ha estado en vigor desde el 24 de febrero de 1582. y probablemente permanecerá en vigor en el futuro previsible.

Sin embargo, el horario de verano está muy sujeto a cambios. Puede ser que dentro de 20 años, algún país pueda compensar el tiempo por un día completo o algún otro extremo para el horario de verano. Es casi seguro que nunca sucederá un día completo de DST, pero el DST sigue estando muy en el aire e indeciso. Por lo tanto, la solución anterior está preparada para el futuro, además de ser muy, muy rápida.

El fragmento de código anterior se ejecuta muy rápido. Mi computadora puede procesar 65536 fechas en ~ 52 ms en Chrome.

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

usuario7331530
fuente
0

Esta es una solución que evita los problemas problemáticos con el objeto Date y la zona horaria, requiere que la fecha de entrada tenga el formato "aaaa-dd-mm". Si desea cambiar el formato, modifique la función 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
fuente
-1

Siempre me preocupa cuando se mezclan las matemáticas con las funciones de fecha (es muy fácil pasar por alto algún otro detalle del año bisiesto). Di que tienes:

var d = new Date();

Sugeriría usar lo siguiente, los días se guardarán en day:

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

No veo ninguna razón por la que esto no funcionaría bien (y no estaría tan preocupado por las pocas iteraciones ya que esto no se usará tan intensamente).

Martin Ekblom
fuente
-1

/ * USE ESTE GUIÓN * /

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
fuente