Javascript calcula o dia do ano (1 - 366)

118

Como faço para usar 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 .
Kirk Woll
fonte
4
var days = new Date().getFullYear() % 4 == 0 ? 366 : 365;
Alex Turpin
Mas realmente não tenho certeza do que você quer dizer. Você quer apenas o número de dias do ano? Ou entre duas datas?
Alex Turpin
16
fyi @ xeon06, o cálculo do ano bissexto é um pouco mais complicado do que mod'ing por 4. veja: algoritmo de ano bissexto
Matt Felzani
4
@ Xeon06: Isso é correto apenas na maioria das vezes. Da Wikipedia : anos que são igualmente divisíveis por 100 não são anos bissextos, a menos que também sejam igualmente divisíveis por 400, caso em que são anos bissextos.
Cameron
Bem, estou corrigido. @minitech parece ter a resposta certa então.
Alex Turpin

Respostas:

137

Após 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);

Editar: O código acima falhará quando nowfor uma data entre 26 de março e 29 de outubro e nowa hora for anterior à 1h (por exemplo, 00:59:59). Isso ocorre porque o código não leva em consideração o horário de verão. Você deve compensar por isso:

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
fonte
5
Math.floorconsistentemente me deu um resultado de 1 dia a menos do que o esperado após um determinado dia de abril. Math.ceilfuncionou conforme o esperado, mas vi que é aconselhável que você use em Math.roundvez de qualquer um.
baacke de
3
O componente de dia é base-1. ou seja, para representar 1º de janeiro deste ano, você usaria new Date(2014, 0, 1), e não new Date(2014, 0, 0)como aqui. Isso é intencional? Talvez seja isso o que explica estar um dia fora, pois new Date(2014, 0, 0)vai voltar 12/31/2013.
Kirk Woll
1
Talvez use .setUTCHourse Date.UTC()para uma solução mais confiável.
Noyo
6
@AlexTurpin, @ T30: Eu sei que isso é um pouco antigo, mas se você estava se perguntando ... o problema é causado por causa do horário de verão que começa em março. Isso ocorre porque, quando você tira a diferença de meia-noite de uma data antes do horário de verão e meia-noite de uma data depois do horário de verão, você não terá um número de milissegundos divisível por 1000 * 60 * 60 * 24 (será exatamente uma hora de diferença) . A solução mais fácil é usar, em ceilvez de floor, isso lhe dará um sistema de numeração onde 1º de janeiro = 1. Se você quiser 1º de janeiro = 0 (como floorlhe daria), apenas subtraia 1 de seu resultado final.
Warren R.
2
Para levar em conta os fusos horários e o horário de verão, altere a linha 3 para: var diff = now - start + (start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000;
Marlon
46

Isso funciona em todas as mudanças do 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;
};
Joe Orost
fonte
1
Concorde que há erros relacionados ao horário de verão na resposta aceita. A solução acima é melhor e mais rápida. Aqui está uma variação dele que testei em jsPerf jsperf.com/date-getdayofyear-perf
Shyam Habarakada
@ShyamHabarakada: o código em seu benchmark está quebrado, getDay()precisa ser alterado para getDate(). O primeiro retorna o dia da semana (0 = domingo..6 = sábado), não o dia.
CodeManX de
32

