Javascript - obtenha matriz de datas entre 2 datas


155
var range = getDates(new Date(), new Date().addDays(7));

Eu gostaria que "intervalo" fosse uma matriz de objetos de data, um para cada dia entre as duas datas.

O truque é que ele também deve lidar com os limites de mês e ano.

Respostas:


171
Date.prototype.addDays = function(days) {
    var date = new Date(this.valueOf());
    date.setDate(date.getDate() + days);
    return date;
}

function getDates(startDate, stopDate) {
    var dateArray = new Array();
    var currentDate = startDate;
    while (currentDate <= stopDate) {
        dateArray.push(new Date (currentDate));
        currentDate = currentDate.addDays(1);
    }
    return dateArray;
}

Aqui está uma demonstração funcional http://jsfiddle.net/jfhartsock/cM3ZU/


2
Obrigado John. Eu usei principalmente o seu, mas você tem um erro byRef, pois currentDate não pode ser empurrado para o array ou você acaba com um array de n elementos, todos na última data. Alterá-lo para currentDate = new Date (currentDate) funciona.
Scott Klarenbach

isso é bom para a data futura, mas quando estou trabalhando em uma data passada, como 30 dias antes, onde devo alterar o código acima para obter apenas data e não hora.
vaibhav kulkarni

@vaibhavkulkarni Você pode simplesmente reverter o protótipo addays () e modificar o loop while. Além disso, os comentários não são o lugar para iniciar uma nova pergunta.
John Hartsock

Devemos remover melhor o tempo de startDatee endDate? Porque se startDateo tempo for posterior ao stopDatetempo, ele não será incluído stopDateno resultado, certo?
Hp93 11/06

@ Hp93 Não tenho certeza exatamente do que você está falando. Se você tocar o violino que eu forneci, verá que ele cobre essa situação.
John Hartsock

58

Tente isso, lembre-se de incluir o momento js,

function getDates(startDate, stopDate) {
    var dateArray = [];
    var currentDate = moment(startDate);
    var stopDate = moment(stopDate);
    while (currentDate <= stopDate) {
        dateArray.push( moment(currentDate).format('YYYY-MM-DD') )
        currentDate = moment(currentDate).add(1, 'days');
    }
    return dateArray;
}

Apenas uma pequena melhoria: recomenda-se a notação abreviada para criar matrizes var dateArray = [];Detalhes aqui
Adrian Moisa

É a nova maneira de definir matrizes, e suponho que seja mais curta / mais limpa.
Mohammed Safeer

1
Correção importante : var currentDate = moment(startDate);caso você esteja usando esse método duas vezes nas mesmas datas moment.js, ficará surpreso com o motivo pelo qual ele funciona apenas na primeira vez. Isso acontece porque javascripts passa objetos por referência para que a função termine usando o startDate duas vezes (que já está mutado). A correção da correção acima garante que você esteja trabalhando com novos e únicos momentos js objetos no escopo da função. Verifique este violino #
Adrian Moisa

51

Eu olhei todos acima. Acabei escrevendo a mim mesmo. Você não precisa de momentjs para isso . Um loop for nativo é suficiente e faz mais sentido porque existe um loop for para contar valores em um intervalo.

Um forro:

var getDaysArray = function(s,e) {for(var a=[],d=new Date(s);d<=e;d.setDate(d.getDate()+1)){ a.push(new Date(d));}return a;};

Versão longa

var getDaysArray = function(start, end) {
    for(var arr=[],dt=new Date(start); dt<=end; dt.setDate(dt.getDate()+1)){
        arr.push(new Date(dt));
    }
    return arr;
};

Listar datas entre:

var daylist = getDaysArray(new Date("2018-05-01"),new Date("2018-07-01"));
daylist.map((v)=>v.toISOString().slice(0,10)).join("")
/*
Output: 
    "2018-05-01
    2018-05-02
    2018-05-03
    ...
    2018-06-30
    2018-07-01"
*/

Dias desde uma data passada até agora:

var daylist = getDaysArray(new Date("2018-05-01"),new Date());
daylist.map((v)=>v.toISOString().slice(0,10)).join("")

E se você quiser buscar todos os dias especificados getDaysArray? Não os dias entre isso.
Jonjie

