计算是否最后一个X天然后增加月份

时间:2019-08-03 08:26:03

标签: javascript datetime vue.js vuejs2 momentjs

我正在尝试解决Vue JS应用程序表单的付款频率<select>的问题。为了对我所拥有的内容进行一些解释,我将在此处添加一些上下文。

有一个申请表,带有一个<select>框,其中有一些选项供用户选择下一次付款的时间,例如:该月的最后一个工作日,每周,每两周,最后一个星期一一个月,该月的最后一个星期二等,我将在下面列出可用的选项。

用户选择合适的<option>,并自动计算其下一个和下一个支付日期,例如:下一个支付:30/08/2019,后续支付:27/09/2019。用户可以根据需要选择编辑这些字段。

下一个支付日期有3个输入字段,以下支付日期有(DD / MM / YYYY)字段3个输入字段。

我遇到的问题与每月最后周的支付频率选项有关,例如:该月的最后一个星期一,该月的最后一个星期二到星期五。问题是,例如,如果我在每月的最后一个星期四,假设日期是29/08/2019,然后选择选项该月的最后一个星期一,而不是自动将1个月添加到月份字段中,它将保留在当前月份,这是不正确的,因为您不能有过去的下一个支付日期。

我使用的是 Moment JS (2.24.0版),并且使用的是 Vue JS (2.6.10版),还有软件包 vee-validate 用于已经设置的验证。

我有一些方法可以用来确定用户的下一个和之后的支付日期,下面列出的payFrequencyChange方法计算出用户可以选择的每个可用支付频率选项。我试过检查代码,似乎应该根据日期正确地计算 month 字段,但不是。

