使用JavaScript循环遍历日期范围

185

如果有两个Date()对象,其中一个比另一个小,那么我如何在这两个日期之间循环每一天?

for(loopDate = startDate; loopDate < endDate; loopDate += 1)
{

}

这种循环会起作用吗?但是如何在循环计数器中加一天?

谢谢!

12个回答

294

以下是一种通过利用添加一天的方式使日期在必要时滚动到下一个月的方法,而不需要与毫秒数打交道,也不会涉及夏令时问题。

var now = new Date();
var daysOfYear = [];
for (var d = new Date(2012, 0, 1); d <= now; d.setDate(d.getDate() + 1)) {
    daysOfYear.push(new Date(d));
}

请注意,如果想要存储日期,您需要创建一个新的日期对象(如上述代码中使用new Date(d)),否则您将得到在循环中d的最终值作为每个存储日期的结果。


1
比其他答案更易读。每个循环添加86400000毫秒不太易读。 - Owen
6
注意夏令时。当日期为 GMT N 时,d.getDate() + 1 返回的是 GMT N - 1。在这种情况下,d.getDate() + 1 会返回相同的月份中的同一天两次。请注意。 - Rafael Fontes
1
为什么在定义“now”时要使用Date.now()new Date() 默认情况下返回当前日期对象。如果没有使用new构造函数调用Date,则只会得到一个日期字符串,您还需要将其转换为日期对象。 - tatlar
我在互联网上尝试了多种解决方案。奇怪的是,有时会跳过几天,比如1.12、2.12、3.12、5.12...(注意4.12被跳过了),我不知道为什么会这样... 有人遇到过这个问题并找到了解决方案吗? - Erik Kubica
1
d = new Date('2019-03-31') d.setDate(d.getDate() + 1) d.toISOString().slice(0, 10) // 2019-03-31^^ 失败。 - Mirek Rusin
显示剩余4条评论

93

基于Tom Gullen的回答。

var start = new Date("02/05/2013");
var end = new Date("02/10/2013");


var loop = new Date(start);
while(loop <= end){
   alert(loop);           

   var newDate = loop.setDate(loop.getDate() + 1);
   loop = new Date(newDate);
}

3
@DevAllanPer,Date 是一个全局对象。https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Date - Dmitri Pisarev
loop = new Date(newDate); is not needed. You already set loop with loop.setDate(loop.getDate() + 1); - Jan

16

我认为我找到了一个更简单的答案,如果你允许使用Moment.js

// cycle through last five days, today included
// you could also cycle through any dates you want, mostly for
// making this snippet not time aware
const currentMoment = moment().subtract(4, 'days');
const endMoment = moment().add(1, 'days');
while (currentMoment.isBefore(endMoment, 'day')) {
  console.log(`Loop at ${currentMoment.format('YYYY-MM-DD')}`);
  currentMoment.add(1, 'days');
}
<script src="https://cdn.jsdelivr.net/npm/moment@2/moment.min.js"></script>


12

这是一个简单的有效代码,对我而言可运行

var from = new Date(2012,0,1);
var to = new Date(2012,1,20);
    
// loop for every day
for (var day = from; day <= to; day.setDate(day.getDate() + 1)) {
   // your day is here
   console.log(day)
}


11

如果 startDate 和 endDate 确实是日期对象,您可以将它们转换为自1970年1月1日午夜以来的毫秒数,例如:

var startTime = startDate.getTime(), endTime = endDate.getTime();

然后您可以从一个循环到另一个循环,通过每次增加86400000(一天中的毫秒数,即1000 * 60 * 60 * 24)来增加loopTime:

for(loopTime = startTime; loopTime < endTime; loopTime += 86400000)
{
    var loopDay=new Date(loopTime)
    //use loopDay as you wish
}

1
+1,给了我足够多的工作内容,我已经在我的问题中包含了可运行的解决方案。 - Tom Gullen
5
在穿越夏令时变更(在该地区存在此问题的情况下)时,这种方法无法正常工作。除此之外是个不错的解决方案。 - chadgh
5
不可以假设一天有 86400000 秒。这个循环容易受到夏令时变化和其他边缘情况的影响。 - Jeremy J Starcher
2
除了夏令时之外,另一个边缘条件是“闰秒”。一秒的差异确实很重要 - 转换为毫秒的日期对应于给定日期的第一秒。一秒钟的误差会导致你落在前一天。 - Wojtek Kruszewski

3
作为一个函数,

function getDatesFromDateRange(from, to) {
  const dates = [];
  for (let date = from; date <= to; date.setDate(date.getDate() + 1)) {
    const cloned = new Date(date.valueOf());
    dates.push(cloned);
  }
  return dates;
}

const start = new Date(2019, 11, 31);
const end = new Date(2020, 1, 1);

const datesArray = getDatesFromDateRange(start, end);
console.dir(datesArray);


3
var start = new Date("2014-05-01"); //yyyy-mm-dd
var end = new Date("2014-05-05"); //yyyy-mm-dd

while(start <= end){

    var mm = ((start.getMonth()+1)>=10)?(start.getMonth()+1):'0'+(start.getMonth()+1);
    var dd = ((start.getDate())>=10)? (start.getDate()) : '0' + (start.getDate());
    var yyyy = start.getFullYear();
    var date = dd+"/"+mm+"/"+yyyy; //yyyy-mm-dd

    alert(date); 

    start = new Date(start.setDate(start.getDate() + 1)); //date increase by 1
}

1

不想将结果存储在数组中,那么也许可以使用yield?

/**
 * @param {object} params
 * @param {Date} params.from
 * @param {Date} params.to
 * @param {number | undefined} params.incrementBy
 * @yields {Date}
 */
 function* iterateDate(params) {
    const increaseBy = Math.abs(params.incrementBy ?? 1);
    for(let current = params.from; current.getTime() <= params.to.getTime(); current.setDate(current.getDate() + increaseBy)) {
        yield new Date(current);
    }
}

for (const d of iterateDate({from: new Date(2021,0,1), to: new Date(2021,0,31), incrementBy: 1})) {
    console.log(d.toISOString());
}


1
基于Tabare的答案,我不得不在最后再添加一天,因为周期是在截断之前完成的。
var start = new Date("02/05/2013");
var end = new Date("02/10/2013");
var newend = end.setDate(end.getDate()+1);
var end = new Date(newend);
while(start < end){
   alert(start);           

   var newDate = start.setDate(start.getDate() + 1);
   start = new Date(newDate);
}

0

假设您从UI获取了开始日期和结束日期,并将其存储在控制器中的作用域变量中。

然后声明一个数组,每次函数调用都会重置该数组,以便在下一次调用函数时可以存储新数据。

var dayLabel = [];

记得使用new Date(您的起始变量),因为如果您不使用新日期并直接将其分配给变量,则setDate函数将在每次迭代中更改原始变量值。

for (var d = new Date($scope.startDate); d <= $scope.endDate; d.setDate(d.getDate() + 1)) {
                dayLabel.push(new Date(d));
            }

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