import Duration from "../duration.js"; function dayDiff(earlier, later) { const utcDayStart = (dt) => dt.toUTC(0, { keepLocalTime: true }).startOf("day").valueOf(), ms = utcDayStart(later) - utcDayStart(earlier); return Math.floor(Duration.fromMillis(ms).as("days")); } function highOrderDiffs(cursor, later, units) { const differs = [ ["years", (a, b) => b.year - a.year], ["quarters", (a, b) => b.quarter - a.quarter + (b.year - a.year) * 4], ["months", (a, b) => b.month - a.month + (b.year - a.year) * 12], [ "weeks", (a, b) => { const days = dayDiff(a, b); return (days - (days % 7)) / 7; }, ], ["days", dayDiff], ]; const results = {}; const earlier = cursor; let lowestOrder, highWater; for (const [unit, differ] of differs) { if (units.indexOf(unit) >= 0) { lowestOrder = unit; results[unit] = differ(cursor, later); highWater = earlier.plus(results); if (highWater > later) { results[unit]--; cursor = earlier.plus(results); } else { cursor = highWater; } } } return [cursor, results, highWater, lowestOrder]; } export default function (earlier, later, units, opts) { let [cursor, results, highWater, lowestOrder] = highOrderDiffs(earlier, later, units); const remainingMillis = later - cursor; const lowerOrderUnits = units.filter( (u) => ["hours", "minutes", "seconds", "milliseconds"].indexOf(u) >= 0 ); if (lowerOrderUnits.length === 0) { if (highWater < later) { highWater = cursor.plus({ [lowestOrder]: 1 }); } if (highWater !== cursor) { results[lowestOrder] = (results[lowestOrder] || 0) + remainingMillis / (highWater - cursor); } } const duration = Duration.fromObject(results, opts); if (lowerOrderUnits.length > 0) { return Duration.fromMillis(remainingMillis, opts) .shiftTo(...lowerOrderUnits) .plus(duration); } else { return duration; } }