Javascript calcular o dia do ano (1 – 366)

Como eu uso o JavaScript para calcular o dia do ano, de 1 a 366? Por exemplo:

  • 3 de janeiro deve ser 3 .
  • 1 de fevereiro deve ser 32 .

Seguindo a edição do 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); 

Isso funciona em todas as mudanças de horário de verão em todos os países (o “meio dia” acima não funciona na Austrália):

 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; }; 
 Date.prototype.dayOfYear= function(){ var j1= new Date(this); j1.setMonth(0, 0); return Math.round((this-j1)/8.64e7); } alert(new Date().dayOfYear()) 

Felizmente, essa pergunta não especifica se o número do dia atual é necessário, deixando espaço para essa resposta.
Além disso, algumas respostas (também sobre outras questões) tiveram problemas bissextos ou usaram o object Date. Embora o Date object do javascript tenha aproximadamente 285616 anos (100.000.000 de dias) em ambos os lados de 1 de janeiro de 1970, eu estava farto de todos os tipos de inconsistências de datas inesperadas em diferentes navegadores (principalmente do ano 0 a 99). Eu também estava curioso para saber como calcular isso.

Então eu escrevi um algoritmo simples e, acima de tudo, pequeno para calcular o correto ( Proleptic Gregorian / Astronomical / ISO 8601: 2004 (cláusula 4.3.2.1), então ano 0 existe e é um ano bissexto e anos negativos são suportados ) dia do ano com base no ano , mês e dia .
Observe que na notação AD/BC , o ano 0 AD / BC não existe: em vez disso, o ano 1 BC é o ano bissexto! Se você precisa considerar a notação BC, simplesmente subtraia primeiro um ano do valor do ano (senão positivo) !!

Eu modifiquei (para javascript) o algoritmo bitmask-módulo de curto-circuito leapYear e criei um número mágico para fazer uma busca bit-wise de offsets (que exclui jan e feb, precisando de 10 * 3 bits (30 bits é menor que 31 bits, para que possamos salvar com segurança outro caractere no bit shift em vez de >>> )).

Observe que nenhum mês ou dia pode ser 0 . Isso significa que se você precisar dessa equação apenas para o dia atual (alimentando-a usando .getMonth() ), basta remover o -- de -- --m .

Observe que isso pressupõe uma data válida (embora a verificação de erros seja apenas mais alguns caracteres).

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


Acho muito interessante que ninguém tenha considerado o uso do UTC, uma vez que não está sujeito a DST. Portanto, proponho o seguinte:

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

Você pode testá-lo com o seguinte:

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

Quais são as saídas para o ano bissexto de 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 

Bem, se eu entendi corretamente, você quer 366 em um ano bissexto, 365 caso contrário, certo? Um ano é um ano bissexto se for divisível por 4, mas não por 100, a menos que também seja divisível 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 após atualização:

Nesse caso, não acho que exista um método embutido; você precisará fazer isso:

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

(Sim, eu realmente fiz isso sem copiar ou colar. Se há uma maneira fácil eu vou ficar bravo)

Esta é uma maneira simples de encontrar o dia atual do ano e deve ser responsável por anos bissextos sem um problema:

Javascript:

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

Javascript no script do Google Apps:

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

A principal ação desse código é encontrar o número de milissegundos que se passaram no ano atual e depois converter esse número em dias. O número de milissegundos que se passaram no ano atual pode ser encontrado ao subtrair o número de milissegundos do primeiro segundo do primeiro dia do ano atual, que é obtido com a new Date(new Date().getYear()+1900, 0, 1, 0, 0, 0) (Javascript) ou new Date(new Date().getYear(), 0, 1, 0, 0, 0) (Script do Google Apps), a partir dos milissegundos da 23ª hora do dia atual, que foi encontrado com a new Date().setHours(23) . O objective de definir a data atual para a 23ª hora é garantir que o dia do ano seja arredondado corretamente por Math.round() .

Depois de ter o número de milissegundos do ano atual, você pode converter esse tempo em dias dividindo por 1000 para converter milissegundos em segundos, dividindo em 60 para converter segundos em minutos e dividindo em 60 para converter minutos em horas, e finalmente dividindo por 24 para converter horas em dias.

Nota: esta publicação foi editada para contabilizar as diferenças entre JavaScript e JavaScript implementadas no Script do Google Apps. Além disso, mais contexto foi adicionado para a resposta.

Este método leva em consideração o fuso horário e o horário de verão

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

(tirou daqui )

Veja também este violino

Math.round ((nova Data (). SetHours (23) – nova Data (nova Data (). GetFullYear (), 0, 1, 0, 0, 0)) / 1000/86400);

otimiza ainda mais a resposta.

Além disso, alterando setHours (23) ou o último, mas dois zero, posteriormente, para outro valor, pode fornecer o dia do ano relacionado a outro fuso horário. Por exemplo, para recuperar da Europa, um recurso localizado na América.

Se você não quiser reinventar a roda, você pode usar a 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 

Eu fiz um que é legível e vai fazer o truque muito rapidamente, bem como manipular objects JS Date com fusos horários diferentes.

Eu incluí alguns casos de teste para fusos horários, DST, segundos bissextos e anos bissextos.

O PS ECMA-262 ignora os segundos bissextos, ao contrário do UTC. Se você fosse converter isso em um idioma que usa o UTC real, você poderia adicionar 1 a um 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" ); 

Gostaria de fornecer uma solução que faça cálculos adicionando os dias para cada mês 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)); 

Uma alternativa usando registros de data e hora UTC. Além disso, como outros observaram, o dia que indica 1o mês é 1, em vez de 0. O mês começa em 0, no entanto.

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

/ * USE ESTE 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"); 

Você pode passar o parâmetro como o número da data na function setDate :

 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) 

Eu acho que isso é mais simples:

 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! 

Sempre me preocupa quando misturo matemática com funções de data (é tão fácil perder algum detalhe bissexto). Diga que você tem:

 var d = new Date(); 

Sugiro usar o seguinte, os dias serão salvos no day :

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

Não consigo ver nenhuma razão pela qual isso não funcionaria muito bem (e eu não ficaria tão preocupado com as poucas iterações, já que isso não será usado tão intensamente).