在NodeJS中遍历日期范围

54

我想遍历一个日期范围,每次迭代增加一天。我会在Java中使用JodaTime构建的东西 - 在NodeJS中是否有类似的东西?

9个回答

160

你可以在 node.js 应用程序中使用 moment.js

npm install moment

那么你可以非常简单地这样做:

var moment = require('moment');

var a = moment('2013-01-01');
var b = moment('2013-06-01');

// If you want an exclusive end date (half-open interval)
for (var m = moment(a); m.isBefore(b); m.add(1, 'days')) {
  console.log(m.format('YYYY-MM-DD'));
}

// If you want an inclusive end date (fully-closed interval)
for (var m = moment(a); m.diff(b, 'days') <= 0; m.add(1, 'days')) {
  console.log(m.format('YYYY-MM-DD'));
}

嗯...这看起来很像你在自己回答中编写的代码。Moment.js是一个更受欢迎的库,有很多功能,但我想知道哪一个执行得更好?也许你可以进行测试并告诉我们。 :)

但是,这两个库都无法像JodaTime那样做到这一点。为此,您需要一个在JavaScript中实现TZDB的库。我在这里列出了一些

此外,请注意一般情况下JavaScript日期存在的问题。这也影响NodeJS。


2
我对date-utils的第二个时刻表示赞同。 - film42
在循环的增量部分中,使用moment 2.10 m.add(1,'days')。 - avances123
1
很棒的答案!请记住,在新的 moment 版本中,建议使用 m.add(1, 'days')(替换参数)弃用警告:moment().add(period, number) 已弃用。请使用 moment().add(number, period)。 - user659682
1
我遇到了一个问题,即范围的最后一天未被包括在内。我使用m.diff(b, 'days') <= 0代替m.isBefore(b)解决了这个问题。 - JohnnyQ
3
如果您想包括最后一天,可以使用m.isSameOrBefore(b) - mpen
显示剩余4条评论

33

我建议更改Matt之前的答复。他的代码将对a对象造成突变。尝试这样做...

var moment = require('moment');
var a = moment('2013-01-01');
var b = moment('2013-06-01');

for (var m = moment(a); m.isBefore(b); m.add(1, 'days')) {
    console.log(m.format('YYYY-MM-DD'));
}

var a = moment('2013-01-01'); 这样 a 已经是一个 moment,不需要 var m = moment(a)。应该这样写:for (var m = a; m.isBefore(b); m.add(1, 'days'))。此外,我认为我更喜欢使用 while 循环而不是建议的 for 循环。 - oyalhi
2
@oyalhi var m = a 仍会导致改变 a 的效果,因为它们都指向同一个 moment 对象。而通过执行 var m = moment(a),会生成一个新的 moment 对象并将其分配给 m,从而对 m 进行改变,而 a 保持不变。 - Guy
我不知道当时在想什么。谢谢你的澄清,@Guy。 - oyalhi

2

以下是一种不使用外部库的解决方案:

  var start = new Date('October 1, 2020 03:00:00Z');
  var now = new Date();

  for (var d = start; d < now; d.setDate(d.getDate() + 1)) {
    console.log(d);
  }

结果:
2020年10月1日 03:00:00
2020年10月2日 03:00:00
2020年10月3日 03:00:00
2020年10月4日 03:00:00
2020年10月5日 03:00:00
2020年10月6日 03:00:00

第一个日期末尾的Z表示UTC时间。如果您想要本地时间,请删除Z


1
使用https://github.com/JerrySievert/node-date-utils框架,你可以轻松地进行迭代,像这样:
require('date-utils');

var d = new Date('2013-01-01');
var e = new Date('2013-06-01');

for(var i = d; i.isBefore(e); i.addDays(1)) {
  console.log(i.toFormat("YYYY-MM-DD"));  
}

0

使用momentjs和lodash range的另一种方法:

let a = moment('2021-01-01');
let b = moment('2021-01-10');
_.range(b.diff(a, "d")).forEach((d) =>
  console.log(moment(a).add(d, "d").format("YYYY/MM/DD"))
);

如果您不想使用lodash,那么可以像这里所示获取范围。

[...Array(b.diff(a, "d")).keys()].forEach((d) =>
  console.log(moment(a).add(d, "d").format("YYYY/MM/DD"))
);

0

使用 moment 和 while 循环的另一种方法。
如果您想要一个独占的结束日期

let startDate = moment()
let endDate = moment().add(5, 'days')
while (endDate.isAfter(startDate)) {
    console.log(startDate.format('YYYY-MM-DD'))
    //increment by one day
   startDate = startDate.add(1, 'day')
}

如果您想要一个包含结束日期的话。
let startDate = moment()
let endDate = moment().add(5, 'days')
while (endDate.isSameOrAfter(startDate)) {
    console.log(startDate.format('YYYY-MM-DD'))
    //increment by one day
    startDate = startDate.add(1, 'day')
}

0

你可以不使用 moment 库来完成它。

for (const date = new Date(2022, 10, 1); date < new Date(2022, 11, 1); date.setDate(date.getDate() + 1)) {
  console.log(date)
}

或者甚至将其作为迭代函数

export function addDate(date: Date, value = 1) {
  const newDate = new Date(date)
  newDate.setDate(newDate.getDate() + value)
  return newDate
}

export function* iterateDate(startDate: Date, endDate: Date) {
  for (let date = startDate; date <= endDate; date = addDate(date))
    yield date
}

这样你就可以像这样迭代

for (const date of iterateDate(new Date('2022-10-01'), new Date()))
  console.log(date)

0

使用Ramdadate-fns的函数式方法:

R = require('ramda')
D = require('date-fns')

start = new Date('2013-01-01')
end = new Date('2013-06-01')

numDays = D.differenceInDays(end, start)
R.times(n => D.addDays(start, n), numDays)

-1

虽然有很多工具可以用于此,但将它们整合成一个有用的循环以检查数据可能会很麻烦。

这个应该能解决问题。可能有点过度,但你可以很容易地基于参数进行更多的调整。

var moment = require('moment');
var _ = require('lodash');

function(collectionsWithDateValues){
  var slots = [];
  var hours = {
    start: 7,   // 7am
    end: 21,    // 9pm
    window: 2   // How long each item should be slotted for.
  };
  var rightNow  = moment().add(0, 'days').hours(hours.start).minute(0).second(0);
  var cutoff    = moment(rightNow).add(14,'days'); // Check the next 2 weeks.
  for( rightNow ; rightNow.isBefore(cutoff) ; rightNow.add(hours.window, 'hours') ){
    // Check if we're going beyond the daily cutoff, go to the next day
    if(rightNow.isAfter(moment(rightNow).hour(hours.end))){
      rightNow.add(1, 'days').hour(hours.start);
    }
    var foundClash = false;
    _.forEach(collectionsWithDateValues,  function(item){
      // Check if the item is within now and the slotted time 
      foundClash = moment(item.date).isBetween(rightNow, moment(rightNow).add(hours.window, 'hours').subtract(1, 'minutes').seconds(59));
    });

    if(!foundClash){
      slots.push(rightNow.toString());
    }
  }
  return slots;
}

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