JavaScript calcular el día del año (1 - 366)
¿Cómo uso JavaScript para calcular el día del año, del 1 al 366?
Por ejemplo:
3 de enerodebería ser3.1 de febrerodebería ser32.
Respuesta #1
Siguiendo la edición del 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 now sea una fecha entre el 26 de marzo y el 29 de octubre y la hora de now sea antes de la 1AM (por ejemplo, 00:59:59). Esto se debe a que el código no toma en cuenta el horario de verano. Debes 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);Respuesta #2
Me parece muy interesante que nadie haya considerado usar UTC ya que no está sujeto al horario de verano. Por lo 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;
}
Puedes 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
Respuesta #3
Esto funciona a través de los cambios de horario de verano en todos los países (el de "mediodía" de arriba 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;
};
Respuesta #4
Date.prototype.dayOfYear= function(){
var j1= new Date(this);
j1.setMonth(0, 0);
return Math.round((this-j1)/8.64e7);
}
alert(new Date().dayOfYear())
Respuesta #5
Por suerte, esta pregunta no especifica si se requiere el número del día actual, dejando espacio para esta respuesta.
También algunas respuestas (también en otras preguntas) tenían problemas con los años bisiestos o usaban el objeto Date. Aunque el objeto Date de javascript cubre 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 inesperadas de fechas en diferentes navegadores (sobre todo del año 0 al 99). También tenía curiosidad sobre cómo calcularlo.
Así que escribí un algoritmo simple y, sobre todo, pequeño para calcular el día del año correcto (Proleptic Gregorian/Astronómico/ISO 8601:2004 (cláusula 4.3.2.1), por lo que el año 0 existe y es un año bisiesto y se soportan años negativos) basado en año, mes y día.
Ten en cuenta que en la notación AD/BC, el año 0 AD/BC no existe: en su lugar, el año 1 AC es el bisiesto. ¡Si necesitas tener en cuenta la notación AC, simplemente resta un año al valor del año (que de otro modo es positivo) primero!
Modifiqué (para JavaScript) el algoritmo de año bisiesto con máscara de bits y módulo de cortocircuito y se me ocurrió un número mágico para hacer una búsqueda por bits de desplazamientos (que excluye enero y febrero, por lo que se necesitan 10 * 3 bits (30 bits es menos de 31 bits, así que podemos guardar de manera segura otro carácter en el desplazamiento de bits en lugar de >>>)).
Tenga en cuenta que ni el mes ni el día pueden ser 0. Eso significa que si necesita esta ecuación solo para el día actual (alimentándola usando .getMonth()), solo necesita eliminar el -- 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 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>De nuevo, una línea, pero la dividí en 3 líneas para mayor legibilidad (y siguiendo la explicación).
La última línea es idéntica a la función anterior, sin embargo, el algoritmo (idéntico) de año bisiesto se mueve a una sección anterior de corte corto (antes del cálculo del número de día), porque también se necesita para saber cuántos días tiene un mes en un año (bisiesto) dado.
La línea del medio calcula el número correcto de desplazamiento (para el número máximo de días) de un mes dado en un año (bisiesto) dado usando otro número mágico: dado que 31-28=3 y 3 son solo 2 bits, entonces 12*2=24 bits, podemos almacenar los 12 meses. Como la suma puede ser más rápida que la resta, añadimos el desplazamiento (en lugar de restarlo de 31). Para evitar una rama de decisión de año bisiesto para febrero, modificamos ese número mágico de búsqueda sobre la marcha.
Eso nos deja con la primera línea (bastante obvia): verifica que el mes y el día estén dentro de los límites válidos y nos asegura con un false como valor de retorno en caso de error de rango (nota que esta función tampoco debería poder devolver 0, porque el 1 de enero del año 0000 sigue siendo el día 1), proporcionando una comprobación de errores sencilla: if(r=dayNo(/*y, m, d*/)){}.
Si se usa de esta manera (donde el mes y el día no pueden ser 0), entonces se puede cambiar --m>=0 && m<12 a m>0 && --m<12 (ahorrando otro carácter).
La razón por la que escribí el fragmento en su forma actual es que para valores de mes basados en 0, solo se necesita eliminar el -- de --m.
Extra:
Nota, no uses el algoritmo por día del mes si solo necesitas el máximo de días por mes. En ese caso hay un algoritmo más eficiente (porque solo necesitamos el año bisiesto cuando el mes es febrero) que publiqué como respuesta a esta pregunta: ¿Cuál es la mejor manera de determinar el número de días en un mes con JavaScript?.
