Сколько итераций сложной продолжительности времени существует между датой начала и датой окончания?

Например, я использую библиотеку moment.js. Вы можете указать продолжительность следующим образом: {годы:1,месяцы:1,недели:1,дни:1,часы:1,минуты:1,секунды:1}. Эта продолжительность времени является субъективной на основе контекста времени начала и окончания.

Например, в одних месяцах может быть 28 дней, а в других — 31. Поэтому, если вы добавите месяц к концу 31 января, будет сказано, что 1 месяц с этого момента — это 28 февраля.

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

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

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

Я не могу просто сказать «в году столько-то минут», потому что в одних годах минут больше, чем в других, потому что в некоторые годы (из-за високосных лет) 366 дней вместо 365, и, следовательно, разное общее количество минут для этого года. возможная продолжительность.

Следовательно, вы можете видеть мою дилемму. Есть ли способ эффективно выяснить, сколько итераций единицы времени существует между начальной и конечной датой? (без добавления единицы времени вручную к времени начала, как я делаю сейчас, пока оно не превысит время окончания, и вручную подсчитывая итерации)

https://jsfiddle.net/gentleman_goat66/ye6bsd1v/1/

let start = "2021-01-01 00:00";
let end = "2023-01-01 00:00";
let unit = {years: 1, months: 1, weeks: 1, days: 1, hours: 1, minutes: 1};

let startMoment = moment(start, 'YYYY-MM-DD HH:mm');
let endMoment = moment(end, 'YYYY-MM-DD HH:mm');

let startEndDurationSeconds = endMoment.diff(startMoment, "seconds");
let startEndDurationMinutes = endMoment.diff(startMoment, "minutes");
let startEndDurationHours = endMoment.diff(startMoment, "hours");
let startEndDurationDays = endMoment.diff(startMoment, "days");
let startEndDurationWeeks = endMoment.diff(startMoment, "weeks");
let startEndDurationMonths = endMoment.diff(startMoment, "months");
let startEndDurationYears = endMoment.diff(startMoment, "years");

console.info(`seconds=${startEndDurationSeconds}`);
console.info(`minutes=${startEndDurationMinutes}`);
console.info(`hours=${startEndDurationHours}`);
console.info(`days=${startEndDurationDays}`);
console.info(`weeks=${startEndDurationWeeks}`);
console.info(`months=${startEndDurationMonths}`);
console.info(`years=${startEndDurationYears}`);

Прикреплен JSFiddle, демонстрирующий простой способ проверить, как библиотека моментов разбивает время между началом и концом. Вопрос будет заключаться в том, как узнать, сколько «единиц» входит в это.

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

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

 function countIterations(start, end, duration) {
    let remainingStart = moment(start);
    let remainingEnd = moment(end);
    let i = 0;
    while (remainingStart <= remainingEnd) {
        i++;
        remainingStart.add(duration);
    }
    return i - 1;
 }
let duration = {years: 0, months: 1, weeks: 1, days: 0, hours: 0, minutes: 0};
let iterations = countIterations(moment(start), moment(end), duration);
console.info(iterations);

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

Вы не можете сделать простую математику здесь. Потому что добавление единицы времени, такой как «месяц», субъективно, иногда это 28 дней, а иногда 30 или 31. Поэтому знание эпохи Unix не помогает. Если бы в месяце всегда было 30 дней, было бы легко

Joseph Astrahan 13.01.2023 02:35

также дубликат Разница в месяцах между двумя датами в JavaScript

pilchard 13.01.2023 02:37

Если бы я хотел узнать, сколько месяцев было между двумя датами, я мог бы просто использовать для этого библиотеку моментов. Это просто говорит вам об этом, но этого недостаточно для моего варианта использования. Я пытаюсь увидеть, сколько времени существует определенная единица итерации между двумя датами, что вполне может быть невозможно без зацикливания вручную с неопределенностью того, что означает «месяц».

Joseph Astrahan 13.01.2023 02:39
month — единственное нестандартное значение в вашем списке, и они были учтены в обоих помеченных дубликатах. Остальное можно преобразовать в секунды или мс и вычислить с помощью простой арифметики (при необходимости с учетом високосных лет). Как рассчитать количество лет между двумя датами?
pilchard 13.01.2023 02:52

Итак, вы хотите знать, сколько минут прошло с 12 января 1834 года по 4 октября 2043 года? например

Medet Tleukabiluly 13.01.2023 02:53

Это не дубликат разницы в месяцах между двумя датами в JavaScript, потому что он спрашивает, сколько единиц сложной продолжительности времени существует между двумя датами, а не просто месяцами.

Joseph Astrahan 13.01.2023 02:53

Продолжительность комплекса @pilchard означает просто не месяц, что-то вроде 1 месяца и 2 дней

Joseph Astrahan 13.01.2023 02:54

