Javascript: obtenga una variedad de fechas entre 2 fechas

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

Me gustaría que "rango" sea un conjunto de objetos de fecha, uno para cada día entre las dos fechas.

El truco es que también debe manejar los límites de mes y año.

Scott Klarenbach
fuente

Respuestas:

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

Aquí hay una demostración funcional http://jsfiddle.net/jfhartsock/cM3ZU/

John Hartsock
fuente
2
Gracias John Principalmente usé el tuyo, pero tienes un error byRef, ya que currentDate no puede ser empujado a la matriz o terminarás con una matriz de n elementos, todo como la última fecha. Cambiarlo a currentDate = new Date (currentDate) funciona.
Scott Klarenbach
esto está bien para la fecha futura, pero cuando estoy trabajando en una fecha pasada como 30 días antes, ¿dónde debo cambiar el código anterior para obtener solo la fecha y no la hora?
vaibhav kulkarni
@vaibhavkulkarni Simplemente puede invertir el prototipo addays () y modificar el ciclo while. Además, los comentarios no son el lugar para comenzar una nueva pregunta.
John Hartsock
¿Deberíamos eliminar mejor el tiempo de startDatey endDate? Porque si startDateel tiempo es más tarde que stopDateel tiempo, no se incluirá stopDateen el resultado, ¿verdad?
Hp93
@ Hp93 No estoy seguro exactamente de qué estás hablando. Si ejecuta el violín que le proporcioné, verá que cubre esa situación.
John Hartsock
58

Prueba esto, recuerda incluir el 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;
}
Mohammed Safeer
fuente
Solo una pequeña mejora: se recomienda la notación abreviada para crear matrices var dateArray = [];Detalles aquí
Adrian Moisa
Es la nueva forma de definir matrices, y supongo que es más corta / más limpia.
Mohammed Safeer
1
var currentDate = moment(startDate);Solución importante : en caso de que esté utilizando este método dos veces en el mismo momento.js fechas, se desconcertará por qué funciona solo la primera vez. Esto sucede porque los javascripts pasan objetos por referencia, por lo que la función termina usando el startDate dos veces (que ya está mutado). El parcheo de la corrección anterior garantiza que esté trabajando con objetos js de momento nuevos y únicos en el alcance de la función. Mira este violín
Adrian Moisa
53

Miré todos los de arriba. Terminé escribiendo yo mismo. No necesitas momentos para esto . Un bucle for nativo es suficiente y tiene más sentido porque existe un bucle for para contar valores en un rango.

Un trazador de líneas:

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

Versión larga

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

Lista de fechas 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"
*/

Días desde una fecha pasada hasta ahora:

var daylist = getDaysArray(new Date("2018-05-01"),new Date());
daylist.map((v)=>v.toISOString().slice(0,10)).join("")
Enesn
fuente
¿Qué sucede si desea obtener todos los días que especificó getDaysArray? No los días entre eso.
Jonjie
¡Gracias! exactamente lo que necesitaba sin dependencias. :)
mpsyp
2
Esta función manipula la fecha de entrada de origen. :) Lo probé.
Hamed Taheri
44
@ HamedTaheri: sí, pero eso se puede solucionar asignando una copia de start a dt en lugar de start en sí, por ejemplo for (var arr=[], dt=new Date(start), ...). ;-)
RobG
funciona bien, pero un bucle for (;;) no es tan legible para el mantenimiento del software cuando trabaja con muchas otras personas.
Victor
27

Uso moment.js y Twix.js, que brindan un excelente soporte para la manipulación de fecha y 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);

Tengo esto ejecutándose en http://jsfiddle.net/Lkzg1bxb/

Ahmed Aswani
fuente
He descargado todos los archivos relacionados con él, pero aún muestra el error TypeError: moment.twix no es una función
vaibhav kulkarni
Puede que tenga que incluir las bibliotecas. En nodejs dice: 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)
Phrogz
fuente
3
Para estar seguro, a diferencia de lo anterior, generalmente debe elegir una hora en el medio del día para evitar pequeñas variaciones debido al horario de verano.
Phrogz
Me gustaría que también agregaras el cambio del medio día al código.
pollos
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;

}
Scott Klarenbach
fuente
1
Esto se congelaría si proporciona fechas en orden incorrecto
pie6k
11

Si está utilizando momento, puede usar su "complemento oficial" para rangos moment-rangey esto se vuelve trivial.

ejemplo de nodo de rango 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')))

ejemplo de navegador de rango de 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>

Ejemplo de fecha fns:

Si está utilizando, date-fnsentonces eachDayes su amigo y obtiene, con mucho, la respuesta más breve y 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>

Akrion
fuente
8