obrigado! exatamente o que eu precisava, sem dependências. :)
mpsyp

2
Esta função manipula a data de entrada da fonte. :) eu testei.
Hamed Taheri

4
@ HamedTaheri - sim, mas isso pode ser corrigido atribuindo uma cópia de start para dt em vez de iniciar por si mesma, por exemplo for (var arr=[], dt=new Date(start), ...). ;-)
RobG 6/11/19

trabalhar bem, mas um loop for (;;) ruim não é tão legível para a manutenção do software quando você está trabalhando com muitas outras pessoas.
219 Victor Victor

27

Eu uso moment.js e Twix.js, eles fornecem um ótimo suporte para manipulação de data e hora

var itr = moment.twix(new Date('2012-01-15'),new Date('2012-01-20')).iterate("days");
var range=[];
while(itr.hasNext()){
    range.push(itr.next().toDate())
}
console.log(range);

Eu tenho isso em execução em http://jsfiddle.net/Lkzg1bxb/


Tenho baixar todos os arquivos relacionados com ele, mas ainda mostra a TypeError erro: moment.twix não é uma função
vaibhav kulkarni

Pode ser necessário incluir as bibliotecas. No nodejs é como, var moment = require ('moment'); require ('twix');
Dr Bala Soundararaj

18
var boxingDay = new Date("12/26/2010");
var nextWeek  = boxingDay*1 + 7*24*3600*1000;

function getDates( d1, d2 ){
  var oneDay = 24*3600*1000;
  for (var d=[],ms=d1*1,last=d2*1;ms<last;ms+=oneDay){
    d.push( new Date(ms) );
  }
  return d;
}

getDates( boxingDay, nextWeek ).join("\n");
// Sun Dec 26 2010 00:00:00 GMT-0700 (Mountain Standard Time)
// Mon Dec 27 2010 00:00:00 GMT-0700 (Mountain Standard Time)
// Tue Dec 28 2010 00:00:00 GMT-0700 (Mountain Standard Time)
// Wed Dec 29 2010 00:00:00 GMT-0700 (Mountain Standard Time)
// Thu Dec 30 2010 00:00:00 GMT-0700 (Mountain Standard Time)
// Fri Dec 31 2010 00:00:00 GMT-0700 (Mountain Standard Time)
// Sat Jan 01 2011 00:00:00 GMT-0700 (Mountain Standard Time)

3
Para estar seguro, ao contrário do acima, geralmente você deve escolher um horário no meio do dia para evitar pequenas variações devido ao horário de verão.
Phrogz

Desejo que você também adicione alterações no meio do dia ao código.
galinhas

15
function (startDate, endDate, addFn, interval) {

 addFn = addFn || Date.prototype.addDays;
 interval = interval || 1;

 var retVal = [];
 var current = new Date(startDate);

 while (current <= endDate) {
  retVal.push(new Date(current));
  current = addFn.call(current, interval);
 }

 return retVal;

}

1
Isso congelaria se você fornecer datas em ordem incorreta
pie6k

11

Se você estiver usando o momento, poderá usar o "plugin oficial" deles para intervalos moment-rangee isso se tornará trivial.

exemplo de nó de intervalo de momento:

const Moment = require('moment');
const MomentRange = require('moment-range');
const moment = MomentRange.extendMoment(Moment);

const start = new Date("11/30/2018"), end = new Date("09/30/2019")
const range = moment.range(moment(start), moment(end));

console.log(Array.from(range.by('day')))

exemplo de navegador no intervalo do momento:

window['moment-range'].extendMoment(moment);

const start = new Date("11/30/2018"), end = new Date("09/30/2019")
const range = moment.range(moment(start), moment(end));

console.log(Array.from(range.by('day')))
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-range/4.0.1/moment-range.js"></script>

date fns exemplo:

Se você estiver usando, date-fnsentão eachDayé seu amigo e você obtém de longe a resposta mais curta e concisa:

console.log(dateFns.eachDay(
  new Date(2018, 11, 30),
  new Date(2019, 30, 09)
))
<script src="https://cdnjs.cloudflare.com/ajax/libs/date-fns/1.29.0/date_fns.min.js"></script>


8

Acabei de me deparar com essa pergunta, a maneira mais fácil de fazer isso é usar o momento:

