Подсчитать количество юбилеев между двумя датами?

#javascript #algorithm

#javascript #алгоритм

Вопрос:

Какой самый простой способ в Javascript вычислить количество юбилеев между двумя датами.

Моя попытка:

 module.exports.countAnniversariesBetweenTwoDates = (start_date, end_date, anniversary_date) => {

  if (start_date == end_date) {
    return 0;
  }

  let start_date_year = start_date.getFullYear();
  let end_date_year = end_date.getFullYear();
  let anniversary_year = anniversary_date.getFullYear();
  let start_date_month_and_day = Number(('0'   (start_date.getMonth()   1)).slice(-2)   ''   ('0'   start_date.getDate()).slice(-2));
  let end_date_month_and_day = Number(('0'   (end_date.getMonth()   1)).slice(-2)   ''   ('0'   end_date.getDate()).slice(-2));
  let anniversary_date_month_and_day = Number(('0'   (anniversary_date.getMonth()   1)).slice(-2)   ''   ('0'   anniversary_date.getDate()).slice(-2));

  let anniversary_count = 0;

  // special case for start year
  if (start_date_month_and_day < anniversary_date_month_and_day) {
    anniversary_count  ;
  }

  let temp_start_date_year = start_date_year   1;
  while(temp_start_date_year < end_date_year) {
    anniversary_count  ;
    temp_start_date_year  ;
  }

  // special case for end year
  if (end_date_month_and_day > anniversary_date_month_and_day) {
    anniversary_count  ;
  }
  return anniversary_count;
}
 

Комментарии:

1. Почему бы просто не преобразовать обе даты в миллисекунды и получить количество целых лет между ними?

2. Почему мне кажется, что для этого есть однострочное решение, ха-ха?

3. @MattMorgan Это может быть неточно, поскольку вы не учитываете високосные годы этим методом. Если пара часов не имеет большого значения, это замечательно. (Кроме того, не обе даты — достаточным условием будет количество целых лет между максимальной датой начала и годовщиной этого года и датой окончания.)

4. Вычтите годы, затем добавьте / вычтите 1 в зависимости от того, где дата годовщины попадает в диапазон. Что-то вроде end_year - start_year ( start_day_of_year < anniv_day_of_year ? -1 : 0) (end_day_of_year <= anniv_day_of_year ? 1 : 0)

5. я думаю, что решение @xdhmoore выглядит правильным!

Ответ №1:

Вот один, который учитывает високосные годы:

 function validDate(year, month, day) {
  var testDate = new Date(year, month, day);
  return testDate.getFullYear() === year amp;amp; testDate.getMonth() === month amp;amp; testDate.getDate() === day;
}

function countAnniversaries(begin, end, anniversary) {
  var countDate = new Date(anniversary.getTime());
  var anniversaries = 0;
  var countYear = begin.getFullYear();
  var anniversaryMonth = anniversary.getMonth();
  var anniversaryDay = anniversary.getDate();
  countDate.setFullYear(countYear);
  while (countDate.getTime() <= end.getTime()) {
    if (validDate(countYear, anniversaryMonth, anniversaryDay) amp;amp; countDate.getTime() >= begin.getTime()) {
      anniversaries  ;
    }
    countYear  ;
    countDate.setFullYear(countYear);  
    countDate.setMonth(anniversaryMonth);
    countDate.setDate(anniversaryDay);
  }
  return anniversaries;
}

console.log(countAnniversaries(new Date('Feb 1, 2012'), new Date('Feb 4, 2026'), new Date('Feb 2, 2012')))
console.log(countAnniversaries(new Date('Feb 1, 2012'), new Date('Feb 4, 2026'), new Date('Feb 29, 2012'))) 

Комментарии:

1. это юбилей? var countDate = new Date(begin.getTime());

2. Это дата, которая потенциально является годовщиной — она устанавливается, а затем проверяется, предшествует ли она дате окончания

3. но мне нужно знать, сколько раз определенный день / месяц (годовщина) встречается в диапазоне дат. т.е. нужно передать 3 параметра функции start_date, end_date and anniversary_date

4. отредактировано … countAnniversaries теперь принимает дату годовщины (игнорируя год)

5. Если вы спрашиваете, почему это 3 вместо 14 , это потому, что он учитывает только 29 февраля в високосные годы… если вы спрашиваете, почему это 3 вместо 4 , это потому, что юбилей открыт для интерпретации… Я отредактировал ответ, чтобы подсчитать год начала

Ответ №2:

Если вы используете moment.js вы можете просто получить разницу между двумя датами в виде лет, используя Math.floor() для округления в меньшую сторону до ближайшего полного числа лет.:

 yearDiff = Math.floor(moment(new Date(endDate)).diff(new Date(startDate),'years'));
 

Редактировать: приведенный выше код можно упростить немного больше:

 yearDiff = moment(endDate).diff(startDate,'years');
 

Возможно, вам придется написать дополнительный код для обработки периодов времени менее года или некоторых других особых случаев.

Вы могли бы, конечно, перебирать даты, похожие на то, как вы это делаете:

 var startDate = "03/08/2019";
var endDate = "01/01/2022";
var anniversary = "03/07/2015";
var anniversaryCount = 0;

var counterMoment = moment(startDate);
while (counterMoment.isSameOrBefore(endDate)) {
    var anniversaryThisYear = moment(anniversary).year(counterMoment.year());
    if (counterMoment.isSame(anniversaryThisYear)) {
        anniversaryCount  ;
    }
    counterMoment.add(1,'day');
}
alert("Number of anniversaries: " anniversaryCount);
 

Все зависит от того, каков конечный результат и как вы планируете использовать значение.

Комментарии:

1. решение не использует дату годовщины, или я запутался !?!

2. Если ваш период времени превышает год, он должен быть довольно точным, но, конечно, будут некоторые особые случаи, когда это не даст вам правильного результата. Я обновил свой ответ кодом, который будет перебирать даты, аналогичные тому, что вы делаете.