javascript - 采用 ISO 格式的每月周数(如果跨过星期四则算周数)

标签 javascript angular date momentjs

根据 ISO 标准,我每月需要整数周。

而且我使用的是 momentJS 而不是 Js 的 Date。

根据 ISO 日期格式,如果该月有星期四,则计算该月的周数,否则计算上个月的周数。

据此,今年四舍五入周数为 5 的月份 ( 2018 ) 是:

火星、五月、八月和十一月

据说其余的有 4 周。

这是我的代码(灵感 here ):

编辑,如果我不应用评论中建议的修复,我最终会在 2018 年 12 月花费 1 周的时间,与 2017 年相同。

ngOnInit() {
  this.generateTimelineForGivenYear('2018');
}

generateTimelineForGivenYear(year){
  for (let i = 1; i < 13; i++) {
    let month;
    if (i < 10) month = '0'.concat(i.toString());
    else month = i;
    this.howManyWeeksForGivenMonth(moment(year + '-'+ month + '-05'));
  }
}

howManyWeeksForGivenMonth(myDate){
  console.log('The Month : ', myDate.month() + 1);
  const start = myDate.clone().startOf('month').week();
  let end = myDate.clone().endOf('month').week();
  if( start > end ){ end = 52 + end }
  const res =  end - start;
  console.log('The Number of Weeks: ', res);
  console.log('----------------------------------------------------');
}

我的结果:

The Month :  1
The Number of Weeks:  4
----------------------------------------------------
The Month :  2
The Number of Weeks:  4
----------------------------------------------------
The Month :  3
The Number of Weeks:  4
----------------------------------------------------
The Month :  4
The Number of Weeks:  4
----------------------------------------------------
The Month :  5
The Number of Weeks:  4
----------------------------------------------------
The Month :  6
The Number of Weeks:  4
----------------------------------------------------
The Month :  7
The Number of Weeks:  4
----------------------------------------------------
The Month :  8
The Number of Weeks:  4
----------------------------------------------------
The Month :  9
The Number of Weeks:  5
----------------------------------------------------
The Month :  10
The Number of Weeks:  4
----------------------------------------------------
The Month :  11
The Number of Weeks:  4
----------------------------------------------------
The Month :  12
The Number of Weeks:  5
----------------------------------------------------

如你所见,我得到了两个月个月,即 5 周,但也不正确:

九月和十二月

我也尝试过:

howManyWeeksForGivenMonth(myDate){
  console.log('The Month : ', myDate.month() + 1);
  const first = myDate.day() == 0 ? 6 : myDate.day()-1;;
  const day = 7-first;
  const last = myDate.daysInMonth();
  let res = Math.floor((last-day)/7);
  if ((last-day) % 7 !== 0) res++;
  console.log('The Number of Weeks: ', res);
  console.log('----------------------------------------------------');
}

这给出了:

The Month :  1
The Number of Weeks:  4
----------------------------------------------------
The Month :  2
The Number of Weeks:  3
----------------------------------------------------
The Month :  3
The Number of Weeks:  4
----------------------------------------------------
The Month :  4
The Number of Weeks:  4
----------------------------------------------------
The Month :  5
The Number of Weeks:  5
----------------------------------------------------
The Month :  6
The Number of Weeks:  4
----------------------------------------------------
The Month :  7
The Number of Weeks:  4
----------------------------------------------------
The Month :  8
The Number of Weeks:  5
----------------------------------------------------
The Month :  9
The Number of Weeks:  4
----------------------------------------------------
The Month :  10
The Number of Weeks:  4
----------------------------------------------------
The Month :  11
The Number of Weeks:  4
----------------------------------------------------
The Month :  12
The Number of Weeks:  4
----------------------------------------------------

...没有更好。

我做错了什么?

更新:

一旦发现我周四没有剪辑是问题所在,这是我的新尝试:

howManyWeeksForGivenMonth(myDate){
    console.log('The Month ', myDate.month() + 1 );

    let weeks = 4
    if(myDate.clone().startOf('month').weekday() >= 5 ){
        weeks ++;
        console.log('first week extra');
    }

    if(myDate.clone().endOf('month').weekday() < 5 ) {
        weeks ++;
        console.log('last week extra');
    }

    return weeks;
}

我明白了:

The Month  1
last week extra
5
The Month  2
last week extra
5
The Month  3
4
The Month  4
last week extra
5
The Month  5
last week extra
5
The Month  6
first week extra
5
The Month  7
last week extra
5
The Month  8
4
The Month  9
first week extra
last week extra
6
The Month  10
last week extra
5
The Month  11
4
The Month  12
first week extra
last week extra
6

这里没有什么可读的,只是纯粹的垃圾。

显然,我知道两个 if 永远不应该在一个月内同时触发,但我原以为这根本不会发生。

我认为是错的,但除此之外它仍然不对应于正确的月份。那么现在是什么情况呢?

最佳答案

我不遵循您确定当月周数的方法。我的方法是计算第一个星期四之后还剩下多少天:如果有28天或更多,则有5周。否则有 4 个。

/* @param {number} year - full year
** @param {number} month - calendar month number (Jan = 1, Feb = 2, etc.)
** @returns {number} weeks in month
*/
function weeksInMonth(year, month) {
  // Create a Date for the given year and month
  var d = new Date(year, month-1, 1);
  // Get the number of days in the month
  var daysInMonth = new Date(year, month, 0).getDate();
  // Get date of first Thursday
  var firstThuDate = (11 - d.getDay()) % 7 + 1;
  // Get number of days in month after 1st Thursday
  var daysLeft = daysInMonth - firstThuDate;
  // If there are 28 or more days left, there are 5 weeks
  // Otherwise, there are 4
  return daysLeft > 27? 5 : 4;
}

// Weeks in 2018 months
for (var i=0; i<12; i++) {
  var monthName = new Date(2018,i).toLocaleString(undefined, {month:'short'});
  console.log(monthName + ' 2018: ' + weeksInMonth(2018,i+1));
}

当然,您可以将上面的代码减少到更少的代码,这是为了算法的清晰而编写的。

使用 moment.js 的相同算法:

// Count ISO weeks in month
function weeksInMonth(year, month) {
  // Create moment object
  var d = moment([year, month - 1, 1]);
  // Get date of first Thursday
  var firstThu = d.weekday(4).date();;
  // Subtract from last day of month
  var daysLeft = d.endOf('month').date() - firstThu;
  // If days left > 27, there are 5 weeks
  // Otherwise there are 4
  return daysLeft > 27 ? 5 : 4;
}

// Weeks in 2018 months
for (var i=0; i<12; i++) {
  var monthName = new Date(2018,i).toLocaleString(undefined, {month:'short'});
  console.log(monthName + ' 2018: ' + weeksInMonth(2018,i+1));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment.min.js"></script>

关于javascript - 采用 ISO 格式的每月周数(如果跨过星期四则算周数),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50155397/

相关文章:

javascript - 如何使用 jasmine 测试 setTimeout 中的 spy ?

Angular 2 访问基础 href

c# - 在 TextBoxFor() 中显示格式化日期

java - 根据格式将字符串日期验证为有效日期的最佳方法是什么?

javascript - 奇怪的 JavaScript 作用域问题

javascript - connect-flash 和 jade : unable to show flash messahe

javascript - 将逗号添加到 NgFor 列表的最佳方法

angular - 从 Angular 2 中的指令调用组件的方法

angular - rxjs 根据第一个答案返回不同的 Observable

java - 在一行中设置日期