Javascript - получить массив дат между 2 датами


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

Я бы хотел, чтобы «диапазон» был массивом объектов даты, по одному на каждый день между двумя датами.

Хитрость заключается в том, что он должен обрабатывать границы месяца и года.

Ответы:


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

Вот функциональная демоверсия http://jsfiddle.net/jfhartsock/cM3ZU/


2
Спасибо Джон. Я в основном использовал ваш, но у вас есть ошибка byRef, в которой currentDate не может быть помещен в массив, или вы получите массив из n элементов, все как последняя дата. Изменение его на currentDate = new Date (currentDate) работает.
Скотт Кларенбах

Это хорошо для будущей даты, но когда я работаю над прошлой датой, например, за 30 дней до того, где я должен изменить вышеуказанный код, чтобы получить только дату, а не время.
Вайбхав Кулкарни

@vaibhavkulkarni Вы можете просто изменить прототип addays () и изменить цикл while. Кроме того, комментарии не место для запуска нового вопроса.
Джон Хартсок

Должны ли мы лучше убрать время из startDateи endDate? Потому что, если startDateвремя позже, чем stopDateвремя, оно не будет включено stopDateв результат, верно?
Hp93

@ Hp93 Не знаю точно, о чем ты говоришь. Если вы запустите скрипту, которую я предоставил, вы увидите, что она покрывает эту ситуацию.
Джон Хартсок

58

Попробуйте это, не забудьте включить момент 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;
}

Небольшое улучшение: рекомендуется использовать сокращенную запись для создания массивов. var dateArray = [];Подробности здесь
Адриан Мойса

Это новый способ определения массивов, и я полагаю, что он короче / чище.
Мохаммед Сейфер

1
Важное исправление : var currentDate = moment(startDate);если вы используете этот метод дважды в один и тот же день moment.js, вы будете удивлены, почему он работает только в первый раз. Это происходит потому, что javascripts передает объекты по ссылке, поэтому функция в конце дважды использует startDate (которая уже мутирована). Исправление вышеупомянутого исправления гарантирует, что вы работаете с новыми и уникальными моментами js объектов в области действия функции. Проверьте эту скрипку
Адриан Моиза

53

Я посмотрел все выше. Закончил писать сам. Вам не нужны моменты для этого . Достаточно встроенного цикла for, и оно имеет больше смысла, поскольку существует цикл for для подсчета значений в диапазоне.

Один лайнер:

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

Длинная версия

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

Список дат между:

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"
*/

Дни от прошедшей даты до настоящего времени:

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

Что делать, если вы хотите получить все указанные вами дни getDaysArray? Не дни между ними.
Джонджи

Спасибо! именно то, что мне нужно без каких-либо зависимостей. :)
mpsyp

2
эта функция манипулирует исходной датой ввода. :) Я проверял это.
Хамед Тахери

4
@ HamedTaheri-да, но это может быть исправлено путем присвоения копии начала до дт , а не начать себя, например for (var arr=[], dt=new Date(start), ...). ;-)
RobG

работает хорошо, но слишком плохо цикл for (;;) не так удобен для сопровождения программного обеспечения, когда вы работаете с большим количеством других людей.
Виктор

27

Я использую moment.js и Twix.js, они очень хорошо поддерживают манипуляции с датой и временем

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

У меня это работает на http://jsfiddle.net/Lkzg1bxb/


Я скачал все файлы, связанные с ним, но все равно он показывает ошибку TypeError: moment.twix не является функцией
vaibhav kulkarni

Возможно, вам придется включить библиотеки. В nodejs это выглядит так: var moment = require ('moment'); требуют ( 'Twix');
Доктор Бала

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
В целях безопасности, в отличие от вышеизложенного, обычно следует выбирать время в середине дня, чтобы избежать незначительных изменений из-за перехода на летнее время.
Phrogz

Я хотел бы, чтобы вы также добавили изменение середины дня в код.
куры

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
Это будет зависать, если вы предоставите даты в неправильном порядке
pie6k

11

Если вы используете момент, то вы можете использовать их «официальный плагин» для диапазонов moment-range и тогда это становится тривиальным.

