Javascript - pobierz tablicę dat pomiędzy dwoma datami

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

Chciałbym, aby „zakres” był tablicą obiektów dat, po jednym na każdy dzień między dwiema datami.

Sztuczka polega na tym, że powinien również obsługiwać granice miesięcy i lat.

Scott Klarenbach
źródło

Odpowiedzi:

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

Oto funkcjonalne demo http://jsfiddle.net/jfhartsock/cM3ZU/

John Hartsock
źródło
2
Dzięki, John. Przeważnie używałem twojego, ale masz błąd byRef, w którym currentDate nie może zostać wypchnięty do tablicy lub otrzymasz tablicę n elementów, wszystkie jako ostatnia data. Zmiana na currentDate = new Date (currentDate) działa.
Scott Klarenbach
jest to w porządku na przyszłą datę, ale kiedy pracuję z datą przeszłą, na przykład 30 dni wcześniej, powinienem zmienić powyższy kod, aby uzyskać tylko datę, a nie godzinę.
vaibhav kulkarni
@vaibhavkulkarni Możesz po prostu odwrócić prototyp addays () i zmodyfikować pętlę while. Ponadto komentarze nie są miejscem, w którym można rozpocząć nowe pytanie.
John Hartsock,
Czy powinniśmy lepiej usunąć czas z startDatei endDate? Ponieważ jeśli startDateczas jest późniejszy niż stopDateczas, to nie zostanie uwzględniony stopDatew wyniku, prawda?
Hp93
@ Hp93 Nie jestem pewien, o czym mówisz. Jeśli zaczniesz grać na skrzypcach, które dostarczyłem, zobaczysz, że obejmuje to tę sytuację.
John Hartsock
58

Spróbuj tego, pamiętaj, aby uwzględnić moment 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
źródło
Tylko niewielka poprawa: zalecana jest skrócona notacja do tworzenia tablic. var dateArray = [];Szczegóły tutaj
Adrian Moisa
Jest to nowy sposób definiowania tablic i przypuszczam, że jest krótszy / bardziej przejrzysty.
Mohammed Safeer,
1
Ważna poprawka : var currentDate = moment(startDate);jeśli używasz tej metody dwa razy w tej samej dacie moment.js, zdziwisz się, dlaczego działa ona po raz pierwszy. Dzieje się tak, ponieważ javascripts przekazuje obiekty przez referencję, więc funkcja kończy się dwukrotnym użyciem startDate (która jest już zmutowana). Poprawienie powyższej poprawki zapewnia, że ​​pracujesz z nowymi i unikalnymi obiektami moment js w zakresie funkcji. Sprawdź to skrzypce
Adrian Moisa,
52

Spojrzałem na wszystkie powyżej. Skończyło się na pisaniu siebie. Nie potrzebujesz do tego momentów . Natywna pętla for jest wystarczająca i ma największy sens, ponieważ istnieje pętla for do zliczania wartości w zakresie.

Jedna wkładka:

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

Długa wersja

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

Podaj daty pomiędzy:

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

Dni od minionej daty do teraz:

var daylist = getDaysArray(new Date("2018-05-01"),new Date());
daylist.map((v)=>v.toISOString().slice(0,10)).join("")
enesn
źródło
A co, jeśli chcesz pobrać wszystkie określone dni w getDaysArray? Nie dni między nimi.
Jonjie
dzięki! dokładnie to, czego potrzebowałem, bez zależności. :)
mpsyp
2
ta funkcja manipuluje datą wejściową źródła. :) Przetestowałem to.
Hamed Taheri
4
@ HamedTaheri - tak, ale można to naprawić, przypisując kopię startu do dt zamiast uruchamiania samego siebie, np for (var arr=[], dt=new Date(start), ...). ;-)
RobG
działa dobrze, ale szkoda, pętla for (;;) nie jest tak czytelna dla konserwacji oprogramowania, gdy pracujesz z wieloma innymi osobami.
Victor
27

Używam moment.js i Twix.js, które zapewniają bardzo dobre wsparcie dla manpulacji daty i czasu

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

Mam to uruchomione na http://jsfiddle.net/Lkzg1bxb/

Ahmed Aswani
źródło
Pobrałem wszystkie pliki z nim związane, ale nadal pokazuje błąd TypeError: moment.twix nie jest funkcją
vaibhav kulkarni
Może być konieczne dołączenie bibliotek. W nodejs wygląda to tak, 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
źródło
3
Aby być bezpiecznym, w przeciwieństwie do powyższego, zwykle należy wybrać porę dnia w środku dnia, aby uniknąć niewielkich wahań wynikających z czasu letniego.
Phrogz
Chciałbym, żebyś dodał również zmianę w środku dnia do kodu.
kurczaki
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
źródło
1
Może się to zawiesić, jeśli podasz daty w niewłaściwej kolejności
pie6k
11

Jeśli używasz momentu, możesz użyć ich „oficjalnej wtyczki” do określania zakresów moment-rangei wtedy staje się to trywialne.

przykład węzła moment-zakres:

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

Przykład przeglądarki zakresu momentu:

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>

przykład daty fns:

