Круглое число недель в месяцах в формате ISO (неделя считается, если она пересечена в четверг) - PullRequest
0 голосов
/ 03 мая 2018

Мне нужно круглое количество недель в месяц согласно стандарту ISO.

Кроме того, я использую momentJS вместо даты Js.

в соответствии с форматом даты ИСО неделя считается для этого месяца, если у нее четверг, в противном случае она считается для предыдущего месяца.

в соответствии с тем, что число округленных недель в этом году равно 5 ( 2018 ):

Марс, май, август и ноябрь

говорят, что у остальных 4 недели.

Вот мой код (вдохновение здесь ):

РЕДАКТИРОВАТЬ, если я не применяю предложенное исправление в комментариях, у меня останется 1 неделя для декабря месяца на 2018 год, то же самое для 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

здесь нечего читать, это просто мусор.

Очевидно, я понимаю, что оба ifs никогда не должны запускаться вместе в течение одного месяца, но я предполагал, что это просто не произойдет.

Я предположил, что неправильно, но, кроме того, это все еще не соответствует правильным месяцам. так что это сейчас?

Ответы [ 2 ]

0 голосов
/ 04 мая 2018

Я не следую вашему методу определения количества недель в месяце. Мой подход заключается в подсчете количества дней, оставшихся после первого четверга: если их 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>
0 голосов
/ 03 мая 2018

В недельных календарях есть несколько свойств. Четвертый день всегда является частью календаря, основанного как на неделе, так и на месяце "месяц" или "год". То же самое для четвертого дня до конца периода времени.

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);
}
...