Acho muito interessante que ninguém pensou em usar UTC, uma vez que não está sujeito ao 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 resultados 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
user2501097
fonte
Isso pode estourar porque o número de milissegundos é muito grande.
knt5784
@ knt5784 A matemática pode ser capaz de estourar, mas seu exemplo mostra o maior valor possível do mundo real funcionando bem, então você deve estar ok usando isso, a menos que haja um problema com o navegador com estouro de inteiro.
Por Fagrell de
Eu pessoalmente gosto dessa abordagem. Maneira muito mais limpa (e muito inteligente!) De evitar problemas de horário de verão. Se alguém está se perguntando como converter do DOY de volta à data, é muito mais simples. Basicamente, você acabou de criar uma data de janeiro DOYth. Por exemplo, 59 de janeiro === 28 de fevereiro. O dia bissexto é bem tratado. function doyToDate(doy, year) { return new Date(year, 0, doy); }
Kip
@ knt5784 Não há risco de estouro de milissegundos com este código, pelo menos não por mais 200.000 anos. A maior data suportada por Date é new Date(8640000000000000), que ainda é menor que Number.MAX_SAFE_INTEGER. veja esta resposta: 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
fonte
3
Isso não passaria lint ... Modificar um objeto que não é seu, principalmente um global. Isso também falharia em planetas com inclinação extrema, onde o horário de verão é superior a 12 horas. Porém, de forma mais realista, se você estiver codificando para um navegador que permite alterar o fuso horário do objeto Date, o fuso horário de j1 pode ser Austrália e este fuso horário pode ser Alasca, quebrando o arredondamento.
Ray Foss
11

Felizmente esta questão não especifica se o número do dia atual é obrigatório, deixando espaço para esta resposta.
Além disso, algumas respostas (também sobre outras questões) tiveram problemas de ano bissexto ou usaram o objeto Data. Embora o javascript Date objectcubra aproximadamente 285616 anos (100 milhões de dias) em ambos os lados de 1º de janeiro de 1970, eu estava farto de todos os tipos de inconsistências de data inesperadas em navegadores diferentes (principalmente do ano 0 a 99). Eu também estava curioso para saber como calculá-lo.

Então eu escrevi um algoritmo simples e, acima de tudo, pequeno para calcular o dia do ano correto ( Proléptico Gregoriano / Astronômico / ISO 8601: 2004 (cláusula 4.3.2.1), então ano0 existe e é um ano bissexto e anos negativos são suportados ) com base no ano , mês e dia .
Observe que, em AD/BCnotação, o ano 0 AD / BC não existe: em vez disso, o ano 1 BCé o ano bissexto! SE você precisar contabilizar a notação BC, simplesmente subtraia um ano do valor do ano (caso contrário positivo) primeiro !!

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

Observe que nem o mês nem o dia podem ser 0. Isso significa que se você precisa dessa equação apenas para o dia atual (alimentando-a usando .getMonth()), você só precisa 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;
}
<!-- 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>


Aqui está a versão com validação de intervalo correta .

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>

Novamente, uma linha, mas eu dividi em 3 linhas para facilitar a leitura (e a explicação seguinte).

A última linha é idêntica à função acima, no entanto, o algoritmo leapYear (idêntico) é movido para uma seção de curto-circuito anterior (antes do cálculo do número do dia), porque também é necessário saber quantos dias um mês tem em um dado ano (bissexto).

A linha do meio calcula o número de deslocamento correto (para o número máximo de dias) para um determinado mês em um determinado ano (bissexto) usando outro número mágico: como 31-28=3e 3tem apenas 2 bits, então 12*2=24bits, podemos armazenar todos os 12 meses. Como a adição pode ser mais rápida do que a subtração, adicionamos o deslocamento (em vez de subtraí-lo 31). Para evitar um ramo de decisão de ano bissexto para fevereiro, modificamos esse número de pesquisa mágico instantaneamente.

Isso nos deixa com a (bastante óbvia) primeira linha: ela verifica se o mês e a data estão dentro dos limites válidos e nos garante um falsevalor de retorno no erro de intervalo (observe que esta função também não deve ser capaz de retornar 0, porque 1 jan 0000 ainda é dia 1.), proporcionando fácil verificação de erros: if(r=dayNo(/*y, m, d*/)){}.
Se usado desta forma (onde mês e dia podem não ser 0), então um pode mudar --m>=0 && m<12para m>0 && --m<12(salvando outro caractere).
O motivo pelo qual digitei o snippet em sua forma atual é que para valores de mês baseados em 0, basta remover o --de --m.