Você precisa instalar o momento e o intervalo de momentos primeiro:

const Moment = require('moment');
const MomentRange = require('moment-range');
const moment = MomentRange.extendMoment(Moment);

const start = moment()
const end = moment().add(2, 'months')
const range = moment.range(start, end)
const arrayOfDates = Array.from(range.by('days'))
console.log(arrayOfDates)

6

Estou usando a solução @Mohammed Safeer há um tempo e fiz algumas melhorias. Usar datas formatadas é uma prática ruim ao trabalhar em seus controladores. moment().format()deve ser usado apenas para fins de exibição em visualizações. Lembre-se também quemoment().clone() garante a separação dos parâmetros de entrada, o que significa que as datas de entrada não são alteradas. É altamente recomendável que você use o moment.js ao trabalhar com datas.

Uso:

  • Forneça datas moment.js como valores para startDate, endDateparâmetros
  • intervalO parâmetro é opcional e o padrão é 'days'. Use intervalos suportados pelo .add()método (moment.js). Mais detalhes aqui
  • totalO parâmetro é útil ao especificar intervalos em minutos. O padrão é 1.

Invocar:

var startDate = moment(),
    endDate = moment().add(1, 'days');

getDatesRangeArray(startDate, endDate, 'minutes', 30);

Função:

var getDatesRangeArray = function (startDate, endDate, interval, total) {
    var config = {
            interval: interval || 'days',
            total: total || 1
        },
        dateArray = [],
        currentDate = startDate.clone();

    while (currentDate < endDate) {
        dateArray.push(currentDate);
        currentDate = currentDate.clone().add(config.total, config.interval);
    }

    return dateArray;
};

6

Usando o ES6, você tem Array.from, o que significa que você pode escrever uma função realmente elegante, que permite intervalos dinâmicos (horas, dias, meses).

function getDates(startDate, endDate, interval) {
const duration = endDate - startDate;
const steps = duration / interval;
return Array.from({length: steps+1}, (v,i) => new Date(startDate.valueOf() + (interval * i)));
}
const startDate = new Date(2017,12,30);
const endDate = new Date(2018,1,3);
const dayInterval = 1000 * 60 * 60 * 24; // 1 day
const halfDayInterval = 1000 * 60 * 60 * 12; // 1/2 day

console.log("Days", getDates(startDate, endDate, dayInterval));
console.log("Half Days", getDates(startDate, endDate, halfDayInterval));


2
"Elegante" depende do seu ponto de vista. new Date(2017,12,30)é 30 de janeiro de 2018. Para mim, o período começa em 29 de janeiro de 2018. Nem todos os dias têm 8,64e7 ms (24 horas) de duração em que o horário de verão é observado. ;-)
RobG 6/11/19

5

Eu estava trabalhando recentemente com moment.js, seguindo o truque ..

function getDateRange(startDate, endDate, dateFormat) {
        var dates = [],
            end = moment(endDate),
            diff = endDate.diff(startDate, 'days');

        if(!startDate.isValid() || !endDate.isValid() || diff <= 0) {
            return;
        }

        for(var i = 0; i < diff; i++) {
            dates.push(end.subtract(1,'d').format(dateFormat));
        }

        return dates;
    };
    console.log(getDateRange(startDate, endDate, dateFormat));

O resultado seria:

["09/03/2015", "10/03/2015", "11/03/2015", "12/03/2015", "13/03/2015", "14/03/2015", "15/03/2015", "16/03/2015", "17/03/2015", "18/03/2015"]

3
var listDate = [];
var startDate ='2017-02-01';
var endDate = '2017-02-10';
var dateMove = new Date(startDate);
var strDate = startDate;

while (strDate < endDate){
  var strDate = dateMove.toISOString().slice(0,10);
  listDate.push(strDate);
  dateMove.setDate(dateMove.getDate()+1);
};
console.log(listDate);

//["2017-02-01", "2017-02-02", "2017-02-03", "2017-02-04", "2017-02-05", "2017-02-06", "2017-02-07", "2017-02-08", "2017-02-09", "2017-02-10"]

1
Por favor, adicionar mais descrição e / ou informações sobre sua resposta e como ele resolve o problema pediu para que outros possam facilmente compreender que sem pedir esclarecimentos
koceeng

