Рассчитайте новую дату для нового года, сохранив соответствующий день недели (например, понедельник). - PullRequest
0 голосов
/ 09 января 2019

Контекст: Программный инструмент для планирования / управления событиями

Цель: Клонировать событие предыдущего года - и дать пользователю преимущество при выборе даты начала и окончания события.

Допущение: Это новое событие вероятно повторение / событие по сравнению с прошлым годом. Таким образом, событие октября 2018 года будет клонировано на октябрь 2019 года.

Пример: Клонируемое событие имело дату начала: четверг, 20 октября 2016 года, и дату окончания: четверг, 3 ноября 2016 года (включая даты установки и завершения мероприятия)

Ожидаемый результат:

  • Количество дней в диапазоне дат сохраняется. (14 дней)
  • День недели сохраняется. (Четверг для обоих)

Код должен возвращать новую дату начала: Чт, 17 октября 2019 года и дата окончания: Чт, 31 октября 2019 года

Дополнительно: Другой приемлемый диапазон дат может быть: Четверг, 24 октября 2019 года и дата окончания 7 ноября 2019 года

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

Вопросы: Я хочу использовать библиотеку Moment.js , если это возможно

Вариант использования / Фактический дизайн

Ожидаемый результат / Примеры

Текущий код: Это то, что мы имеем в настоящее время, но это не возвращает ожидаемый результат. Кажется, просто вычитать день, независимо от разницы в год.

const today = moment();
const thisYear = today.format('YYYY');

const old_start = moment('2018-10-08');
const old_end = moment('2018-08-12');

// if in same year, use current dates
if (thisYear === old_start.format('YYYY')) {
  console.log({
    start: new_start.format('YYYY-MM-DD'),
    end: new_end.format('YYYY-MM-DD')
  })
} else {  
  console.log({
    start: new_start.year(thisYear)
      .isoWeek(old_start.isoWeek())
      .isoWeekday(old_start.isoWeekday())
      .format('YYYY-MM-DD'),
    end: new_end.year(thisYear)
      .isoWeek(old_end.isoWeek())
      .isoWeekday(old_end.isoWeekday())
      .format('YYYY-MM-DD')
  })  
}

Полученные неверные даты:

Буду признателен за любую помощь в том, что мы здесь делаем неправильно и как мы можем это исправить. Спасибо!

1 Ответ

0 голосов
/ 09 января 2019

Вот решение, которое принимает дату начала, дату окончания и количество лет в будущем и возвращает будущую дату начала и окончания, которая

  1. Начинается в тот же день недели, что и первоначальная дата начала
  2. Начинается в течение трех дней с первоначальной даты начала
  3. Имеет то же количество дней между будущими датами начала и окончания, что и между первоначальными датами начала и окончания

Логические шаги:

  1. Приблизительная будущая дата начала путем добавления количества введенных лет к исходной дате начала
  2. Определить разницу между числовым DOW исходной даты начала и приблизительной датой будущего
  3. Преобразовать следующую таблицу в формулу:

.

+----------------+-----------------------------------------------+
| DOW difference | Days to subtract from approximate future date |
+----------------+-----------------------------------------------+
|      -6        |        1                                      |
|      -5        |        2                                      |
|      -4        |        3                                      |
|      -3        |       -3                                      |
|      -2        |       -2                                      |
|      -1        |       -1                                      |
|       0        |        0                                      |
|       1        |        1                                      |
|       2        |        2                                      |
|       3        |        3                                      |
|       4        |       -3                                      |
|       5        |       -2                                      |
|       6        |       -1                                      |
+----------------+-----------------------------------------------+

который я кодифицировал как:

Math.abs(dowDiff) < 4 ? dowDiff : dowDiff + 7 * -Math.sign(dowDiff, daysAdd)
  1. Вычтите расчетное количество дней из приблизительной будущей даты, чтобы определить фактическую будущую дату
  2. Определите разницу в днях между исходной датой начала и окончания и добавьте их к расчетной будущей дате начала, чтобы получить будущую дату окончания
  3. Возвращает рассчитанные будущие даты начала и окончания

const getFutureDates = (start, end, years) => {
  const dStart = moment(start);
  const dStartFuture = dStart.clone().add(years || 1, 'years');
  const dowDiff = dStartFuture.day() - dStart.day();
  const daysSub = Math.abs(dowDiff) < 4 ? dowDiff : dowDiff + 7 * -Math.sign(dowDiff, daysAdd);
  dStartFuture.subtract(daysSub, 'days');
  const days = moment(end).diff(dStart, 'days');
  const dEndFuture = dStartFuture.clone().add(days, 'days');
  return {
    start: dStartFuture,
    end: dEndFuture
  };
}

const tests = [
  {start: '2011-08-10', end: '2011-08-20', years: 8},
  {start: '2017-08-09', end: '2017-08-19', years: 2},
  {start: '2014-08-06', end: '2014-08-16', years: 5},
];

tests.forEach(({start, end, years}) => {
  const format = (s, e) => `${moment(s).format('YYYY-MM-DD')} to ${moment(e).format('YYYY-MM-DD')}`;
  const {start: fStart, end: fEnd} = getFutureDates(start, end, years);
  console.log(`${format(start, end)} => ${format(fStart, fEnd)}`);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.23.0/moment.min.js"></script>
...