@medet tieukabiluly, я хочу знать, например, сколько единиц (X месяцев + X дней + X минут) существует между начальной и конечной датами. Я уже знаю, сколько минут существует, но это не помогает для итераций единицы сложного времени, где месяцы могут быть разными.

Joseph Astrahan 13.01.2023 03:00

Я неправильно понимаю? Похоже, ОП понимает, что определенные интервалы (с лунными компонентами, не привязанные к точной дате начала) не могут быть преобразованы в числовые значения и что мы можем выполнять математические операции только с числовыми значениями. Если вы можете преобразовать входные данные в миллисекунды, вы можете разделить их. Если вы не можете, вы не можете. Верно?

danh 13.01.2023 03:45

Я собираюсь добавить JSFiddle, чтобы немного продемонстрировать проблему с моим текущим решением @danh (тем не менее, проблема здесь в том, сколько единиц сложной единицы времени может поместиться между двумя датами), у меня есть решение, которое состоит в том, чтобы вручную добавить это время к времени начала, пока оно не превысит конечное время, и подсчитать, сколько раз это произошло, чтобы получить итерации, но это требует очень много времени. Нет никакого математического способа сделать это (я думаю). Это действительно мой вопрос, есть ли математический способ решить это? (или что-то, что мне не хватает, если есть не математический способ)

Joseph Astrahan 13.01.2023 03:49

Не точная копия, но Как я могу определить, подходят ли кратные длительности равномерно между двумя датами? предоставляет достаточно информации, чтобы ответить на ваш вопрос. Дело в том, что любая продолжительность, включающая годы, месяцы или дни, проблематична, поскольку все три имеют разную длину в зависимости от различных факторов (високосные годы, месяцы разной длины, переход на летнее время и т. д.). Также места меняют свое стандартное смещение часового пояса, что может быть редкостью с 1900 года, но все же происходит.

RobG 13.01.2023 05:27

Таким образом, последовательное добавление длительности к начальной точке — действительно единственный путь, и вам все равно понадобятся бизнес-правила для сортировки таких вещей, как 31 марта плюс 1 месяц, 29 февраля плюс 1 год и так далее.

RobG 13.01.2023 05:31

Если продолжительность указана в часах или меньших единицах, то достаточно просто получить разницу во временных значениях и разделить на продолжительность в миллисекундах. Однако, как только у вас появятся дни, месяцы или годы, вы вернетесь к итеративному сложению или вычитанию.

RobG 13.01.2023 05:37

@RobG спасибо, у меня было подозрение, что это единственный способ сделать это, но я не был уверен

Joseph Astrahan 13.01.2023 06:06
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
15
56
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

Функция ниже имеет две ветви, соответствующие этим двум случаям. Оба содержат небольшую встроенную функцию сумматора, которая запускает момент add() на Object.entries() объекта продолжительности.

Он прошел несколько беглых тестов, которые я ему дал.

let start = "2021-01-01 00:00";
let end = "2023-01-01 00:00";
let unit = { years: 1, months: 1, weeks: 1, days: 1, hours: 1, minutes: 1, seconds: 1 };

let smallUnit = { weeks: 1, days: 1, hours: 1, minutes: 1, seconds: 1 };
let tinyUnit = { seconds: 1 };

function unitsBetweenDates(start, end, unit) {
  let m = moment(start)
  let mEnd = moment(end)

  if (unit.years || unit.months) {
    let dividend = 0
    let add = (date, object) => {
      Object.entries(object).forEach(([unit, qty]) => date.add(qty, unit))
    }
    // notice that we don't try to count more than a million years or months
    while (m.isBefore(mEnd) && ++ dividend < 100000) add(m, unit);
    return dividend-1
  } else {
    let intervalLength = object => {
      let i = moment.duration()
      Object.entries(object).forEach(([unit, qty]) => i.add(qty, unit))
      return i
    }
    return Math.floor(mEnd.diff(m) / intervalLength(unit))
  }
}

console.info("a year and a month, etc, divided into 2 years  = ", unitsBetweenDates(start, end, unit))
console.info("a week and a day, etc, divided into 2 years  = ", unitsBetweenDates(start, end, smallUnit))
console.info("one second divided into 2 years  = ", unitsBetweenDates(start, end, tinyUnit))
<script src = "https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js"></script>

Я добавил пример функции, которая делает это с помощью грубой силы, в моем примере и с заданным диапазоном дат в 2 года ваша функция возвращает 20, а моя возвращает 19. Как правильно?

Joseph Astrahan 14.01.2023 20:18

Это вопрос пола и потолка. Мой цикл увеличивает счетчик на итерации, где текущая дата превышает лимит, поэтому он возвращает целочисленный потолок. Ваш вычитает 1 после завершения цикла, создавая целое число. На ваше усмотрение: return dividend-1 может быть тем, что вы хотите в моем

danh 15.01.2023 02:43

Другие вопросы по теме