getOverlappingDaysInIntervals.js 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. import { getTimezoneOffsetInMilliseconds } from "./_lib/getTimezoneOffsetInMilliseconds.js";
  2. import { millisecondsInDay } from "./constants.js";
  3. import { toDate } from "./toDate.js";
  4. /**
  5. * @name getOverlappingDaysInIntervals
  6. * @category Interval Helpers
  7. * @summary Get the number of days that overlap in two time intervals
  8. *
  9. * @description
  10. * Get the number of days that overlap in two time intervals. It uses the time
  11. * between dates to calculate the number of days, rounding it up to include
  12. * partial days.
  13. *
  14. * Two equal 0-length intervals will result in 0. Two equal 1ms intervals will
  15. * result in 1.
  16. *
  17. * @param intervalLeft - The first interval to compare.
  18. * @param intervalRight - The second interval to compare.
  19. * @param options - An object with options
  20. *
  21. * @returns The number of days that overlap in two time intervals
  22. *
  23. * @example
  24. * // For overlapping time intervals adds 1 for each started overlapping day:
  25. * getOverlappingDaysInIntervals(
  26. * { start: new Date(2014, 0, 10), end: new Date(2014, 0, 20) },
  27. * { start: new Date(2014, 0, 17), end: new Date(2014, 0, 21) }
  28. * )
  29. * //=> 3
  30. *
  31. * @example
  32. * // For non-overlapping time intervals returns 0:
  33. * getOverlappingDaysInIntervals(
  34. * { start: new Date(2014, 0, 10), end: new Date(2014, 0, 20) },
  35. * { start: new Date(2014, 0, 21), end: new Date(2014, 0, 22) }
  36. * )
  37. * //=> 0
  38. */
  39. export function getOverlappingDaysInIntervals(intervalLeft, intervalRight) {
  40. const [leftStart, leftEnd] = [
  41. +toDate(intervalLeft.start),
  42. +toDate(intervalLeft.end),
  43. ].sort((a, b) => a - b);
  44. const [rightStart, rightEnd] = [
  45. +toDate(intervalRight.start),
  46. +toDate(intervalRight.end),
  47. ].sort((a, b) => a - b);
  48. // Prevent NaN result if intervals don't overlap at all.
  49. const isOverlapping = leftStart < rightEnd && rightStart < leftEnd;
  50. if (!isOverlapping) return 0;
  51. // Remove the timezone offset to negate the DST effect on calculations.
  52. const overlapLeft = rightStart < leftStart ? leftStart : rightStart;
  53. const left = overlapLeft - getTimezoneOffsetInMilliseconds(overlapLeft);
  54. const overlapRight = rightEnd > leftEnd ? leftEnd : rightEnd;
  55. const right = overlapRight - getTimezoneOffsetInMilliseconds(overlapRight);
  56. // Ceil the number to include partial days too.
  57. return Math.ceil((right - left) / millisecondsInDay);
  58. }
  59. // Fallback for modularized imports:
  60. export default getOverlappingDaysInIntervals;