Extra:
Nota, não use este algoritmo de dias por mês se você precisa apenas de no máximo dias por mês. Nesse caso existe um algoritmo mais eficiente (porque só precisamos do leepYear quando o mês é fevereiro). Postei como resposta a esta pergunta: Qual é a melhor forma de determinar o número de dias de um mês com javascript? .

GitaarLAB
fonte
1
Eu o coloquei em uma função de data para facilitar o uso. As inconsistências de Date () ainda são um problema, mas estou usando os anos de 2015+, então espero que sejam consistentes. O pobre JSHint morreu tentando validar seu código 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
Que bom que gostou. Este algo é totalmente testado por 2 ^ 31-1 anos (uma gritante 2147483647, que de> 7500 vezes o alcance da data-objeto de javascript) em ambos os lados 0. (Ele pode trabalhar para 2 ^ 32, mas eu não testei que ainda). Além disso, você pode ler a minha resposta novamente: você pode raspar +1de this.getMonth()+1se remover a --partir --m. EDITAR Então, eu faria (para uma 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
Na verdade, eu só fiz isso quando estava olhando para ele! Percebi que estava adicionando um e subtraindo imediatamente. Acho que quando chegarmos aos 2^31 - 2016anos, o js provavelmente estará um pouco desatualizado.
freshvolk
@Freshvolk: lol, é por isso que eu nunca testei além de 2 ^ 31 :)Mas até então, pelo menos dará resultados previsíveis e consistentes haha. EDITAR , apenas por uma questão de teoria, usando o algoritmo de módulo convencional mais lento para ano bissexto, o intervalo pode ser estendido para 2 ^ 53. O algoritmo de pesquisa de mês não é o fator limitante.
GitaarLAB
5

Se 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
Amaury Liet
fonte
4

Bem, se bem entendi, você quer 366 em um ano bissexto, 365 caso contrário, certo? Um ano é um ano bissexto se for igualmente 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 haja 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, na verdade fiz isso sem copiar ou colar. Se houver uma maneira fácil, ficarei bravo)

Ry-
fonte
Minha maneira fácil é usar o número mágico 1054267675 e encerrar o dia, sou muito preguiçoso para digitar tudo isso:)
GitaarLAB
4

Esta é uma maneira simples de encontrar o dia atual do ano e deve representar os anos bissextos sem problemas:

Javascript:

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

Javascript no Google Apps Script:

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 decorridos no ano atual e, em seguida, converter esse número em dias. O número de milissegundos decorridos no ano atual pode ser encontrado subtraindo o número de milissegundos do primeiro segundo do primeiro dia do ano atual, que é obtido com new Date(new Date().getYear()+1900, 0, 1, 0, 0, 0)(Javascript) ounew Date(new Date().getYear(), 0, 1, 0, 0, 0) (Google Apps Script), dos milissegundos da 23ª hora do dia atual, que foi encontrado com new Date().setHours(23). O objetivo de definir a data atual para a 23ª hora é garantir que o dia do ano seja arredondado corretamente por Math.round().

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

Observação: esta postagem foi editada para explicar as diferenças entre JavaScript e JavaScript implementado no Google Apps Script. Além disso, mais contexto foi adicionado para a resposta.

Liz Page-Gould
fonte
Você pode explicar um pouco mais do que apenas dizer que está funcionando?
Stephen Reindl,
Sim! Lamento não ter fornecido mais detalhes em primeiro lugar. A expressão dentro da instrução "Math.round" encontra o número de milissegundos no ano atual subtraindo o primeiro dia do ano dos milissegundos da última hora do dia atual do ano. O número de milissegundos é dividido por 1000 para converter para segundos, 60 para converter para minutos, 60 para converter para horas e 24 para converter para dias. A expressão é agrupada em uma função "Math.round ()" para que seja arredondada para um número inteiro no dia do ano.
Liz Page-Gould
Devo também acrescentar que essa solução é essencialmente igual à solução "aceita", exceto que faz tudo em uma linha de código.
Liz Page-Gould,
Como isso contabiliza o horário de verão? Isso não iria confundir um pouco?
Dan Oswalt
Não, o horário de verão não afetaria esse cálculo, pois o horário de verão tem a resolução de horas e esse código está calculando o número de dias do ano. Além disso, como usei o .setHoursmétodo no primeiro objeto de data e especifiquei a hora do dia com o segundo objeto de data, uma alteração de 1 hora do horário de verão não afetará os horários dos objetos Date usados ​​neste cálculo.
Liz Page-Gould
4

