JavaScript - 获取2个日期之间的日期数组

293
var range = getDates(new Date(), new Date().addDays(7));
我希望“range”成为一个日期对象的数组,其中包括两个日期之间每一天的日期。关键是它还应该处理月份和年份的边界。

如果允许使用date-fns,可以使用eachDayOfInterval [1]和addDays [2]来返回开始日期和结束日期之间的日期数组。 - tinystone
34个回答

246
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
谢谢John。我主要使用的是你的,但是你有一个按引用传递的错误,在将currentDate推入数组时,你会得到一个由n个元素组成的数组,这些元素都是最后一个日期。将它更改为currentDate = new Date(currentDate)即可解决问题。 - Scott Klarenbach
这段代码在处理未来日期时是有效的,但如果我要处理30天前的过去日期,我应该在哪里更改代码以仅获取日期而非时间? - vaibhav kulkarni
@vaibhavkulkarni 你可以简单地反转addays()原型并修改while循环。此外,注释不是提出新问题的地方。 - John Hartsock
对我来说不起作用。跳过了几天,例如1.1.2017、1.2、1.4、1.5、1.7(月.日.年)。有什么想法吗? - Erik Kubica
对我来说运行得很好http://jsfiddle.net/cM3ZU/1326/,看看修改后的示例。我认为您可能会遇到日期格式问题。我使用m / d / yyyy作为我的格式。 - John Hartsock
显示剩余7条评论

149

我查看了上面所有的内容,最终自己写了出来。 你不需要momentjs一个普通的for循环就足够了,而且使用for循环更有意义,因为for循环是用来计算范围内的值的。

一行代码:

var getDaysArray = function(s,e) {for(var a=[],d=new Date(s);d<=new Date(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<=new Date(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("")

5
这个函数会修改输入的日期数据。 :) 我已经测试过了。 - Hamed Taheri
5
@HamedTaheri - 是的,但可以通过将start的副本分配给dt而不是直接分配start本身来解决这个问题,例如:for (var arr = [], dt = new Date(start), ...)。;-) - RobG
4
当日期跨度中发生时间更改(例如从夏令时/ DST切换到标准时间)时,这将无法按预期工作。你最终会少掉最后一天。但是可以通过明确设置时间来避免这种情况。 - Felix Wienberg
1
非常好用!不过,我会再作一点补充:将dt<=end改为dt<=new Date(end) - Srinath Kamath
1
你的返回值是 [] 吗?你需要输入日期对象,例如 new Date("2021-03-01"),而不仅仅是 "2021-03-01"。比如说,我一开始就忽略了这个。 - jave.web
显示剩余4条评论

78

试试这个,记得包含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;
}

只是一个小改进:建议使用简写符号来创建数组 var dateArray = []; 详情请见这里 - Adrian Moisa
这是定义数组的新方式,我认为它更简洁。 - Mohammed Safeer
2
重要修复:var currentDate = moment(startDate); 如果您在相同的moment.js日期上两次使用此方法,您将感到困惑,为什么它只能第一次工作。这是因为javascript通过引用传递对象,所以函数最终会使用两次已经改变的startDate。修补上述修复程序可以确保您在函数范围内使用新的和唯一的moment js对象。请查看此fiddle - Adrian Moisa
8
值得注意的是,不再推荐使用moment.js。该项目的开发已经停止,尽管它仍将被维护,但维护者建议寻找替代品。 - Albert MN.
1
只是添加一条注释,当与日期一起指定时间时,这将无法正常工作。 例如,getDates('2021-01-01 23:00:00','2021-01-04 22:00:00') 返回了 ["2021-01-01", "2021-01-02", "2021-01-03"],这不包括 2021-01-04 - Arun A S
谢谢,使用moment可以处理两个日期之间的大时间差:(getDates(new Date('2018-01-01'), new Date('2028-07-01')))。 - Rafiq

30

我在使用上面的答案时遇到了麻烦,由于本地夏令时(DST)造成的时区变化,日期范围中缺少了某些单日。我实现了一个使用UTC日期的版本来解决这个问题:

function dateRange(startDate, endDate, steps = 1) {
  const dateArray = [];
  let currentDate = new Date(startDate);

  while (currentDate <= new Date(endDate)) {
    dateArray.push(new Date(currentDate));
    // Use UTC date to prevent problems with time zones and DST
    currentDate.setUTCDate(currentDate.getUTCDate() + steps);
  }

  return dateArray;
}

const dates = dateRange('2020-09-27', '2020-10-28');
console.log(dates);

注意: 时区和夏令时的应用取决于你的locale,一般不建议改写。使用UTC时间可以解决大部分与时间有关的问题。

额外福利: 你可以通过可选的steps参数来设置要创建时间戳的时间间隔。如果你想设置每周的时间戳,将steps设置为7即可。


1
谢谢你。这非常有用。最终我在将其推入数组之前转换为ISO字符串。我可以看到自己将来会经常使用它。 - MarketerInCoderClothes
new Date(currentDate).toString(); 可能会有所帮助。 - Kanish

29

我使用 moment.jsTwix.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
你可能需要包含库。在Node.js中,它的写法是:var moment = require('moment'); require('twix'); - Dr Bala Soundararaj
我认为您可以使用toArray()而不是iterate()来简化这个问题:moment.twix(new Date('2012-01-15'),new Date('2012-01-20')).toArray("days"); http://isaaccambron.com/twix.js/docs.html#toarray - Kimeiga

25
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
我希望您也能将代码添加到中途更改。 - chickens

22
如果您正在使用moment,则可以使用它们的"官方插件"进行范围选择moment-range,然后这变得非常简单。
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')))

moment-range 浏览器示例:

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示例:

如果您正在使用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>


7
从v2.0.0开始,date-fns进行了重大更改,现在使用eachDayOfInterval()方法来代替以前的方法。以下是一个示例: 每天的时间间隔({ start: new Date(2014, 0, 10), end: new Date(2014, 0, 20) })可以这样表示: eachDayOfInterval( { start: new Date(2014, 0, 10), end: new Date(2014, 0, 20) } ) - Mads Hjorth

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

}

5
如果您提供的日期顺序不正确,程序将会出现冻结。 - Adam Pietrasiak

13
使用 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));


6
“优雅”这个词根据您的观点而异。对我来说,new Date(2017,12,30)是2018年1月30日,因此日期范围从2018年1月29日开始。在观察夏令时的地区,并不是所有的天数都是8.64e7毫秒(24小时)长的。;-) - RobG

9

我刚刚看到这个问题,最简单的方法是使用moment:

首先需要安装moment和moment-range:

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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接