I needed too do this today (yes, adding weeks could make this unnecessary). If you find the need to do this, here’s the function I wrote to return a DateTime object, with optional timestamp.
function add_months_to_date( $number_months, $keep_time = true, $date = null ) { if ( !is_numeric( $number_months ) || intval( $number_months ) < 1 ) { return null; } // Process the $date parameter try { $date = new DateTime( $date ); } // On any error, default to today catch ( Exception $e ) { $date = new DateTime(); } // Get date values for the current month $day = intval( $date->format( 'd' ) ); $month = intval( $date->format( 'm' ) ); $year = intval( $date->format( 'Y' ) ); // Find the future date month and year $added_months = $number_months % 12; $added_years = floor( $number_months / 12 ); $future_month = ( $month + $added_months ) % 12; $future_year = $year + $added_years + floor( ( $month + $added_months ) / 12 ); // Build future date format, with optional timestamp $date_format = '%s-%s-01'; if ( $keep_time ) { $date_format = sprintf( '%s %s', $date_format, $date->format( 'H:i:s' ) ); } // Find the last day of the future month $future_date = new DateTime( sprintf( $date_format, $future_year, $future_month ) ); $last_day = $future_date->format( 't' ); // Set out of range dates to the last day of the future month if ( $last_day < $day ) { $day = $last_day; } // Set the correct day of the future month and return return $future_date->setDate( $future_year, $future_month, $day ); }