【问题标题】:How to get list of days in a month with Moment.js如何使用 Moment.js 获取一个月中的天数列表
【发布时间】:2014-08-31 02:27:09
【问题描述】:

使用 Moment.js 我想在一个数组中获取特定年份一个月中的所有天数。例如:

January-2014:
[
"01-wed",
"02-thr",
"03-fri",
"04-sat"
]

有什么建议吗?我浏览了 Moment.js 文档,但找不到任何东西。我得到的壁橱是这样的:

moment("2012-02", "YYYY-MM").daysInMonth() 

但这只会返回一个整数,其中包含特定月份的总天数,而不是每天的数组。

【问题讨论】:

  • 我假设应该是"04-sat"而不是"04-say",然后是"05-sun", "06-mon", "07-tue", "08-wed"等等?为什么需要这个?
  • 是的,说是错字。我需要将其显示在下拉列表中,以便用户可以在年月组合中选择一年,然后是一个月,然后是一天。但除了显示 1,2,3... 的日子,我还想显示日期名称 1-mon, 2-tues, 3-wed...
  • 在下面查看我的答案。不过,为了让某人选择日期,我建议使用众多可用的 JavaScript 日历日期选择器之一。
  • 我将使用日期选择器来处理我正在开发的日历插件中的其他内容,但对于应用程序的这个特定部分,它需要是一个下拉菜单。感谢您的回答。

标签: javascript node.js momentjs


【解决方案1】:

这是一个可以解决问题的函数(不使用 Moment,而只是使用原生 JavaScript):