Acho que está pulando 31-03-2016 por algum motivo!
usar o seguinte

1
Você não deveria ter varantes strDatedentro do loop while!
Boris Yakubchik

2

O d3js fornece muitas funções úteis e inclui o d3.time para manipulações fáceis de datas

https://github.com/d3/d3-time

Para sua solicitação específica:

Utc

var range = d3.utcDay.range(new Date(), d3.utcDay.offset(new Date(), 7));

ou hora local

var range = d3.timeDay.range(new Date(), d3.timeDay.offset(new Date(), 7));

O intervalo será uma matriz de objetos de data que caem no primeiro valor possível para cada dia

você pode alterar timeDay para timeHour, timeMonth etc. para os mesmos resultados em intervalos diferentes


2

Aqui está um liner que não requer bibliotecas, caso você não queira criar outra função. Apenas substitua startDate (em dois lugares) e endDate (que são objetos js date) pelas suas variáveis ​​ou valores de data. Claro que você poderia envolvê-lo em uma função, se preferir

Array(Math.floor((endDate - startDate) / 86400000) + 1).fill().map((_, idx) => (new Date(startDate.getTime() + idx * 86400000)))

isso não leva em consideração Daylight / Padrão Savings Time muda .. alguns dias são mais longos e alguns são mais curtos
Mike

2

Eu uso essa função

function getDatesRange(startDate, stopDate) {
    const ONE_DAY = 24*3600*1000;
    var days= [];
    var currentDate = new Date(startDate);
    while (currentDate <= stopDate) {
        days.push(new Date (currentDate));
        currentDate = currentDate - 1 + 1 + ONE_DAY;
    }
    return days;
}

2

Estou usando o simples while loop para calcular as datas entre

var start = new Date("01/05/2017");
var end = new Date("06/30/2017");
var newend = end.setDate(end.getDate()+1);
end = new Date(newend);
while(start < end){
   console.log(new Date(start).getTime() / 1000); // unix timestamp format
   console.log(start); // ISO Date format          
   var newDate = start.setDate(start.getDate() + 1);
   start = new Date(newDate);
}


1

Nota: Eu sei que isso é um pouco diferente da solução solicitada, mas acho que muitos a acharão útil.

Se você deseja encontrar cada intervalo "x" (dias, meses, anos, etc ...) entre duas datas, moment.js e o intervalo de momentos pacotes de extensão de ativam essa funcionalidade.

Por exemplo, para encontrar a cada 30 dias entre duas datas :

window['moment-range'].extendMoment(moment);

var dateString = "2018-05-12 17:32:34.874-08";
var start  = new Date(dateString);
var end    = new Date();
var range1 = moment.range(start, end);
var arrayOfIntervalDates = Array.from(range1.by('day', { step: 30 }));

arrayOfIntervalDates.map(function(intervalDate){
  console.log(intervalDate.format('YY-M-DD'))
});

