【问题标题】:Round number of weeks per months in ISO format (week counts if crossed Thursday)ISO 格式的每个月的周数(如果在星期四交叉,则计算周数)
【发布时间】:2018-10-13 18:55:33
【问题描述】:

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

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

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

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

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

据说其余的有 4 周。

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

如果我不在 cmets 中应用建议的修复程序,请编辑,我将在 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 不应该在一个月内同时触发,但我认为这根本不会发生。

我猜错了,但除此之外它仍然不对应正确的月份。那么现在是什么?

【问题讨论】:

  • 我明白了:我使用月份开始和月份结束,而不是从星期四开始计算。这就是造成差异的原因。现在我只需要弄清楚如何判断给定的一周是否已经过了星期四。
  • 啊 MometJS 有一个weekday() 函数!容易多了!

标签: javascript angular date momentjs


【解决方案1】:

基于周的日历有一些属性。 第四天始终是基于周和基于月的日历“月”或“年”的一部分。时间段结束前的第四天也是如此。

function getWeeksInMonth(year, month)
{
    // 4th day of the month
    const start_date = new Date(year, month, 4);
    // 1st day of next month -4 day
    const end_date = new Date(year, month + 1, -3);
    // (0 || 7) => 7, it's a fix: ISO sundays have a number of 7, not 0
    // how much days must be added at the beginning
    const start_delta = (start_date.getDay() || 7) - 1;
    // how much days must be added at the end
    const end_delta = 7 - (end_date.getDay() || 7);
    // how much days are between the two dates
    // replace knowing if the month is 28/29/30/31 days long
    const between_delta = Math.round((end_date - start_date) / 86400000);
    // divided by 7 to get the number of weeks
    return Math.floor((start_delta + between_delta + end_delta) / 7);
}

【讨论】:

  • 抱歉不是这样。我正在研究我自己的答案。重新阅读我发表的评论。
【解决方案2】:

我没有按照您的方法来确定该月的周数。我的方法是计算第一个星期四之后剩下的天数:如果有 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));
}
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment.min.js"&gt;&lt;/script&gt;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多