这是有问题的代码:


    new Vue({
      el: '#application-form',
      data: {
        frequency: [{ value: 0, name: 'Last working day of month' }, { value: 1, name: 'Weekly' }, { value: 2, name: 'Four weekly' }, { value: 10, name: 'Specific Date' }, { value: 3, name: 'Bi-Weekly' }, { value: 9, name: 'Last Friday of month' }, { value: 5, name: 'Last Monday of month' }, { value: 6, name: 'Last Tuesday of month' }, { value: 7, name: 'Last Wednesday of month' }, { value: 8, name: 'Last Thursday of month' }],
        NextPaydateError: false,
        FollowingPaydateError: false,
        formData: {
          EmpPayFrequency: '',
          NextPaydate: '',
          FollowingPaydate: '',
          NextPaydateDay: '',
          NextPaydateMonth: '',
          NextPaydateYear: '',
          FollowingPaydateDay: '',
          FollowingPaydateMonth: '',
          FollowingPaydateYear: ''
        }
      },
      methods: {

        /**
         * Switch fields
         */
        switchToField(fieldSwitchName, fieldValue, fieldLength) {
          if (String(fieldValue).length >= fieldLength) {
            this.$refs[fieldSwitchName].focus();
          }
        },

        /**
         * Leading Zero
         * @param {int} input
         * @param {bool} years
         */
        leadingZeros: function leadingZeros(input, years = false) {
          if (!years) {
            if (String(input).length === 1) return '0' + input
          } else {
            if (String(input).length === 2) {
              if (parseInt(input) > 50 && parseInt(input) < 100) {
                return '19' + input
              }
            }
          }
          return input
        },

        /**
         * Next Pay Date Change
         */
        nextPayDateChange: function nextPayDateChange() {
          string = this.formData.NextPaydateYear + '-' + this.formData.NextPaydateMonth + '-' + this.formData.NextPaydateDay
          date = moment(string).format('DD/MM/YYYY')
          if (this.formData.NextPaydateYear === '') return
          this.NextPaydateError = (date === 'Invalid date') ? true : false
          this.formData.NextPaydate = date
        },

        /**
         * Following Pay Date Change
         */
        followingPayDateChange: function followingPayDateChange() {
          nextDate = this.formData.NextPaydateYear + '-' + this.formData.NextPaydateMonth + '-' + this.formData.NextPaydateDay
          followingDate = this.formData.FollowingPaydateYear + '-' + this.formData.FollowingPaydateMonth + '-' + this.formData.FollowingPaydateDay
          if (!moment(followingDate).isAfter(moment(nextDate))) {
            this.FollowingPaydateError = true
            return
          }
          date = moment(followingDate).format('DD/MM/YYYY')
          if (this.formData.FollowingPaydateYear === '') return
          this.FollowingPaydateError = (date === 'Invalid date') ? true : false
          this.formData.FollowingPaydate = date
        },

        /**
         * Find Last Working Day
         * @param {bool} nextMonth
         */
        lastBusinessDay: function lastBusinessDay(nextMonth) {
          dateOffset = {
            'Saturday': 1,
            'Sunday': 2
          }
          currentDate = new Date()
          date = new Date(currentDate.getFullYear(), currentDate.getMonth() + (nextMonth ? 2 : 1), 0)
          lastDay = date.toLocaleString('en-GB', {
            day: 'numeric'
          })
          lastWeekday = date.toLocaleString('en-GB', {
            weekday: 'long',
          })
          return dateOffset[lastWeekday] ? lastDay - dateOffset[lastWeekday] : lastDay
        },

        /**
         * Find Last Weekday
         * @param {object} monthMoment
         * @param {int} dayInt
         */
        lastWeekdayOfMonth: function weekly(monthMoment, dayInt) {
          var lastDay = monthMoment.endOf('month').startOf('day')
          for (let i = 0; i <= 10; i++) {
            if (lastDay.day() === dayInt) {
              return lastDay
            } else {
              lastDay.subtract(1, 'days')
            }
          }
        },

        /**
         * Weekly Workouts
         */
        weekly: function weekly(year, month, date, day) {
            date = new Date()
            offset = 4
            result = null
            if ('undefined' === typeof day || null === day) {
                day = 5
            }
            if ('undefined' === typeof year || null === year) {
                year = date.getFullYear()
            }
            if ('undefined' === typeof month || null === month) {
                month = date.getMonth()
            }
            do {
                result = new Date(year, month, date.getDate() + offset)
                offset++
            } while (result.getDay() !== day)
            return result
        },

        /**
         * Pay Frequency Change
         * @param {int} value
         */
        payFrequencyChange: function payFrequencyChange(value) {
          var elems = document.querySelectorAll('.dobbox.is-invalid')
          if (typeof elems === 'object') {
            elems.forEach.call(elems, function(el) {
              el.classList.remove('is-invalid')
            });
          }
          currentDate = new Date()
          switch (parseInt(value)) {
            case 0: // last working day
              next = {
                day: this.lastBusinessDay(false),
                month: currentDate.getMonth() + 1,
                year: currentDate.getFullYear()
              }
              following = {
                day: this.lastBusinessDay(true),
                month: ((currentDate.getMonth() + 2) === 13) ? 1 : currentDate.getMonth() + 2,
                year: ((currentDate.getMonth() + 2) === 13) ? currentDate.getFullYear() + 1 : currentDate.getFullYear()
              }
              break
            case 1: // weekly
              next = this.weekly(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate(), 5)
              follow = new Date(this.weekly(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate(), 5))
              following = follow.setDate(follow.getDate() + 7)
              next = {
                day: moment(next).format('DD'),
                month: moment(next).format('MM'),
                year: moment(next).format('YYYY')
              }
              following = {
                day: moment(following).format('DD'),
                month: moment(following).format('MM'),
                year: moment(following).format('YYYY')
              }
              break
            case 2: // four weekly
              next = this.weekly(currentDate.getFullYear(),currentDate.getMonth(), currentDate.getDate() + 4)
              d = new Date(this.weekly(currentDate.getFullYear(),currentDate.getMonth(), currentDate.getDate() + 4))
              d.setDate(d.getDate() + 28)
              following = d
              next = {
                day: moment(next).format('DD'),
                month: moment(next).format('MM'),
                year: moment(next).format('YYYY')
              }
              following = {
                day: moment(following).format('DD'),
                month: moment(following).format('MM'),
                year: moment(following).format('YYYY')
              }
              break
            case 10: // specific date
              next = { day: '', month: '', year: '' }
              following = { day: '', month: '', year: '' }
              break
            case 3: // bi-weekly
              next = { day: '', month: '', year: '' }
              following = { day: '', month: '', year: '' }
              break
            case 9: // last friday
              next = this.lastWeekdayOfMonth(moment(), 5)
              following = this.lastWeekdayOfMonth(moment().add(1, 'months'), 5)
              next = {
                day: moment(next).format('DD'),
                month: moment(next).format('MM'),
                year: moment(next).format('YYYY')
              }
              following = {
                day: moment(following).format('DD'),
                month: moment(following).format('MM'),
                year: moment(following).format('YYYY')
              }
              break
            case 8: // last thursday
              next = this.lastWeekdayOfMonth(moment(), 4)
              following = this.lastWeekdayOfMonth(moment().add(1, 'months'), 4)
              next = {
                day: moment(next).format('DD'),
                month: moment(next).format('MM'),
                year: moment(next).format('YYYY')
              }
              following = {
                day: moment(following).format('DD'),
                month: moment(following).format('MM'),
                year: moment(following).format('YYYY')
              }
              break
            case 7: // last wednesday
              next = this.lastWeekdayOfMonth(moment(), 3)
              following = this.lastWeekdayOfMonth(moment().add(1, 'months'), 3)
              next = {
                day: moment(next).format('DD'),
                month: moment(next).format('MM'),
                year: moment(next).format('YYYY')
              }
              following = {
                day: moment(following).format('DD'),
                month: moment(following).format('MM'),
                year: moment(following).format('YYYY')
              }
              break
            case 6: // last tuesday
              next = this.lastWeekdayOfMonth(moment(), 2)
              following = this.lastWeekdayOfMonth(moment().add(1, 'months'), 2)
              next = {
                day: moment(next).format('DD'),
                month: moment(next).format('MM'),
                year: moment(next).format('YYYY')
              }
              following = {
                day: moment(following).format('DD'),
                month: moment(following).format('MM'),
                year: moment(following).format('YYYY')
              }
              break
            case 5: // last monday
              next = this.lastWeekdayOfMonth(moment(), 1)
              following = this.lastWeekdayOfMonth(moment().add(1, 'months'), 1)
              next = {
                day: moment(next).format('DD'),
                month: moment(next).format('MM'),
                year: moment(next).format('YYYY')
              }
              following = {
                day: moment(following).format('DD'),
                month: moment(following).format('MM'),
                year: moment(following).format('YYYY')
              }
              break
          }
          // Populate new dates
          this.formData.NextPaydateDay = this.leadingZeros(next.day)
          this.formData.NextPaydateYear = next.year
          this.formData.NextPaydateMonth = this.leadingZeros(next.month)
          this.formData.FollowingPaydateDay = this.leadingZeros(following.day)
          this.formData.FollowingPaydateYear = following.year
          this.formData.FollowingPaydateMonth = this.leadingZeros(following.month)
          setTimeout(function () { // Prevent validation errors
            this.NextPaydateError = this.FollowingPaydateError = false
          }.bind(this), 10)
        }

      },
      watch: {
        'formData.NextPaydateYear': function formDataNextPaydateYear() {
          this.nextPayDateChange()
        },
        'formData.FollowingPaydateYear': function formDataFollowingPaydateYear() {
          this.followingPayDateChange()
        }
      }
    })

