Repository: date-fns/date-fns
File: src/add/index.js (JavaScript)

Code before:
  if (arguments.length < 2) {
    throw new TypeError(
      '2 arguments required, but only ' + arguments.length + ' present'
    )
  }

  if (!givenAmount) {
    return new Date(NaN)
  }
  const finalDate = toDate(dirtyDate)
  if (typeof givenAmount === 'number') {
    finalDate.setTime(finalDate.getTime() + givenAmount)
    return finalDate
  }
  if (Object.keys(givenAmount).length === 0) {
    return finalDate
  }
  let milliseconds = toInteger(givenAmount.milliseconds) || 0
  let seconds = toInteger(givenAmount.seconds) || 0
  let minutes = toInteger(givenAmount.minutes) || 0
  let hours = toInteger(givenAmount.hours) || 0
  let days = toInteger(givenAmount.days) || 0
  let months = toInteger(givenAmount.months) || 0
  const quarters = toInteger(givenAmount.quarters) || 0
  const weeks = toInteger(givenAmount.weeks) || 0
  const years = toInteger(givenAmount.years) || 0

  months += years * 12 + quarters * 3
  let desiredMonth = finalDate.getMonth() + months
  let dateWithDesiredMonth = new Date(0)
  dateWithDesiredMonth.setFullYear(finalDate.getFullYear(), desiredMonth, 1)
  dateWithDesiredMonth.setHours(0, 0, 0, 0)
  let daysInMonth = getDaysInMonth(dateWithDesiredMonth)
  finalDate.setMonth(desiredMonth, Math.min(daysInMonth, finalDate.getDate()))
  days += weeks * 7
  hours += days * 24
  minutes += hours * 60
  seconds += minutes * 60
  milliseconds += seconds * 1000
  finalDate.setTime(finalDate.getTime() + milliseconds)
  return finalDate
}


Review comment (bug):
Please don't default values to 0 after `toInteger` because it will suppress any `NaN` in here, which would be behavior that is hard to debug. Instead, check if the key is present and default it to 0 only if it's not:

```js
let milliseconds = 'milliseconds' in duration ? toInteger(duration.milliseconds) : 0
```

This way `NaN` will stay `NaN` even if it's passed as the value, so the resulting date would be `Invalid Date`.

Code after:
import addMonths from '../addMonths/index.js'
import toDate from '../toDate/index.js'
import requiredArgs from '../_lib/requiredArgs/index.js'
import toInteger from '../_lib/toInteger/index.js'

/**
 * @name add
 * @category Common Helpers
 * @summary Add the specified years, months, days, hours, minutes and seconds to the given date.
 *
 * @description
 * Add the specified years, months, days, hours, minutes and seconds to the given date.
 *
 * @param {Date|Number} date - the date to be changed
 * @param {Object} duration - the object with years, months, days, hours, minutes and seconds to be added
 *
 * | Key            | Description                        |
 * |----------------|------------------------------------|
 * | years          | Amount of years to be added        |
 * | months         | Amount of months to be added       |
 * | days           | Amount of days to be added         |
 * | hours          | Amount of hours to be added        |
 * | minutes        | Amount of minutes to be added      |
 * | seconds        | Amount of seconds to be added      |
 *
 * All values default to 0
 *
 * @returns {Date} the new date with the seconds added
 * @throws {TypeError} 2 arguments required
 *
 * @example
 * // Add the following duration to 1 September 2014, 10:19:50
 * var result = add(new Date(2014, 8, 1, 10, 19, 50), {
 *   years: 2,
 *   months: 24,
 *   days: 7,
 *   hours: 5,
 *   minutes: 9,
 *   seconds: 30,
 * })
 * //=> Sat Sep 8 2018 15:29:20
 */
export default function add(dirtyDate, duration) {
  requiredArgs(2, arguments)

  if (!duration || typeof duration !== 'object') return new Date(NaN)

  const years = 'years' in duration ? toInteger(duration.years) : 0
  const months = 'months' in duration ? toInteger(duration.months) : 0
  const days = 'days' in duration ? toInteger(duration.days) : 0
  const hours = 'hours' in duration ? toInteger(duration.hours) : 0
  const minutes = 'minutes' in duration ? toInteger(duration.minutes) : 0
  const seconds = 'seconds' in duration ? toInteger(duration.seconds) : 0

  // Add years and months
  const dateWithMonths = addMonths(toDate(dirtyDate), months + years * 12)

  // Add days, hours, minutes and seconds
  const hoursToAdd = hours + days * 24
  const minutesToAdd = minutes + hoursToAdd * 60
  const secondsToAdd = seconds + minutesToAdd * 60
  const msToAdd = secondsToAdd * 1000
  const finalDate = new Date(dateWithMonths.getTime() + msToAdd)

  return finalDate
}