Protože definice "věk v měsících"... flexibilní, nejjednodušší způsob, jak je použít trochu aritmetiky, jako byste to spočítat v hlavě, a ne zapojit Date
třídy.
Pro [a] lidské interpretace "věk v měsících", pravidlo je
Vypočítat rozdíl mezi dvěma daty v měsících,
jako kdyby den-of-the-měsíc byl 1 měsíc pro obě data
Odečíst 1 vyloučit poslední měsíc
Pak, pokud den-of-the-měsíc poslední den období je na
nebo po celý den-of-the-měsíc v první den období, [potenciálně částečné] poslední měsíc je kompletní: přidejte 1 obnovit počítat
Ten, létat v masti je, že od měsíce obsahují různé počty dní, které se zabývají případy, kdy 2 měsíce se liší v jejich počtu dní.
Pokud, nicméně, do konce měsíce je kratší než na začátku měsíce, můžete se dostat do situace, kdy okrajová podmínka nemůže být nikdy splněna (např. počáteční datum je 28. února a datum ukončení je 31. Března. Chcete-li to, musíte se podívat na "konci měsíce" jako okna od posledního dne začátku měsíce přes poslední den na konci měsíce včetně.
To vede k tomuto kódu. Používám strukturu, jako na následujícím představují datum:
{
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
}
Zajištění toho, že údaje v tomto struct představuje platné datum je ponechán jako cvičení pro čtenáře.
Kód není tak složité:
/**
*
* @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())
bude téměř jistě vrátí chybu neplatné Datum.