如何从当前日期倒推至指定日期生成年月数组?是否可用Moment简化
问题:生成从当前日期倒推至指定日期的年月数组
需求:从当前日期倒推至指定的最早加入日期(示例:2021年7月25日),生成格式如「August 2022」的年月数组。现有JS代码仅支持两年范围,需重构以支持任意年数,同时询问用Moment.js实现是否更简便。
现有代码:
function getMonthDifference(startDate: Date, endDate: Date) { return ( endDate.getMonth() - startDate.getMonth() + 12 * (endDate.getFullYear() - startDate.getFullYear()) ) } const earliestDateJoined = "2020-07-25" const now = new Date() const earliestDate = new Date(earliestDateJoined) for (let i = 0; i < getMonthDifference(earliestDate, now) + 1; i++) { let month = new Date().getMonth() + 1 - i let year = new Date().getFullYear() // console.log("before", year, month) if (month < 1) { month = month + 12 year = year - 1 if (month < 1) { month = month + 12 year = year - 1 } } const nameMonth = { 1: "Jan", 2: "Feb", 3: "Mar", 4: "Apr", 5: "May", 6: "Jun", 7: "Jul", 8: "Aug", 9: "Sep", 10: "Oct", 11: "Nov", 12: "Dec" } console.log(year + " Year " + nameMonth[month] + " Month ") }
原生JS重构方案(支持任意年数)
原代码的问题在于处理月份小于1时仅嵌套了两层判断,超过两年就会失效。下面提供两种可靠的重构方案,无需硬编码年份修正逻辑:
方案1:基于日期对象的安全回退
利用日期对象的setMonth方法自动处理年份进位,避免手动计算边界:
function generateMonthArray(earliestDateStr) { const earliestDate = new Date(earliestDateStr); const now = new Date(); const monthArray = []; // 初始化迭代日期为当前月第一天,避免日期溢出问题 const currentDate = new Date(now.getFullYear(), now.getMonth(), 1); while (currentDate >= earliestDate) { // 格式化年月为「August 2022」格式 const formattedMonth = new Intl.DateTimeFormat('en-US', { year: 'numeric', month: 'long' }).format(currentDate); monthArray.push(formattedMonth); // 回退一个月 currentDate.setMonth(currentDate.getMonth() - 1); } return monthArray; } // 使用示例 const earliestDateJoined = "2020-07-25"; const result = generateMonthArray(earliestDateJoined); console.log(result);
方案2:数学计算推导年月
通过数学计算直接得出目标年月,逻辑更直观:
function getMonthDifference(startDate, endDate) { return endDate.getMonth() - startDate.getMonth() + 12 * (endDate.getFullYear() - startDate.getFullYear()); } function generateMonthArray(earliestDateStr) { const earliestDate = new Date(earliestDateStr); const now = new Date(); const totalMonths = getMonthDifference(earliestDate, now); const monthArray = []; for (let i = 0; i <= totalMonths; i++) { let year = now.getFullYear(); let month = now.getMonth() - i; // 处理月份为负数的情况 if (month < 0) { const yearOffset = Math.floor(Math.abs(month) / 12); const monthOffset = Math.abs(month) % 12; year -= yearOffset; month = monthOffset === 0 ? 12 : 12 - monthOffset; year -= monthOffset === 0 ? 1 : 0; } // 获取完整月份名称 const monthName = new Intl.DateTimeFormat('en-US', { month: 'long' }).format(new Date(year, month)); monthArray.push(`${monthName} ${year}`); } return monthArray; } // 使用示例 const earliestDateJoined = "2020-07-25"; const result = generateMonthArray(earliestDateJoined); console.log(result);
两种方案均支持任意年数范围,同时用Intl.DateTimeFormat替代手动月份映射,更可靠且支持多语言适配。
Moment.js实现方案(更简便)
如果项目中已经引入Moment.js,用它实现会大幅简化代码——内置的日期加减、格式化和比较方法,无需手动处理边界:
// 先安装依赖:npm install moment const moment = require('moment'); function generateMonthArray(earliestDateStr) { const earliestMoment = moment(earliestDateStr); const nowMoment = moment(); const monthArray = []; let currentMoment = nowMoment.clone().startOf('month'); while (currentMoment.isSameOrAfter(earliestMoment, 'month')) { // 直接格式化为「August 2022」 monthArray.push(currentMoment.format('MMMM YYYY')); currentMoment.subtract(1, 'month'); } return monthArray; } // 使用示例 const earliestDateJoined = "2020-07-25"; const result = generateMonthArray(earliestDateJoined); console.log(result);
Moment.js版本的代码逻辑更清晰、可读性更高,适合已有依赖的项目;如果不需要引入第三方库,原生JS方案也足够可靠。
内容的提问来源于stack exchange,提问作者user3026715
相关产品推荐
相关产品推荐

