differenceInMonths.mjs 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. import { compareAsc } from "./compareAsc.mjs";
  2. import { differenceInCalendarMonths } from "./differenceInCalendarMonths.mjs";
  3. import { isLastDayOfMonth } from "./isLastDayOfMonth.mjs";
  4. import { toDate } from "./toDate.mjs";
  5. /**
  6. * @name differenceInMonths
  7. * @category Month Helpers
  8. * @summary Get the number of full months between the given dates.
  9. *
  10. * @description
  11. * Get the number of full months between the given dates using trunc as a default rounding method.
  12. *
  13. * @typeParam DateType - The `Date` type, the function operates on. Gets inferred from passed arguments. Allows to use extensions like [`UTCDate`](https://github.com/date-fns/utc).
  14. *
  15. * @param dateLeft - The later date
  16. * @param dateRight - The earlier date
  17. *
  18. * @returns The number of full months
  19. *
  20. * @example
  21. * // How many full months are between 31 January 2014 and 1 September 2014?
  22. * const result = differenceInMonths(new Date(2014, 8, 1), new Date(2014, 0, 31))
  23. * //=> 7
  24. */
  25. export function differenceInMonths(dateLeft, dateRight) {
  26. const _dateLeft = toDate(dateLeft);
  27. const _dateRight = toDate(dateRight);
  28. const sign = compareAsc(_dateLeft, _dateRight);
  29. const difference = Math.abs(
  30. differenceInCalendarMonths(_dateLeft, _dateRight),
  31. );
  32. let result;
  33. // Check for the difference of less than month
  34. if (difference < 1) {
  35. result = 0;
  36. } else {
  37. if (_dateLeft.getMonth() === 1 && _dateLeft.getDate() > 27) {
  38. // This will check if the date is end of Feb and assign a higher end of month date
  39. // to compare it with Jan
  40. _dateLeft.setDate(30);
  41. }
  42. _dateLeft.setMonth(_dateLeft.getMonth() - sign * difference);
  43. // Math.abs(diff in full months - diff in calendar months) === 1 if last calendar month is not full
  44. // If so, result must be decreased by 1 in absolute value
  45. let isLastMonthNotFull = compareAsc(_dateLeft, _dateRight) === -sign;
  46. // Check for cases of one full calendar month
  47. if (
  48. isLastDayOfMonth(toDate(dateLeft)) &&
  49. difference === 1 &&
  50. compareAsc(dateLeft, _dateRight) === 1
  51. ) {
  52. isLastMonthNotFull = false;
  53. }
  54. result = sign * (difference - Number(isLastMonthNotFull));
  55. }
  56. // Prevent negative zero
  57. return result === 0 ? 0 : result;
  58. }
  59. // Fallback for modularized imports:
  60. export default differenceInMonths;