Javascript - отримати масив дат між двома датами


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 = працює нова дата (currentDate).
Скотт Кларенбах

це добре для майбутньої дати, але коли я працюю над минулою датою, наприклад, за 30 днів до того, де я повинен змінити вищевказаний код, щоб отримати лише дату, а не час.
vaibhav kulkarni

@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 моменту у межах функції. Перевірте цю скрипку
Адріана Мойса

52

Я переглянув усі вище. Закінчив писати сам. Для цього вам не потрібні моменти . Народного для циклу достатньо і має найбільш сенс, оскільки для циклу існує підрахунок значень у діапазоні.

Один вкладиш:

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? Не дні між цим.
Jonjie

Дякую! саме те, що мені було потрібно без залежностей. :)
mpsyp

2
ця функція маніпулює датою введення джерела. :) Я це протестував.
Хамед

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

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

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 = requ ('момент'); вимагати ('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
Щоб бути безпечним, на відміну від вищезазначеного, зазвичай слід вибирати час у середині дня, щоб уникнути незначних змін через літній час.
Фрогз

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

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:

Якщо ви використовуєте, 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.

Викликати:

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.З значить ви можете написати дійсно елегантну функцію, яка дозволяє динамічно проходити інтервали (години, дні, місяці).

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

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

Utc

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

Примітка. Я знаю, що це дещо інше, ніж запитуване рішення, але я думаю, що багато хто вважатиме це корисним.

Якщо ви хочете знайти кожен "х" інтервал (дні, місяці, роки тощо) між двома датами, 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

@ софтвар рішення, але потім включаючи опцію робочих дат

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