Например, я использую библиотеку 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 дней, было бы легко
также дубликат Разница в месяцах между двумя датами в JavaScript
Если бы я хотел узнать, сколько месяцев было между двумя датами, я мог бы просто использовать для этого библиотеку моментов. Это просто говорит вам об этом, но этого недостаточно для моего варианта использования. Я пытаюсь увидеть, сколько времени существует определенная единица итерации между двумя датами, что вполне может быть невозможно без зацикливания вручную с неопределенностью того, что означает «месяц».
month
— единственное нестандартное значение в вашем списке, и они были учтены в обоих помеченных дубликатах. Остальное можно преобразовать в секунды или мс и вычислить с помощью простой арифметики (при необходимости с учетом високосных лет). Как рассчитать количество лет между двумя датами?Итак, вы хотите знать, сколько минут прошло с 12 января 1834 года по 4 октября 2043 года? например
Это не дубликат разницы в месяцах между двумя датами в JavaScript, потому что он спрашивает, сколько единиц сложной продолжительности времени существует между двумя датами, а не просто месяцами.
Продолжительность комплекса @pilchard означает просто не месяц, что-то вроде 1 месяца и 2 дней
@medet tieukabiluly, я хочу знать, например, сколько единиц (X месяцев + X дней + X минут) существует между начальной и конечной датами. Я уже знаю, сколько минут существует, но это не помогает для итераций единицы сложного времени, где месяцы могут быть разными.
Я неправильно понимаю? Похоже, ОП понимает, что определенные интервалы (с лунными компонентами, не привязанные к точной дате начала) не могут быть преобразованы в числовые значения и что мы можем выполнять математические операции только с числовыми значениями. Если вы можете преобразовать входные данные в миллисекунды, вы можете разделить их. Если вы не можете, вы не можете. Верно?
Я собираюсь добавить JSFiddle, чтобы немного продемонстрировать проблему с моим текущим решением @danh (тем не менее, проблема здесь в том, сколько единиц сложной единицы времени может поместиться между двумя датами), у меня есть решение, которое состоит в том, чтобы вручную добавить это время к времени начала, пока оно не превысит конечное время, и подсчитать, сколько раз это произошло, чтобы получить итерации, но это требует очень много времени. Нет никакого математического способа сделать это (я думаю). Это действительно мой вопрос, есть ли математический способ решить это? (или что-то, что мне не хватает, если есть не математический способ)
Не точная копия, но Как я могу определить, подходят ли кратные длительности равномерно между двумя датами? предоставляет достаточно информации, чтобы ответить на ваш вопрос. Дело в том, что любая продолжительность, включающая годы, месяцы или дни, проблематична, поскольку все три имеют разную длину в зависимости от различных факторов (високосные годы, месяцы разной длины, переход на летнее время и т. д.). Также места меняют свое стандартное смещение часового пояса, что может быть редкостью с 1900 года, но все же происходит.
Таким образом, последовательное добавление длительности к начальной точке — действительно единственный путь, и вам все равно понадобятся бизнес-правила для сортировки таких вещей, как 31 марта плюс 1 месяц, 29 февраля плюс 1 год и так далее.
Если продолжительность указана в часах или меньших единицах, то достаточно просто получить разницу во временных значениях и разделить на продолжительность в миллисекундах. Однако, как только у вас появятся дни, месяцы или годы, вы вернетесь к итеративному сложению или вычитанию.
@RobG спасибо, у меня было подозрение, что это единственный способ сделать это, но я не был уверен
Вот идея: интервалы, не содержащие месяцев или лет, однозначны, и мы можем просто вычислить их в миллисекундах. Интервалы с лунными компонентами необходимо многократно добавлять, чтобы найти делимое, но мы можем просто добавлять интервал к начальной дате, пока он не превысит конечную дату, поэтому цикл выполняет только время дивиденда.
Функция ниже имеет две ветви, соответствующие этим двум случаям. Оба содержат небольшую встроенную функцию сумматора, которая запускает момент 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. Как правильно?
Это вопрос пола и потолка. Мой цикл увеличивает счетчик на итерации, где текущая дата превышает лимит, поэтому он возвращает целочисленный потолок. Ваш вычитает 1 после завершения цикла, создавая целое число. На ваше усмотрение: return dividend-1
может быть тем, что вы хотите в моем
Отвечает ли это на ваш вопрос? Сколько ноября (или любого конкретного месяца) между датой начала и датой окончания?