Debido a que la definición de "la edad en meses" es... flexible, la forma más fácil es usar un poco de aritmética como se podría calcular en tu cabeza, y no involucrar a la Date
clase.
Para la [a] de la interpretación humana de "la edad en meses", la regla es
Calcular la diferencia entre dos fechas en meses,
como si el día-de-la-mes fue el día 1 del mes para ambas fechas
Restar 1 a excluir el final de mes
Entonces, si el día-de-la-mes del último día del plazo es en
o después del día-de-la-mes del primer día del período, el [potencialmente parcial] final de mes es completa: añadir 1 para restaurar el recuento
La mosca en el ungüento es, desde hace meses contienen diferente número de días, se ocupan de los casos donde los 2 meses difieren en su número de días.
Si, sin embargo, el fin de mes es más corto que el mes de inicio, usted puede entrar en una situación en la que la condición de frontera nunca se pueden cumplir (por ejemplo, la fecha de inicio es el 28 de febrero y la fecha de finalización es el 31 de Marzo. Para arreglar eso, usted tiene que mirar en el "fin de mes" como una ventana que van desde el último día del mes de inicio hasta el último día del fin de mes inclusive.
Que lleva a este código. Estoy usando una estructura como la siguiente para representar una fecha:
{
year: 2021 , // 4-digit year
month: 11 , // month of year (1-12 mapping to January-December)
day: 23 // day of month (1-[28-31] depending on year/month
}
Asegurar que los datos en que se estructura representa una fecha válida se deja como ejercicio para el lector.
El código no es tan complicado:
/**
*
* @param {object} bgn - start date of period
* @param {number} bgn.year - 4-digit year
* @param {number} bgn.month - month of year [1-12]
* @param {number} bgn.day - day of month [1-31]
*
* @param {object} end - end date of period
* @param {number} end.year - 4-digit year
* @param {number} end.month - month of year [1-12]
* @param {number} end.day - day of month [1-31]
*
*/
function diffInMonths( bgn , end ) {
const between = ( x , min , max ) => x >= min && x <= max;
// We'll need to add back the final month based on the following:
// - end.day >= bgn.day -- we've passed the month boundary, or
// - end.day is within the end-of-month window
// (when the end month is shorter than the start month)
const needAdjustment = end.day >= bgn.day
|| between( end.day, daysInMonth(bgn), daysInMonth(end) );
const finalMonthAdjustment = needsAdjustment ? 1 : 0;
const deltaM = 12 * ( end.year - bgn.year )
+ ( end.month - bgn.month )
- 1 // remove the final month from the equation
+ finalMonthAdjustment // add in the precomputed final month adjustment
;
return deltaM;
}
/**
*
* @param {object} dt - date
* @param {number} dt.year - 4-digit year
* @param {number} dt.month - month of year [1-12]
* @param {number} dt.day - day of month [1-31]
*
*/
function daysInMonth(dt) {
const leapYear = ( dt.year % 4 === 0 && dt.year % 100 !== 0 ) || dt.year % 400 === 0;
const monthDays = leapYear ? daysPerMonthLeap : daysPerMonth;
const days = monthDays[dt.month];
return days;
}
// jan feb mar apr may jun jul aug sep oct nov dec
// ---------- --- --- --- --- --- --- --- --- --- --- --- ---
const daysPerMonth = [ undefined, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, ];
const daysPerMonthLeap = [ undefined, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, ];
new Date(userDate.split('/').reverse())
es casi seguro que devolver una Fecha no válida.