Пример узла диапазона моментов:

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

Пример браузера с диапазоном моментов:

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>

пример даты fns:

Если вы используете, date-fnsто eachDayваш друг, и вы получите самый короткий и краткий ответ:

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

Просто наткнулся на этот вопрос, самый простой способ сделать это - использовать момент:

Сначала нужно установить момент и диапазон моментов:

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

Некоторое время я использовал решение @Mohammed Safeer и внес несколько улучшений. Использование форматированных дат - плохая практика при работе в ваших контроллерах. moment().format()следует использовать только для отображения в представлениях. Также помните, что это moment().clone()обеспечивает отделение от входных параметров, а это означает, что даты ввода не изменяются. Я настоятельно рекомендую вам использовать moment.js при работе с датами.

Использование:

  • Обеспечить moment.js даты в качестве значений startDate, endDateпараметров
  • intervalпараметр является необязательным и по умолчанию устанавливается в «дни». Используйте интервалы, поддерживаемые .add()методом (moment.js). Подробнее здесь
  • totalПараметр полезен при указании интервалов в минутах. По умолчанию это 1.

Invoke:

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

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

Функция:

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

Используя ES6, вы получаете Array.from, что означает, что вы можете написать действительно элегантную функцию, которая учитывает динамические интервалы (часы, дни, месяцы).

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
«Элегантный» зависит от вашей точки зрения. new Date(2017,12,30)30 января 2018 года, для меня диапазон дат начинается 29 января 2018 года. Не все дни имеют продолжительность 8,64e7 мс (24 часа), когда наблюдается переход на летнее время. ;-)
RobG

5

Я недавно работал с moment.js, после чего добился цели ..

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

Результат будет:

["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
Пожалуйста, добавьте больше описания и / или информации о вашем ответе и о том, как он решает
заданную

Я считаю, что это пропускает 2016-03-31 по некоторым причинам!
woodhead92

1
Вы не должны иметь varраньше strDateвнутри цикла while!
Борис Якубчик

2

d3js предоставляет множество удобных функций и включает d3.time для легкой манипуляции с датой

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

Для вашего конкретного запроса:

Универсальное глобальное время

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

или местное время

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

диапазон будет массивом объектов даты, которые попадают в первое возможное значение для каждого дня

Вы можете изменить timeDay на timeHour, timeMonth и т. д. для получения одинаковых результатов на разных интервалах


2

Вот один вкладыш, который не требует никаких библиотек на тот случай, если вы не хотите создавать другую функцию. Просто замените startDate (в двух местах) и endDate (которые являются объектами даты js) вашими переменными или значениями даты. Конечно, вы можете обернуть его в функцию, если вы предпочитаете

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

это не учитывает изменения летнего / стандартного времени .. некоторые дни длиннее, а некоторые короче
Майк

2

Я использую эту функцию

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

Я использую простой цикл while для расчета между датами

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

Примечание: я знаю, что это немного отличается от запрошенного решения, но я думаю, что многие найдут его полезным.

Если вы хотите найти каждый интервал "x" (дни, месяцы, годы и т. Д.) Между двумя датами, moment.js и диапазоном момента расширения включите эту функцию.

Например, чтобы найти каждый 30-й день между двумя датами :

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. Создайте массив лет:

    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. Генерация массивов за месяц:

            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. Генерация массивов за дни:

            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

Вы можете сделать это легко с помощью momentJS

Добавьте момент к вашим зависимостям

npm i moment

Затем импортируйте это в свой файл

var moment = require("moment");

Затем используйте следующий код, чтобы получить список всех дат между двумя датами

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

Это может помочь кому-то,

Вы можете получить вывод строки и отформатировать объект row_date, как хотите.

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

Вот стандартный метод, который будет принимать даты или строки Момента в качестве входных данных и генерировать массив дат как Моментные даты. Если вы не хотите, чтобы даты Момента выводились, измените то, что map()возвращает метод.

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

решение @ softvar, но затем с опцией рабочих дат

/**
 * 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

Функция:

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

Использование:

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

Надеюсь, это поможет вам

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.