Acho que é 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!
Sean
fonte
3

Este método leva em consideração a questão do 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; 
}

(tirado daqui )

Veja também este violino

Andriy F.
fonte
Isso é um pouco ineficiente, mas funciona perfeitamente. Você poderia apenas obter os objetos de tempo e setDate alterar a data para o dia 1. Ambos são perfeitamente compatíveis. A ideia é que você não mudará de fuso horário. Isso também pressupõe que o horário de verão é inferior a 12 horas ... o que é uma suposição segura na Terra.
Ray Foss
2

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

otimiza ainda mais a resposta.

Além disso, alterando setHours (23) ou o last-but-two 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.

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

esta é a minha solução

Jogue
fonte
Eu uso 31 de dezembro do ano anterior para fazer 01 de janeiro = 01 DOY. Também descobri que 10 de março tem o mesmo DOY de 11 de março porque um tinha 69 e o outro 69,9 alguma coisa, ambos com piso de 69. Fazer Math.round corrigiu isso . Eu acredito que 10 de março ou 11 de março é a mudança do horário de verão que faz com que 11 de março não seja exatamente 70 DOY.
usuário3015682
0

Fiz um que é legível e fará o truque muito rapidamente, além de lidar com objetos JS Date com fusos horários diferentes.

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

PS ECMA-262 ignora segundos bissextos, ao contrário do UTC. Se você converter isso para uma linguagem que usa UTC real, poderá apenas adicionar 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
fonte
0

Gostaria de fornecer uma solução que faça cálculos somando os dias de 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));

Dessa forma, você não precisa gerenciar os detalhes dos anos bissextos e do horário de verão.

manix
fonte
0

Uma alternativa usando carimbos de data / hora UTC. Além disso, como outros observaram, o dia que indica o primeiro do mês é 1 em vez de 0. No entanto, o mês começa em 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
fonte
0

Você pode passar o parâmetro como número de data na setDatefunção:

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

Isso pode ser útil para aqueles que precisam do dia do ano como uma string e têm o jQuery UI disponível.

Você pode usar o jQuery UI Datepicker:

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

Embaixo funciona da mesma forma que algumas das respostas já 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.
fonte
0

Para aqueles entre nós que desejam uma solução 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");
})();

O tamanho dos meses do ano e a maneira como os anos bissextos funcionam se encaixam perfeitamente em manter nosso tempo no caminho com o sol. Caramba, funciona tão perfeitamente que tudo o que fazemos é apenas ajustar meros segundos aqui e ali . Nosso sistema atual de anos bissextos está em vigor desde 24 de fevereiro de 1582 e provavelmente permanecerá em vigor no futuro próximo.

O DST, no entanto, está muito sujeito a alterações. Pode ser que, daqui a 20 anos, algum país possa compensar o tempo em um dia inteiro ou algum outro extremo para o DST. Um dia inteiro de horário de verão quase certamente nunca acontecerá, mas o horário de verão ainda está muito no ar e indeciso. Portanto, a solução acima é à prova de futuro, além de ser muito rápida.

O trecho de código acima é executado muito rápido. Meu computador pode processar 65536 datas em ~ 52ms no Chrome.

Jack Giffin
fonte
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
fonte
0

Esta é uma solução que evita os problemas de objeto Date e fuso horário, requer que a data de entrada esteja no formato "aaaa-dd-mm". Se você quiser alterar o formato, modifique a função 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
fonte
-1

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

var d = new Date();

Eu sugeriria usar o seguinte, os dias serão salvos em day:

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

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

Martin Ekblom
fonte
-1

/ * 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");
Pankaj Yadav
fonte