Home > Enterprise >  How can I determine if multiples of a duration fit evenly between two dates?
How can I determine if multiples of a duration fit evenly between two dates?

Time:01-01

I'm using Luxon, and have two dates and an ISO duration. How can I determine if the duration between the two dates is an multiple of the duration with no remainder?

  • 1/23/2000 to 6/23/2000 with P6M returns true
  • 1/23/2000 to 1/23/2022 with P6M returns true
  • 1/23/2000 to 2/23/2000 with P6M returns false
  • 1/23/2000 to 2/23/2022 with P1M returns true
  • 1/23/2000 to 2/24/2022 with P1M returns false

I considered converting to "months" for example and just using Javascript's modulus operator to determine if the remainder is 0, but ISO durations can be very complex, eg "P3Y6M4DT12H30M5S" represents a duration of "three years, six months, four days, twelve hours, thirty minutes, and five seconds".

Intervals have a splitBy function that seems promising as it leaves the remainder as the last element in the array it returns, but I'm not sure how to then compare that element to my original duration:

import {DateTime, Duration, Interval} from 'luxon';

const date1: DateTime = DateTime.fromJSDate(new Date('12/20/2022'));
const date2: DateTime = DateTime.fromJSDate(new Date('12/20/2023'));
const duration: Duration = Duration.fromISO('P6M');

const interval: Interval = Interval.fromDateTimes(date1, date2);
const split = interval.splitBy(duration);
const modulusDuration = (split[split.length - 1] as Interval).toDuration();
if (modulusDuration.valueOf() === duration.valueOf()) {
  console.log('pass'); // We never get here
} else {
  // We get here
  console.log(modulusDuration.rescale().toObject()) // {months: 6, days: 3, hours: 1}
  console.log(duration.rescale().toObject()) // {months: 6}
  console.log('fail');
}

Here's a stackblitz: https://stackblitz.com/edit/typescript-kuwjpg?file=index.ts

How can I determine if multiples of a duration fit neatly between two dates?

CodePudding user response:

Thanks to @RobG's comment I was able to get this working by iteratively adding the duration to the start date and checking if it lands exactly on the end date:

import {DateTime, Duration, Interval} from 'luxon';

const date1: DateTime = DateTime.fromJSDate(new Date('1/20/2022'));
const date2: DateTime = DateTime.fromJSDate(new Date('1/20/2023'));
const duration: Duration = Duration.fromISO('P6M');


let pass = false;
for (let i = date1; i <= date2; i = i.plus(duration)) {
  if (i.toMillis() === date2.toMillis()) {
    pass = true;
  }
}
console.log(pass ? 'pass' : 'fail');

https://stackblitz.com/edit/typescript-nodwnx?file=index.ts

  • Related