Jeśli używasz, date-fnsto eachDayjest twoim przyjacielem i otrzymujesz zdecydowanie najkrótszą i najbardziej zwięzłą odpowiedź:

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
źródło
8

Właśnie natknąłem się na to pytanie, najłatwiej to zrobić za pomocą momentu:

Najpierw musisz zainstalować moment i zakres momentu:

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)
Irfy
źródło
6

Od jakiegoś czasu korzystam z rozwiązania @Mohammed Safeer i wprowadziłem kilka ulepszeń. Używanie sformatowanych dat jest złą praktyką podczas pracy w kontrolerach. moment().format()powinny być używane tylko do celów wyświetlania w widokach. Pamiętaj również, że moment().clone()zapewnia to oddzielenie od parametrów wejściowych, co oznacza, że ​​daty wejściowe nie są zmieniane. Gorąco zachęcam do korzystania z moment.js podczas pracy z datami.

Stosowanie:

  • Zapewnić moment.js dat jako wartości startDate, endDateparametry
  • intervalparametr jest opcjonalny i ma wartość domyślną „dni”. Użyj interwałów wspieranych przez .add()metodę (moment.js). Więcej szczegółów tutaj
  • totalparametr jest przydatny podczas określania interwałów w minutach. Domyślnie 1.

Odwołać się:

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

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

Funkcjonować:

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
źródło
6

Używając ES6 masz Array. od co oznacza, że ​​możesz napisać naprawdę elegancką funkcję, która pozwala na dynamiczne interwały (godziny, dni, miesiące).

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
źródło
2
„Elegancki” zależy od Twojego punktu widzenia. new Date(2017,12,30)jest 30 stycznia 2018 r., dla mnie zakres dat zaczyna się 29 stycznia 2018 r. Nie wszystkie dni mają długość 8,64e7 ms (24 godziny), w których obserwuje się czas letni. ;-)
RobG
5

Niedawno pracowałem z moment.js, podążając za rozwiązaniami ..

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

Wynik byłby:

["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
źródło
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
źródło
1
Dodaj więcej opisów i / lub informacji o swojej odpowiedzi i sposobie rozwiązania
zadanego
Uważam, że z jakiegoś powodu pomijam 31.03.2016!
woodhead92
1
Nie powinieneś mieć varwcześniej strDatewewnątrz pętli while!
Boris Yakubchik
2

d3js zapewnia wiele przydatnych funkcji i zawiera d3.time do łatwej manipulacji datami

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

Na specjalne życzenie:

Utc

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

lub czasu lokalnego

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

zakres będzie tablicą obiektów dat, które przypadają na pierwszą możliwą wartość każdego dnia

Możesz zmienić czas z dnia na godzinę, godzinę, miesiąc itp., aby uzyskać te same wyniki w różnych odstępach czasu

Russella Thompsona
źródło
2

Oto jedna linijka, która nie wymaga żadnych bibliotek na wypadek, gdybyś nie chciał tworzyć innej funkcji. Po prostu zastąp startDate (w dwóch miejscach) i endDate (które są obiektami daty js) zmiennymi lub wartościami dat. Oczywiście, jeśli wolisz, możesz umieścić go w funkcji

Array(Math.floor((endDate - startDate) / 86400000) + 1).fill().map((_, idx) => (new Date(startDate.getTime() + idx * 86400000)))
ti994a
źródło
to nie bierze pod uwagę zmian czasu letniego / standardowego. Niektóre dni są dłuższe, a inne krótsze
Mike
2

Używam tej funkcji

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
źródło
2

Używam prostej pętli while do obliczania dat między datami

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
źródło
1

Uwaga: zdaję sobie sprawę, że jest to nieco inne niż żądane rozwiązanie, ale myślę, że wielu uzna to za przydatne.

Jeśli chcesz znaleźć każdy interwał „x” (dni, miesiące, lata itd.) Między dwiema datami, momentem.js i zakresem chwil pakiety rozszerzenia włącz tę funkcję.

Na przykład, aby znaleźć każdy 30 dzień między dwiema datami :

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'))
});
Złóg
źródło
1
  1. Wygeneruj tablicę lat:

    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. Wygeneruj tablice na miesiąc:

            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. Wygeneruj tablice na dni:

            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
źródło
1

Możesz to łatwo zrobić za pomocą momentJS

Dodaj chwilę do swoich zależności

npm i moment

Następnie zaimportuj to do swojego pliku

var moment = require("moment");

Następnie użyj poniższego kodu, aby uzyskać listę wszystkich dat między dwiema datami

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
źródło
0

To może komuś pomóc,

Możesz z tego pobrać dane wyjściowe wiersza i sformatować obiekt row_date, jak chcesz.

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
źródło
0

Oto gotowa metoda, która zaakceptuje daty lub ciągi znaków lub ich mieszaninę jako dane wejściowe i wygeneruje tablicę dat jako daty Moment. Jeśli nie chcesz, aby daty Moment były danymi wyjściowymi, zmień to, co map()zwraca metoda.

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'));
};
Chłopak
źródło
0

@ softvar, ale z opcją daty pracy

/**
 * 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
źródło
0

Funkcjonować:

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

Stosowanie:

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

Mam nadzieję, że ci to pomoże

Nelson Dang
źródło