Loop de JavaScript entre períodos


135

Dados dois Date()objetos, onde um é menor que o outro, como faço um loop todos os dias entre as datas?

for(loopDate = startDate; loopDate < endDate; loopDate += 1)
{

}

Esse tipo de loop funcionaria? Mas como posso adicionar um dia ao contador de loops?

Obrigado!

Respostas:


201

Aqui está uma maneira de fazer isso, usando a maneira como adicionar um dia faz com que a data passe para o próximo mês, se necessário, e sem mexer com milissegundos. O horário de verão também não é um problema.

var now = new Date();
var daysOfYear = [];
for (var d = new Date(2012, 0, 1); d <= now; d.setDate(d.getDate() + 1)) {
    daysOfYear.push(new Date(d));
}

Observe que, se você deseja armazenar a data, precisará criar uma nova (como acima new Date(d)), ou então cada data armazenada será o valor final ddo loop.


Muito mais legível do que todas as outras respostas. A adição de 86400000 milissegundos a cada loop não é muito legível.
Owen

1
Tenha cuidado com o horário de verão. d.getDate () + 1 quando d.getDate () = GMT N e d.getDate () + 1 = GMT N - 1 d.getDate () + 1 retorna duas vezes o mesmo dia do mês.
Rafael Fontes

1
Por que fazer Date.now()ao definir now? new Date() retorna a data atual como um objeto por padrão . Chamar Datesem o newconstrutor apenas fornece uma string de Data que você converte em um objeto Date de qualquer maneira?
tatlar

Para mim new Date(2012, 0, 1);estava pegando o dia incorreto (um dia antes), new Date(Date.UTC(2012, 0, 1))funcionou bem.
TK421

Eu tentei várias soluções na internet. Estranho é que ele pula algumas vezes alguns dias. Como 1.12, 2.12, 3.12, 5.12 ... (observe que o 4.12 foi ignorado) eu não tenho idéia do por que isso acontece ... Alguém pegou esse problema e encontrou uma solução?
Erik Kubica


9

Se startDate e endDate forem realmente objetos de data, você poderá convertê-los em número de milissegundos desde meia-noite de 1º de janeiro de 1970, assim:

var startTime = startDate.getTime(), endTime = endDate.getTime();

Em seguida, você pode fazer um loop de um para outro, incrementando o loopTime em 86400000 (1000 * 60 * 60 * 24) - número de milissegundos em um dia:

for(loopTime = startTime; loopTime < endTime; loopTime += 86400000)
{
    var loopDay=new Date(loopTime)
    //use loopDay as you wish
}

1
O +1 deu-me o suficiente para trabalhar, e incluí a solução de trabalho na minha pergunta
Tom Gullen

5
isso não funciona ao passar por uma alteração no horário de verão (em áreas onde isso é um problema). Boa solução caso contrário.
chadgh

3
Você não pode assumir que existem 86400000segundos em um dia. Esse loop é frágil para alterações no horário de verão e outras condições de borda.
Jeremy J Starcher

2
Além do horário de verão, outra condição de borda é "Leap Second". A um segundo diferença faz matéria - Datas convertidos em milissegundos correspondem ao primeiro segundo de uma dado dia. Um segundo erro e você pousa no dia anterior.
Wojtek Kruszewski

9

Acho que encontrei uma resposta ainda mais simples, se você se permitir usar o Moment.js :

// cycle through last five days, today included
// you could also cycle through any dates you want, mostly for
// making this snippet not time aware
const currentMoment = moment().subtract(4, 'days');
const endMoment = moment().add(1, 'days');
while (currentMoment.isBefore(endMoment, 'day')) {
  console.log(`Loop at ${currentMoment.format('YYYY-MM-DD')}`);
  currentMoment.add(1, 'days');
}
<script src="https://cdn.jsdelivr.net/npm/moment@2/moment.min.js"></script>


5

Aqui código de trabalho simples, funcionou para mim

var from = new Date(2012,0,1);
var to = new Date(2012,1,20);
    
// loop for every day
for (var day = from; day <= to; day.setDate(day.getDate() + 1)) {
      
   // your day is here

}


2
var start = new Date("2014-05-01"); //yyyy-mm-dd
var end = new Date("2014-05-05"); //yyyy-mm-dd

while(start <= end){

    var mm = ((start.getMonth()+1)>=10)?(start.getMonth()+1):'0'+(start.getMonth()+1);
    var dd = ((start.getDate())>=10)? (start.getDate()) : '0' + (start.getDate());
    var yyyy = start.getFullYear();
    var date = dd+"/"+mm+"/"+yyyy; //yyyy-mm-dd

    alert(date); 

    start = new Date(start.setDate(start.getDate() + 1)); //date increase by 1
}

1

Com base na resposta de Tabare, tive que adicionar mais um dia no final, pois o ciclo é cortado antes

var start = new Date("02/05/2013");
var end = new Date("02/10/2013");
var newend = end.setDate(end.getDate()+1);
var end = new Date(newend);
while(start < end){
   alert(start);           

   var newDate = start.setDate(start.getDate() + 1);
   start = new Date(newDate);
}

0

Se você deseja uma maneira eficiente com milissegundos:

var daysOfYear = [];
for (var d = begin; d <= end; d = d + 86400000) {
    daysOfYear.push(new Date(d));
}

0

Vamos supor que você obteve a data de início e a data de término da interface do usuário e a armazenou na variável de escopo no controlador.

Em seguida, declare uma matriz que será redefinida em todas as chamadas de função, para que na próxima chamada da função os novos dados possam ser armazenados.

var dayLabel = [];

Lembre-se de usar a nova data (sua variável inicial) porque se você não usar a nova data e atribuí-la diretamente à variável, a função setDate alterará o valor da variável original em cada iteração`

for (var d = new Date($scope.startDate); d <= $scope.endDate; d.setDate(d.getDate() + 1)) {
                dayLabel.push(new Date(d));
            }

-2

Com base na resposta de Jayarjo:

var loopDate = new Date();
loopDate.setTime(datFrom.valueOf());

while (loopDate.valueOf() < datTo.valueOf() + 86400000) {

    alert(loopDay);

    loopDate.setTime(loopDate.valueOf() + 86400000);
}

Um comentário para isso é que uma comparação menor que a preferida é mais que! =, Como quando ocorre um loop por vários meses por algum motivo, a comparação! = Nunca é acionada.
Tom Gullen

1
Além do horário de verão, outra condição de borda é "Leap Second". A um segundo diferença faz matéria - Datas convertidos em milissegundos correspondem ao primeiro segundo de uma dado dia. Um segundo erro e você pousa no dia anterior.
Wojtek Kruszewski
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.