简体   繁体   English

计算是否在月份的最后X天,然后增加月份

[英]Calculate if last X day of month then increment month

I'm trying to fix an issue with a Vue JS application form's pay frequency <select> . 我正在尝试解决Vue JS应用程序表单的付款频率<select> To explain a little about what I have, I'll add some context here. 为了对我所拥有的内容进行一些解释,我将在此处添加一些上下文。

There's an application form, with a <select> box with some options for the user to select when they're next paid, eg: Last Working day of the month, Weekly, Bi-weekly, Last Monday of the month, Last Tuesday of the month etc etc, the options available I will list out below. 有一个申请表,带有一个<select>框,其中带有一些选项供用户选择下一次付款的时间,例如:每月的最后一个工作日,每周,双周,每月的最后一个星期一,月份等,我将在下面列出可用的选项。

The user selects the appropriate <option> and their Next & Following pay dates are automatically calculated, eg: Next pay: 30/08/2019, Following pay: 27/09/2019. 用户选择适当的<option>并自动计算其下一个和下一个支付日期,例如:下一个支付:30/08/2019,后续支付:27/09/2019。 The user has the option to edit these fields if they'd like to. 用户可以根据需要选择编辑这些字段。

There's 3 input fields for Next pay date , and 3 input fields for Following pay date , (DD/MM/YYYY) fields. 还有用于下次发薪日起 3个输入字段,并按照支付日 ,(DD / MM / YYYY)领域3个输入字段。

The problem I'm having is in relation to the pay frequency options for the last week of every month, eg: Last Monday of the month, Last Tuesday of the month, right the way through to the Friday. 我遇到的问题与每月最后一周的支付频率选项有关,例如:每月的最后一个星期一,每月的最后一个星期二,一直到星期五。 The problem is that if for instance I'm on the last Thursday of the month, say the date is the 29/08/2019, and then I select the option Last Monday of the month , rather than automatically adding 1 month to the month field, it stays on the current month, and this is incorrect because you can't have a Next pay date that is in the past. 问题是,例如如果我在该月的最后一个星期四,说日期是29/08/2019,然后我选择了该月的最后一个星期一选项,而不是自动将1个月添加到该月字段,它停留在当月,这是不正确的,因为您不能有过去的下一个支付日期。

I'm using Moment JS , version 2.24.0, and using Vue JS version 2.6.10, there's also the package vee-validate for validation that's set up already. 我使用的是Moment JS版本2.24.0,使用的是Vue JS版本2.6.10,还有用于验证的vee-validate软件包。

I have a few methods that are in place to essentially figure out the user's next and following pay dates, the payFrequencyChange method listed below calculates each of the available pay frequency options that the user can select from. 我有一些方法可以用来确定用户的下一个和之后的支付日期,下面列出的payFrequencyChange方法计算用户可以选择的每个可用支付频率选项。 I've tried checking the code, and it seems like it should be calculating the month fields correctly based on the date, but isn't. 我试过检查代码,似乎应该根据日期正确计算月份字段,但事实并非如此。

Here's the code in question: 这是有问题的代码:


    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()
        }
      }
    })

So with the above, everything will work perfectly fine as it's the start of the month, however, if you update your computer's time/date to be for instance, 29th August 2019, then when selecting the options: Last Monday - Thursday, it should increment the Next month, and Following month fields, but when selecting the Last Friday, it should remain on the current month, unless it's 3 days before the end of the month and then it should also increment. 因此,使用上述方法,一切都将在月初顺利运行,但是,如果您将计算机的时间/日期更新为例如2019年8月29日,则在选择以下选项时:上周一-周四增加“下个月”和“下个月”字段,但是当选择“最后一个星期五”时,它应保留在当月,除非在月末前三天,然后也应增加。

I understand that this is a lot to take in, and thus have prepared a Code Pen in addition: 我知道要花很多钱,因此还准备了一支Code Pen:

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

Some help would be appreciated here, this isn't something that I've written so aren't entirely 100% sure how to fix/add this critical bit of functionality. 在这里将获得一些帮助,这不是我写的,因此不能完全100%确定如何修复/添加此关键功能。

You can get the required feature by changing couple of things in the lastWeekdayOfMonth function as below 您可以通过在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')
        }
    }
},

Here I have modularized the code a bit and added another function which will do specific work. 在这里,我对代码进行了一些模块化,并添加了另一个函数来完成特定的工作。

And I am just checking if the result is before the given date go and check for the next month. 我只是在检查结果是否在给定日期之前,然后检查下个月。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM