【问题标题】:How to enumerate dates between two dates in Moment如何枚举 Moment 中两个日期之间的日期
【发布时间】:2014-07-10 19:46:10
【问题描述】:

我有两个moment 日期:

var fromDate = moment(new Date('1/1/2014'));
var toDate   = moment(new Date('6/1/2014'));

moment 是否提供了一种方法来枚举这两个日期之间的所有日期?

如果没有,除了创建一个循环将fromDate 递增1 直到到达toDate 之外,还有什么更好的解决方案吗?

编辑:添加日期枚举方法及问题

我已经模拟了一种方法来枚举两个日期之间的天数,但我遇到了一个问题。

  var enumerateDaysBetweenDates = function(startDate, endDate) {
    var dates = [];

    startDate = startDate.add(1, 'days');

    while(startDate.format('M/D/YYYY') !== endDate.format('M/D/YYYY')) {
      console.log(startDate.toDate());
      dates.push(startDate.toDate());
      startDate = startDate.add(1, 'days');
    }

    return dates;
  };

看看我运行enumerateDaysBetweenDates( moment(new Date('1/1/2014')), moment(new Date('1/5/2014'));时的输出

Thu Jan 02 2014 00:00:00 GMT-0800 (PST)
Fri Jan 03 2014 00:00:00 GMT-0800 (PST)
Sat Jan 04 2014 00:00:00 GMT-0800 (PST)
[ Sun Jan 05 2014 00:00:00 GMT-0800 (PST),
  Sun Jan 05 2014 00:00:00 GMT-0800 (PST),
  Sun Jan 05 2014 00:00:00 GMT-0800 (PST) ]

这是 console.logging 正确的日期,但只有最后一个日期被添加到数组中。这是怎么/为什么?这闻起来像是某种变量引用问题 - 但我没有看到它。

【问题讨论】:

    标签: javascript momentjs


    【解决方案1】:

    使用 moment 库和 for 循环,您可以在两个日期之间进行枚举。

    const moment = require('moment');
    
     let startDate = moment('2021-12-24');
     let endDate = moment('2022-1-4');
     let date = [];
    
     for (var m = moment(startDate); m.isSameOrBefore(endDate); m.add(1, 'days')) {
          date.push(m.format('DD/MM/YYYY'));
      }
    
     console.log(date)

    【讨论】:

      【解决方案2】:

      使用 ES6 表示法

      const from = moment('01/01/2014', 'DD/MM/YYYY')
      const to   = moment('06/01/2014', 'DD/MM/YYYY')
      
      const nbDays = to.diff(from, 'days') + 1
      const result = [...Array(nbDays).keys()]
                .map(i => from.clone().add(i, 'd'))
      
      console.log(result)
      <script src="https://momentjs.com/downloads/moment.min.js"></script>

      【讨论】:

        【解决方案3】:

        使用moment libraryfor loop,您可以在两个日期之间进行枚举。

        let startDate = moment('2020-06-21');
        let endDate = moment('2020-07-15');
        let date = [];
        
        for (var m = moment(startDate); m.isBefore(endDate); m.add(1, 'days')) {
            date.push(m.format('YYYY-MM-DD'));
        }
        
        console.log(date)
        <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>

        【讨论】:

        • 如果 startDate == endDate 并且我需要数组为 ['2020-06-21','2020-06-21'],如何重写此代码? @Tyagi
        【解决方案4】:

        使用 moment 并使用 while 循环,代码将循环运行,直到 startDate 等于 endDate 并推送 startDate,然后将其增加 1 天,以便获得下一个日期

        function enumerateDaysBetweenDates (startDate, endDate){
          let date = []
          while(moment(startDate) <= moment(endDate)){
            date.push(startDate);
            startDate = moment(startDate).add(1, 'days').format("YYYY-MM-DD");
          }
          return date;
        }
        

        你可以通过调用这样的函数来测试它

        let dateArr = enumerateDaysBetweenDates('2019-01-01', '2019-01-10');
        

        【讨论】:

        • 如果 startDate == endDate 并且我需要数组为 ['2020-06-21','2020-06-21'],如何重写此代码?
        【解决方案5】:

        您可以使用moment.js 轻松枚举以下是几天、几周、几个月或几年的更通用解决方案:

        https://gist.github.com/gvko/76f0d7b4b61b18fabfe9c0cc24fc3d2a

        【讨论】:

        • @AdarshMadrecha 页面未找到。
        【解决方案6】:

        Momentjs 本身不提供此功能,但有一个插件可提供此功能:moment-range

        具体来说,请查看Iteration docs

        【讨论】:

          【解决方案7】:

          为你准备好了:

          var enumerateDaysBetweenDates = function(startDate, endDate) {
              var now = startDate.clone(), dates = [];
          
              while (now.isSameOrBefore(endDate)) {
                  dates.push(now.format('M/D/YYYY'));
                  now.add(1, 'days');
              }
              return dates;
          };
          

          引用now 而不是startDate 带来了不同。

          如果您不进行包容性搜索,请将 .isSameOrBefore 更改为 .isBefore

          小提琴: http://jsfiddle.net/KyleMuir/sRE76/118/

          【讨论】:

          • 必须将 now.format('M/D/YYYY') &lt;= endDate.format('M/D/YYYY') 换成 now.isBefore(endDate) 才能正常工作
          • @Mangopop 谢谢,我已经更新了我的答案以包含更好的方法。我还添加了|| now.isSame(endDate),因为最初的答案是包含 endDate。
          • 超级。还使用了 Set 上的 spread 以在多个日期范围上使用它,并在日期范围重叠时获得一组没有重复的结果:stackoverflow.com/a/32000937/756177
          • 你可以用now.isSameOrBefore(endDate)代替now.isBefore(endDate) || now.isSame(endDate)moment docs here
          • @Sabin 谢谢你。我已更新此答案以反映新方法。
          【解决方案8】:

          .add()是一个mutator方法,所以这行的赋值是不必要的:

          startDate = startDate.add(1, 'days');
          

          您可以这样做,并且具有相同的效果:

          startDate.add(1, 'days');
          

          虽然它的名字意味着创建一个新的Date 对象,但toDate() 方法实际上只是返回现有的内部Date 对象。

          因此,您的方法调用都没有创建新的 Datemoment 对象实例。通过使用.clone() 获取新实例来解决此问题:

          startDate = startDate.clone().add(1, 'days');
          

          或者更好的是,将值包装在对moment() 的调用中,就像Mtz 在评论中建议的那样,如果该值是一个时刻对象,它将克隆实例,或者它会解析输入以创建一个新的时刻实例。

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

          我认为日期枚举器方法不应更改传入的任何一个参数。我会创建一个单独的变量来进行枚举。我也会直接比较日期,而不是比较字符串:

          var enumerateDaysBetweenDates = function(startDate, endDate) {
              var dates = [];
          
              var currDate = moment(startDate).startOf('day');
              var lastDate = moment(endDate).startOf('day');
          
              while(currDate.add(1, 'days').diff(lastDate) < 0) {
                  console.log(currDate.toDate());
                  dates.push(currDate.clone().toDate());
              }
          
              return dates;
          };
          

          【讨论】:

          • 不知道克隆方法。甜的!谢谢。
          • 请注意moment().add(period, number) is deprecated. Please use moment().add(number, period)
          • 对参数顺序开关很感兴趣。我猜他们这样做是为了让一系列日期操作函数读起来更像是一个英文句子,但如果你想将 Moment 与柯里化/部分应用程序库一起使用,你会想要.add(period, number),不是吗?跨度>
          • 而不是经典,而我使用“do{} while (condition)”不跳过第一天
          • 我会做var currDate = moment(startDate).startOf('day')lastDate 一样,因为这样输入不需要是moment 实例,而是可以是moment 可以处理的任何东西。如果它已经是 moment 实例,它会自动创建一个克隆,所以它是等价的。
          【解决方案9】:

          作为 Kyle 答案的扩展 - 我一直在尝试让它与 Unix 时间戳一起使用,经过大量试验和错误后,我让它工作并认为我会在这里发布它以防万一有人寻求相同东西和需要它。请参阅下面的代码:

          fromDate = moment.unix(req.params.dateFrom).format('YYYY-MM-DD')
          toDate = moment.unix(req.params.dateTo).format('YYYY-MM-DD')
          
          // Returns an array of dates between the two dates
          function enumerateDaysBetweenDates(startDate, endDate) {
              startDate = moment(startDate);
              endDate = moment(endDate);
          
              var now = startDate, dates = [];
          
              while (now.isBefore(endDate) || now.isSame(endDate)) {
                  dates.push(now.format('YYYY-MM-DD'));
                  now.add(1, 'days');
              }
              return dates;
          };
          

          请注意,我将其转换为 Unix,然后再将该值转换为 moment。这是我遇到的问题,您需要再次将其设为时刻值才能使其正常工作。

          示例用法:

          fromDate = '2017/03/11' // AFTER conversion from Unix
          toDate = '2017/03/13' // AFTER conversion from Unix
          
          console.log(enumerateDaysBetweenDates(fromDate, toDate));
          

          将返回:

          ['2017/03/11', '2017/03/12', '2017/03/13']
          

          【讨论】:

            猜你喜欢
            • 2022-06-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-08-15
            相关资源
            最近更新 更多