Skip to main content
Module

x/date_fns/addMonths/index.ts

date-fns Deno package
Very Popular
Latest
File
import toInteger from '../_lib/toInteger/index.ts'import toDate from '../toDate/index.ts'import requiredArgs from '../_lib/requiredArgs/index.ts'
/** * @name addMonths * @category Month Helpers * @summary Add the specified number of months to the given date. * * @description * Add the specified number of months to the given date. * * ### v2.0.0 breaking changes: * * - [Changes that are common for the whole library](https://github.com/date-fns/date-fns/blob/master/docs/upgradeGuide.md#Common-Changes). * * @param {Date|Number} date - the date to be changed * @param {Number} amount - the amount of months to be added. Positive decimals will be rounded using `Math.floor`, decimals less than zero will be rounded using `Math.ceil`. * @returns {Date} the new date with the months added * @throws {TypeError} 2 arguments required * * @example * // Add 5 months to 1 September 2014: * const result = addMonths(new Date(2014, 8, 1), 5) * //=> Sun Feb 01 2015 00:00:00 */export default function addMonths( dirtyDate: Date | number, dirtyAmount: number): Date { requiredArgs(2, arguments)
const date = toDate(dirtyDate) const amount = toInteger(dirtyAmount) if (isNaN(amount)) { return new Date(NaN) } if (!amount) { // If 0 months, no-op to avoid changing times in the hour before end of DST return date } const dayOfMonth = date.getDate()
// The JS Date object supports date math by accepting out-of-bounds values for // month, day, etc. For example, new Date(2020, 0, 0) returns 31 Dec 2019 and // new Date(2020, 13, 1) returns 1 Feb 2021. This is *almost* the behavior we // want except that dates will wrap around the end of a month, meaning that // new Date(2020, 13, 31) will return 3 Mar 2021 not 28 Feb 2021 as desired. So // we'll default to the end of the desired month by adding 1 to the desired // month and using a date of 0 to back up one day to the end of the desired // month. const endOfDesiredMonth = new Date(date.getTime()) endOfDesiredMonth.setMonth(date.getMonth() + amount + 1, 0) const daysInMonth = endOfDesiredMonth.getDate() if (dayOfMonth >= daysInMonth) { // If we're already at the end of the month, then this is the correct date // and we're done. return endOfDesiredMonth } else { // Otherwise, we now know that setting the original day-of-month value won't // cause an overflow, so set the desired day-of-month. Note that we can't // just set the date of `endOfDesiredMonth` because that object may have had // its time changed in the unusual case where where a DST transition was on // the last day of the month and its local time was in the hour skipped or // repeated next to a DST transition. So we use `date` instead which is // guaranteed to still have the original time. date.setFullYear( endOfDesiredMonth.getFullYear(), endOfDesiredMonth.getMonth(), dayOfMonth ) return date }}