Issue review

Click the month to switch the month and query the corresponding order.

On December 31, nearly six months of the month became the following

Troubleshoot problems

The month calculation is obtained by taking the current time and calling the addMonths method. The addMonths is realized by calculating months and calling the setMonth method, and the value of setMonth is printed in the addMonths.

Index. Vue fragment:

MonthOption: [{name: new Date().getMonth() + 1 + 'monthmonth ', color: '#1989fa', timeStr: New Date().format(' YYYY-mm ')}, {name: new Date().addmonths (-1).getMonth() + 1 + 'month ', timeStr: New Date().addmonths (-1).format(' YYYY-mm ')}, {name: new Date().addmonths (-2).getMonth() + 1 + 'month ', timeStr: New Date().addmonths (-1).format(' YYYY-mm ')}, {name: new Date().addmonths (-1).getMonth() + 1 + 'month ', timeStr: Format (' YYYY-mm ')}, {name: new Date().addmonths (-4).getMonth() + 1 + 'month ', timeStr: New Date().addmonths (-4).format(' YYYY-mm ')}, {name: new Date().addmonths (-5).getMonth() + 1 + 'month ', timeStr: new Date().addMonths(-5).format('yyyy-MM') } ]Copy the code

The prototype. Js fragment:

Object.defineProperty(Date.prototype, 'addMonths', {
  value: function(months) {
    if (months === undefined || months === '') {
      months = 1
    }
    console.log(this.getMonth(),months)
    this.setMonth(this.getMonth() + months)
    return this
  }
})
Copy the code

Print the result

new Date(new Date('2020-12-31').addMonths(-1)).format('yyyy-MM-dd') //  11 -1 "2020-12-01"
new Date(new Date('2020-12-31').addMonths(-2)).format('yyyy-MM-dd') //  11 -2 "2020-10-31"
new Date(new Date('2020-12-31').addMonths(-3)).format('yyyy-MM-dd') //  11 -3 "2020-10-01"
new Date(new Date('2020-12-31').addMonths(-4)).format('yyyy-MM-dd') // 11 -4 "2020-08-31"
new Date(new Date('2020-12-31').addMonths(-5)).format('yyyy-MM-dd') // 11 -5 "2020-07-31"
new Date(new Date('2020-12-31').addMonths(-6)).format('yyyy-MM-dd') // 11 -6 "2020-07-01"
new Date(new Date('2020-12-31').addMonths(-7)).format('yyyy-MM-dd') // 11 -7 "2020-05-31"
new Date(new Date('2020-12-31').addMonths(-8)).format('yyyy-MM-dd') // 11 -8 "2020-05-01"
new Date(new Date('2020-12-31').addMonths(-9)).format('yyyy-MM-dd') // 11 -9 "2020-03-31"
new Date(new Date('2020-12-31').addMonths(-10)).format('yyyy-MM-dd') // 11 -10 "2020-03-02"
new Date(new Date('2020-12-31').addMonths(-11)).format('yyyy-MM-dd') // 11 -11 "2020-01-31"
new Date(new Date('2020-12-31').addMonths(-12)).format('yyyy-MM-dd') // 11 -12 "2019-12-31"
new Date(new Date('2020-12-31').addMonths(-10)).format('yyyy-MM-dd') // 11 -10 "2020-03-02"
Copy the code

From the print above, we can see that this.getmonths () and calculated months passed in are output correctly, so the problem occurred during setMonth. I searched MDN data online and found the following description:

Click to jump quickly to the date.prototype.setmonth () method

If a parameter you specify is outside of the expected range, setMonth() attempts to update the date information in the Date object accordingly. For example, if you use 15 for monthValue, the year will be incremented by 1, and 3 will be used for month.

The current day of month will have an impact on the behavior of this method. Conceptually it will add the number of days given by the current day of the month to the 1st day of the new month specified as the parameter, to return the new date. For example, if the current value is 31st August 2016, calling setMonth with a value of 1 will return 2nd March 2016. This is because in 2016 February had 29 days.

If the specified parameter is outside the expected range, setMonth() attempts to update the date information in the date object accordingly. For example, if monthValue is 15,year is incremented by 1 and month by 3.

The current date of the month affects the behavior of the method. Conceptually, it returns the new date by adding the number of days given by the current date to the first day of the new month specified as an argument. For example, if the current value is August 31, 2016, calling setMonth with the value 1 will return March 2, 2016. That’s because February 2016 has 29 days.

Reasoning into our project. On The 31st of December. Calling addMonths(-1) is equivalent to calling the setMonth(10,31) method. Since There are only 30 days in November, 31 days will be added in November. The result will be a day later, to December 1.

Project on-line plan:

This scheme, without using the setMonth() method, returns the corresponding date character by calculating the year, month and day directly. Business scenarios don’t need dates, just months.

function addMonth(date, months) { var y = date.getFullYear() var m = date.getMonth() var d = date.getDate() y += Math.floor((m + months) / 12) If (m <= 0) {m += 12} var d_max = new Date(y, If (d > d_max) {d = d_max} return y + '-' + (m < 10? '0' + m : m) + '-' + (d < 10 ? '0' + d : d) } addMonth(new Date('2020-12-31'),2)Copy the code

Later, check the excellent plug-in setMonth() source code, find the above features for setMonth method, moment inside the solution:

get(mom, 'Month') + months * isAdding) function mod(n, x) { return ((n % x) + x) % x; } function daysInMonth(year, month) { if (isNaN(year) || isNaN(month)) {return NaN; } var modMonth = mod(month, 12); year += (month - modMonth) / 12; return modMonth === 1 ? isLeapYear(year) ? 29 : 28 : 31 - ((modMonth % 7) % 2); } dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value)); mom._d['setMonth'](value, dayOfMonth);Copy the code

It is recommended that you avoid defining date functions yourself in later development. Use as many good plug-ins as you can. Moment, Dayjs, etc.