Acabo de encontrar esta pregunta, la forma más fácil de hacerlo es usar el momento:

Primero debe instalar el momento y el rango de momento:

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)
Irritar
fuente
6

He estado usando la solución @Mohammed Safeer por un tiempo e hice algunas mejoras. Usar fechas formateadas es una mala práctica mientras trabajas en tus controladores. moment().format()debe usarse solo para fines de visualización en vistas. Recuerde también que moment().clone()garantiza la separación de los parámetros de entrada, lo que significa que las fechas de entrada no se modifican. Le recomiendo que use moment.js cuando trabaje con fechas.

Uso:

  • Proporcionar fechas moment.js como valores para startDate, endDateparámetros
  • intervalEl parámetro es opcional y el valor predeterminado es 'días'. Use intervalos admitidos por .add()método (moment.js). Más detalles aquí
  • totalEl parámetro es útil al especificar intervalos en minutos. El valor predeterminado es 1.

Invocar:

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

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

Función:

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;
};
Adrian Moisa
fuente
6

Con ES6, tiene Array.from, lo que significa que puede escribir una función realmente elegante, que permite intervalos dinámicos (horas, días, 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));

digiguru
fuente
2
"Elegante" depende de su punto de vista. new Date(2017,12,30)es el 30 de enero de 2018, para mí el rango de fechas comienza el 29 de enero de 2018. No todos los días duran 8.64e7 ms (24 h) donde se observa el horario de verano. ;-)
RobG
5

Hace poco estuve trabajando con moment.js, luego hice el truco ...

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

El resultado sería:

["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"]
gor181
fuente
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"]
Công Thắng
fuente
1
Agregue más descripción y / o información sobre su respuesta y cómo resuelve el problema solicitado para que otros puedan entenderlo fácilmente sin pedir aclaraciones
Koceeng
Me parece que esto se salta el 31-03-2016 por alguna razón
woodhead92
1
¡No deberías tener varantes strDatedentro del ciclo while!
Boris Yakubchik
2

d3js proporciona muchas funciones prácticas e incluye d3.time para manipulaciones fáciles de fechas

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

Para su solicitud específica:

UTC

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

o hora local

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

El rango será una matriz de objetos de fecha que caen en el primer valor posible para cada día

puede cambiar timeDay a timeHour, timeMonth, etc. para obtener los mismos resultados en diferentes intervalos

Russell Thompson
fuente
2

Aquí hay una línea que no requiere ninguna biblioteca en caso de que no desee crear otra función. Simplemente reemplace startDate (en dos lugares) y endDate (que son objetos de fecha js) con sus variables o valores de fecha. Por supuesto, puedes envolverlo en una función si lo prefieres

Array(Math.floor((endDate - startDate) / 86400000) + 1).fill().map((_, idx) => (new Date(startDate.getTime() + idx * 86400000)))
ti994a
fuente
esto no tiene en cuenta los cambios de horario de verano / horario de verano estándar. Algunos días son más largos y otros más cortos
Mike
2

Yo uso esta funcion

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;
}
IdontCareAboutReputationPoints
fuente
2

Estoy usando el ciclo while simple para calcular las fechas 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);
}

KARTHIKEYAN.A
fuente
1

Nota: Soy consciente de que esto es ligeramente diferente a la solución solicitada, pero creo que muchos lo encontrarán útil.

Si desea encontrar cada intervalo "x" (días, meses, años, etc.) entre dos fechas, moment.js y los paquetes de extensión de rango de momento , habilite esta funcionalidad.

Por ejemplo, para encontrar cada 30 días entre dos fechas :

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'))
});
Roca
fuente
1
  1. Genere una serie de años:

    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. Generar matrices por mes:

            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. Generar matrices por días:

            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())
elnaz nasiri
fuente
1

Puedes hacerlo fácilmente usando momentJS

Agregue momento a sus dependencias

npm i moment

Luego importe eso en su archivo

var moment = require("moment");

Luego use el siguiente código para obtener la lista de todas las fechas entre dos fechas

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);
Nitesh Malviya
fuente
0

Esto puede ayudar a alguien,

Puede obtener el resultado de la fila a partir de esto y formatear el objeto row_date como desee.

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

Praneeth Nidarshan
fuente
0

Aquí hay un método fijo que aceptará fechas o cadenas de Momento o una mezcla como entradas y generará una matriz de fechas como fechas de Momento. Si no desea fechas de momento como salida, cambie lo map()que devuelve el método.

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'));
};
Chico
fuente
0

La solución de @ softvar, pero luego incluye la opción de fechas de trabajo

/**
 * 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;
}
koosvdkolk
fuente
0

Función:

  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 te ayude

Nelson Dang
fuente