1
  1. Gere uma matriz de anos:

    const DAYS = () => {
     const days = []
     const dateStart = moment()
     const dateEnd = moment().add(30, days')
     while (dateEnd.diff(dateStart, days') >= 0) {
      days.push(dateStart.format(‘D'))
      dateStart.add(1, days')
     }
     return days
    }
    console.log(DAYS())
  2. Gere matrizes para o mês:

            const MONTHS = () => {
             const months = []
             const dateStart = moment()
             const dateEnd = moment().add(12, month')
             while (dateEnd.diff(dateStart, months') >= 0) {
              months.push(dateStart.format(‘M'))
              dateStart.add(1, month')
             }
             return months
            }
            console.log(MONTHS())
  3. Gere matrizes por dias:

            const DAYS = () => {
             const days = []
             const dateStart = moment()
             const dateEnd = moment().add(30, days')
             while (dateEnd.diff(dateStart, days') >= 0) {
              days.push(dateStart.format(‘D'))
              dateStart.add(1, days')
             }
             return days
            }
            console.log(DAYS())

1

Você pode fazer isso facilmente usando momentJS

Adicione um momento às suas dependências

npm i moment

Em seguida, importe isso no seu arquivo

var moment = require("moment");

Em seguida, use o código a seguir para obter a lista de todas as datas entre duas datas

let dates = [];
let currDate = moment.utc(new Date("06/30/2019")).startOf("day");
let lastDate = moment.utc(new Date("07/30/2019")).startOf("day");

do {
 dates.push(currDate.clone().toDate());
} while (currDate.add(1, "days").diff(lastDate) < 0);
dates.push(currDate.clone().toDate());

console.log(dates);

0

Isso pode ajudar alguém,

Você pode obter a saída da linha e formatar o objeto row_date como desejar.

var from_date = '2016-01-01';
var to_date = '2016-02-20';

var dates = getDates(from_date, to_date);

console.log(dates);

function getDates(from_date, to_date) {
  var current_date = new Date(from_date);
  var end_date     = new Date(to_date);

  var getTimeDiff = Math.abs(current_date.getTime() - end_date.getTime());
  var date_range = Math.ceil(getTimeDiff / (1000 * 3600 * 24)) + 1 ;

  var weekday = ["SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"];
  var months = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"];
  var dates = new Array();

  for (var i = 0; i <= date_range; i++) {
     var getDate, getMonth = '';

     if(current_date.getDate() < 10) { getDate = ('0'+ current_date.getDate());}
     else{getDate = current_date.getDate();}

    if(current_date.getMonth() < 9) { getMonth = ('0'+ (current_date.getMonth()+1));}
    else{getMonth = current_date.getMonth();}

    var row_date = {day: getDate, month: getMonth, year: current_date.getFullYear()};
    var fmt_date = {weekDay: weekday[current_date.getDay()], date: getDate, month: months[current_date.getMonth()]};
    var is_weekend = false;
    if (current_date.getDay() == 0 || current_date.getDay() == 6) {
        is_weekend = true;
    }
    dates.push({row_date: row_date, fmt_date: fmt_date, is_weekend: is_weekend});
    current_date.setDate(current_date.getDate() + 1);
 }
 return dates;
}

https://gist.github.com/pranid/3c78f36253cbbc6a41a859c5d718f362.js


0

Aqui está um método fixo que aceita datas ou seqüências de caracteres do momento ou uma mistura como entradas e gera uma matriz de datas como datas do momento. Se você não deseja datas do momento como saída, altere o que o map()método retorna.

const moment = require('moment');

// ...

/**
 * @param {string|import('moment').Moment} start
 * @param {string|import('moment').Moment} end
 * @returns {import('moment').Moment[]}
 */
const getDateRange = (start, end) => {
  const s = moment.isMoment(start) ? start : moment(start);
  const e = moment.isMoment(end) ? end : moment(end);
  return [...Array(1 + e.diff(s, 'days')).keys()].map(n => moment(s).add(n, 'days'));
};

0

solução @ softvar, mas incluindo a opção de datas de trabalho

/**
 * Returns array of working days between two dates.
 *
 * @param {string} startDate
 *   The start date in yyyy-mm-dd format.
 * @param {string} endDate
 *   The end date in yyyy-mm-dd format.
 * @param {boolean} onlyWorkingDays
 *   If true only working days are returned. Default: false
 *
 * @return {array}
 *   Array of dates in yyyy-mm-dd string format.
 */
function getDates(startDate, stopDate, onlyWorkingDays) {
  let doWd = typeof onlyWorkingDays ==='undefined' ? false : onlyWorkingDays;

  let dateArray = [];  
  let dayNr;
  let runDateObj = moment(startDate);  
  let stopDateObj = moment(stopDate);

  while (runDateObj <= stopDateObj) {
    dayNr = runDateObj.day();
    if (!doWd || (dayNr>0 && dayNr<6)) {
     dateArray.push(moment(runDateObj).format('YYYY-MM-DD'));  
    }

    runDateObj = moment(runDateObj).add(1, 'days');
  }
  return dateArray;
}

0

Função:

  var dates = [],
      currentDate = startDate,
      addDays = function(days) {
        var date = new Date(this.valueOf());
        date.setDate(date.getDate() + days);
        return date;
      };
  while (currentDate <= endDate) {
    dates.push(currentDate);
    currentDate = addDays.call(currentDate, 1);
  }
  return dates;
};

Uso:

var dates = getDatesRange(new Date(2019,01,01), new Date(2019,01,25));                                                                                                           
dates.forEach(function(date) {
  console.log(date);
});

Espero que ajude você

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.