因此,如上所述,一切都将在月初顺利进行,但是,如果您将计算机的时间/日期更新为例如2019年8月29日,则在选择以下选项时:上周一至周四,则应增加“下个月”和“下个月”字段,但在选择“最后一个星期五”时,它应保留在当月,除非在月末前三天,然后也应增加。

我知道要花很多钱,因此还准备了一支密码笔:

https://codepen.io/sts-ryan-holton/pen/rXGzox

这里会提供一些帮助,这不是我写的,所以不是完全100%确定如何修复/添加这一关键功能。

1 个答案:

答案 0 :(得分:0)

您可以通过在 lastWeekdayOfMonth 函数中更改以下几项来获得所需的功能

lastWeekdayOfMonth: function weekly(monthMoment, dayInt) {
    var lastDay = moment(monthMoment).endOf('month').startOf('day')
    var result = this.__lastWeekdayOfMonth(lastDay, dayInt)
    if( result.isBefore(monthMoment) ) {
        lastDay = moment(lastDay).add(1, 'month')
        result = this.__lastWeekdayOfMonth(lastDay, dayInt)
    }
    return result
},
__lastWeekdayOfMonth: function __weekly(lastDay, dayInt) {
    for (let i = 0; i <= 10; i++) {
        if (lastDay.day() === dayInt) {
            return lastDay
        } else {
            lastDay.subtract(1, 'days')
        }
    }
},

在这里,我对代码进行了一些模块化,并添加了另一个可以完成特定工作的功能。

我只是检查结果是否在给定日期之前,然后检查下个月。