var getDaysArray = function(year, month) {
  var monthIndex = month - 1; // 0..11 instead of 1..12
  var names = [ 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat' ];
  var date = new Date(year, monthIndex, 1);
  var result = [];
  while (date.getMonth() == monthIndex) {
    result.push(date.getDate() + '-' + names[date.getDay()]);
    date.setDate(date.getDate() + 1);
  }
  return result;
}

例如:

js> getDaysArray(2012,2)
["1-wed", "2-thu", "3-fri", "4-sat", "5-sun", "6-mon", "7-tue",
 "8-wed", "9-thu", "10-fri", "11-sat", "12-sun", "13-mon", "14-tue",
"15-wed", "16-thu", "17-fri", "18-sat", "19-sun", "20-mon", "21-tue", 
"22-wed", "23-thu", "24-fri", "25-sat", "26-sun", "27-mon", "28-tue",
"29-wed"]

ES2015+ 版本 - 还将名称数组隐藏在闭包后面,因此它只初始化一次:

const getDaysArray = (function() {
  const names = Object.freeze([ 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat' ]);
  return (year, month) => {
    const monthIndex = month - 1
    const date = new Date(year, monthIndex, 1);
    const result = [];
    while (date.getMonth() == monthIndex) {
      result.push(`${date.getDate()}-${names[date.getDay()]}`);
    date.setDate(date.getDate() + 1);
    }
    return result;
  }
})();

作为旁注,您可以看到声明日期 const 并不能阻止我们对其进行变异(Object.freeze 也不会,用于使工作日名称数组不可变,对 Date 做任何事情) .我们在这里利用了可变性,但如果我们真的想要一个不可变的 Date 并使用在当前 Javascript 中强制执行该不变性的语言,我们必须go to some length

另请注意,与问题中包含的示例输出不同,上述解决方案不会在 10 日之前补零日期。使用 ES2017+,这很容易修复:

    result.push(`${date.getDate()}`.padStart(2,'0') + `-${names[date.getDay()]}`);

在旧版本的 JS 中执行此操作需要滚动您自己的零填充逻辑,这并不难,但也不是问题的真正重点。

【讨论】:

    【解决方案2】:

    momentjs 的替代品,为我工作

    function getDaysArrayByMonth() {
      var daysInMonth = moment().daysInMonth();
      var arrDays = [];
    
      while(daysInMonth) {
        var current = moment().date(daysInMonth);
        arrDays.push(current);
        daysInMonth--;
      }
    
      return arrDays;
    }
    

    你可以检查

    var schedule = getDaysArrayByMonth();
    schedule.forEach(function(item) {
      console.log(item.format("DD/MM"));
    });
    

    【讨论】:

      【解决方案3】:

      下面是两个很好的函数式方法,除了 Moment 之外没有外部依赖:

      const currentMonthDates = new Array(moment().daysInMonth()).fill(null).map((x, i) => moment().startOf('month').add(i, 'days'));
      const currentMonthDates = Array.from({length: moment().daysInMonth()}, (x, i) => moment().startOf('month').add(i, 'days'));
      

      这将返回一个 Moment 对象数组,然后您可以在其上运行您希望的任何格式方法。

      为了进一步阅读Creating and filling Arrays of arbitrary lengths in JavaScript,还请注意,在第一个示例中,您必须在映射数组之前用 null 填充数组,因为在这样做之前它仍然被归类为空,因此 map 函数不会运行。

      【讨论】:

      • 您的代码仅适用于当前日期,如果我传递格式例如“'2020-01', 'YYYY-MM'”,日期计算不正确
      • @RavenTheX 您可以传入任何日期,只需将 moment() 的实例替换为 moment(date, format)。您的格式必须包含一天(不是 YYYY-MM),否则您没有起点来添加天数。如果您对日期进行硬编码,您始终可以将其设置为所需月份的第一天并省略 .startOf(month) 调用。
      【解决方案4】:

      您可以像这样使用来自lodash_.times 助手和时刻:

          var daysInMonth = [];
      
          var monthDate = moment().startOf('month'); // change to a date in the month of interest
      
          _.times(monthDate.daysInMonth(), function (n) {
          	 daysInMonth.push(monthDate.format('DD-ddd'));  // your format
          	 monthDate.add(1, 'day');
          });
          
          console.log(daysInMonth)
      <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>

      【讨论】:

      • 也许您可以改用 daysInMonth.push(monthDate.format('DD-ddd')); 来获得正确的预期格式
      【解决方案5】:

      您现在也可以使用moment range 来实现此目的:

      const month = moment('2012-02', 'YYYY-MM');
      const range = moment().range(moment(month).startOf('month'), moment(month).endOf('month'));
      const days = range.by('days');
      
      console.log([...days].map(date => date.format('DD-ddd')));
      

      【讨论】:

      【解决方案6】:

      我认为使用moment(month).daysInMonth()获取一个月中的天数的方法与Array.from()一起生成数组是更清洁和执行的方式。

      const getDaysByMonth = (month) => {
        const daysInMonth = moment(month).daysInMonth();
        return Array.from({length: daysInMonth}, (v, k) => k + 1)
      };
      
      let month = '2019-02';
      console.log(`February => ${getDaysByMonth(month)}`);
      
      month = '2019-06';
      console.log(`June => ${getDaysByMonth(month)}`);
      
      month = '2019-07';
      console.log(`July => ${getDaysByMonth(month)}`);
      &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"&gt;&lt;/script&gt;

      【讨论】:

        【解决方案7】:

        要使用moment.js 获得一个月中的天数,我使用这个:

          function daysInMonth(month) {
            var count =  moment().month(month).daysInMonth();
            var days = [];
            for (var i = 1; i < count+1; i++) {
              days.push(moment().month(month).date(i));
            }
            return days;
          }
        

        然后调用函数

        var days = daysInMonth( moment().month() );
        

        【讨论】:

          【解决方案8】:

          来到这个帖子制作日期选择器(是的......) - 我对最佳答案采用了类似的方法,但我认为 for 循环个人更直观/可读。这确实使用基于 JS 0 的日期,因此 5 = 六月、1 = 二月等 - 您可以在基于 1 的日期的日期中省略“+1”。

          var getDaysInMonth = function(year, month) {
            var names = [ 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat' ];
            var date = new Date(year, month + 1, 0);
            var days = date.getDate();
            var dayList = [];
            for (i = days; days > 0; days--) {      
              date.setDate(date.getDate() + 1);
              dayList.push((dayList.length + 1) + '-' + names[date.getDay()]);
            }
            return dayList;
          }
          

          【讨论】:

            【解决方案9】:
            function getAllDatesOfMonth(date) {
                const mDate = moment(date, "YYYY-MM");
                const daysCount = mDate.daysInMonth();
                return Array(daysCount).fill(null).map((v,index)=>{
                    const addDays = index === 0 ? 0 : 1;
                    return mDate.add(addDays, 'days').format('YYYY-MM-DD');
                });
            }
            

            【讨论】:

            • 你能解释一下你的代码在做什么 const addDays 吗?
            • mDate 最初是一个月的第一天。所以 const addDays 表示从第二次迭代开始增加天数。
            【解决方案10】:

            你可以用 for 循环来做到这一点

            var daysInMonth = [];
            
             var monthDate = moment().startOf('month'); 
            
             for(let i=0;i<monthDate.daysInMonth();i++){
                let newDay=monthDate.clone().add(i,'days');
                daysInMonth.push(newDay.format('DD-ddd')); 
            }
                
            console.log(daysInMonth)
            &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"&gt;&lt;/script&gt;

            【讨论】:

              【解决方案11】:

              从 moment.js 版本 2.1.0 开始,当您设置如下日期时:

                  moment([2012, 0, 31]).month(1).format("YYYY-MM-DD"); // 2012-02-29
              

              然后你只需要解析日期,你就有一个月的天数。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2016-06-03
                • 2022-01-13
                • 1970-01-01
                • 2015-01-06
                • 2011-10-19
                • 1970-01-01
                • 2017-10-22
                • 1970-01-01
                相关资源
                最近更新 更多