Installation and use of leave-days-Calculator

The installation

$ npm install leave-days-calculator
Copy the code

The introduction of

import leaveDaysCalculator form 'leave-days-calculator'
Copy the code

use

const start = 'the 2020-06-22 in the morning'
const end = 'the 2020-06-24 in the afternoon
let leaveDays = leaveDaysCalculator(start, end) / / 3
Copy the code

The time format can only be YYYY-MM-DD am/PM

If you like it and can help you start it, github.

Demand background

Since I made the small program field punching requirement, I continued to develop the approval process for leave. When DEALING with the leave form, there was a display of the duration of leave. When the user selects the start time and end time of the leave, it can automatically calculate the duration of the leave, which sounds routine. But, ha, ha, ha, all leave product requirements in accordance with the along while, please, such as:

Leave starts on the morning of June 1 and ends on the morning of June 2. It is not as simple as the end time minus the start time. Morning to morning this situation, a long time. 😂 😂 😂

So the question is, how to accurately calculate the duration of leave?

The solution

Finally, the first scheme was adopted

Solution a:

Based on current leave and non-current leave,

For the day off:

  • From the morning of the day to the morning of the day, the duration of leave is 0.5d;
  • From the morning of the day to the afternoon of the day, the duration of leave is 1.0d;
  • Start time of the day afternoon – end time of the day morning, error warning processing;
  • Start time of the day afternoon – end time of the day afternoon, leave time 0.5d;

If it is calculated on the next day: End time – Start time = gap

  • End time am, start time am, Gap + 0.5
  • End time am, start time PM, Gap + 1
  • End time afternoon, start time morning, gap + 0
  • End time afternoon, start time afternoon, gap + 0.5

The core of this program is the need to accurately calculate the gap, can use third-party tools to deal with. From the point of calculation, the workload is relatively small.

My master may really look down, I wrote a push of redundant code, write a version for me, after fine-tuning the scheme a code is as follows:

const getLeaveDays = (start, end) = > {
    const [times, tags] = start.split(' ')
    const [timet, tagt] = end.split(' ')
    const startStr = +new Date(... times.split(The '-'))
    const endStr = +new Date(... timet.split(The '-'))
    const timeDiff1 = tagt === tags ? 0.5 : {'morning': 'error'.'afternoon': 1 }[tagt] / / in the day
    const timeDiff2 = tagt === tags ? 0.5 : {'morning': 0.'afternoon': 1 }[tagt] / / the next day
    
    if(startStr > endStr) {
        return 'error'
    }
    else if(timet === times) {
        return timeDiff1
    } 
    else {
        return (endStr - startStr) / (60 * 60 * 24 * 1000) + timeDiff2
    }
}
Copy the code

Scheme 2:

Pure manual calculation, according to the same day on the afternoon, next day on the afternoon, every other month on the afternoon, every other year on the afternoon of manual calculation of leave. The development time of this scheme is relatively long, and I choose the scheme when the development cycle is relatively rich, because I still want to know the specific calculation. Find something to do for yourself, add some fun to the boring coding.

Manually implement a leave duration calculator

The format based on the start time and end time is YYYY-MM-DD am/PM.

Figure 1: Flow chart

There are four calculation rules:

  • The duration of leave on the same day of the same month in the same year shall be calculated
  • The duration of leave on other days in the same month of the same year shall be calculated
  • The duration of leave in a year other than the same month shall be calculated
  • The duration of leave not in the same year shall be calculated

Some basic utility functions are required, such as:

  • Is it a leap year
  • The number of days in each month of a year
  • To 0 function
  • Add 0 function

Business common approach:

  • Start time, year month day
  • End time, month is
  • Calculation method of the number of days off on the same day
  • Calculation method of the number of days of leave in the next day
  • The total number of days in the beginning month, the calculation method of the number of days for leave in the beginning month (a function only used in a month or a year)
  • Calculation method for days of leave in the end month (a function only used in a month or year)
  • Intermediate month day accumulator
  • The number of days of leave in the beginning year: the number of days remaining in the beginning month + the number of days remaining in the beginning month
  • Number of days of leave in the end year: number of days in the end month + number of days in the month before the end month
  • Day accumulator for intermediate years

The following is the time for leave calculator source, for reference only.

/** * @Authors youxiaoxiao ([email protected]) * @Date: 2020-06-1 * @Last Modified by: Leave duration calculator :(calculate leave duration by (start time + end time) */

/** * is a leap year * @param {*} year */
function isLeapYear (year) {
    return year % 100! = =0 && year % 4= = =0 || year % 400= = =0
}


/** * Obtain the number of days in a month * @param {*} year * @param {*} month */
function getMaxDay (year, month) {
    year = parseFloat(year)
    month = parseFloat(month)
    if (month === 2) {
        return isLeapYear(year) ? 29 : 28
    }
    return [4.6.9.11].indexOf(month) >= 0 ? 30 : 31
}


/ / to zero
function trimZero (val) {
    val = String(val)
    val = val ? parseFloat(val.replace(/^0+/g.' ')) : ' '
    val = val || 0
    val = val + ' '
    return val
}

/** * leave on the same day */
function sameDayLeave(startNoon, endNoon) {
    let leaveDays = 0
    if (startNoon === endNoon) {
        leaveDays = 0.5
    } 
    else if (startNoon === 'morning' && endNoon === 'afternoon') {
        leaveDays = 1
    } 
    else if (startNoon === 'afternoon' && endNoon === 'morning') {
        console.log('You have chosen the wrong time')}return leaveDays
}


/** ** leave the next day */
function nextDayLeave(startDay, endDay, startNoon, endNoon) {
    let leaveDays = 0
    if (startNoon === 'morning' && endNoon === 'morning') {
        leaveDays = endDay - startDay + 0.5 
    } 
    else if (startNoon === 'morning' && endNoon === 'afternoon') {
        leaveDays = endDay - startDay + 1 
    } 
    else if (startNoon === 'afternoon' && endNoon === 'morning') {
        leaveDays = endDay - startDay
    } 
    else if (startNoon === 'afternoon' && endNoon === 'afternoon') {
        leaveDays = endDay - startDay + 0.5
    }
    return leaveDays
}


/ * * * start off days across the month, the month will not use the function of * /
function startMonthLeaveDays (startMonthAllDays, startDay, startNoon) {
    let startMonthLeave = 0
    if (startNoon === 'morning') {
        startMonthLeave = Number(startMonthAllDays) -  Number(startDay) + 1
    } else if (startNoon === 'afternoon') {
        startMonthLeave = Number(startMonthAllDays) -  Number(startDay) + 0.5
    }
    return Number(startMonthLeave)
}


/ * * * for leave days across the month end of month, will not use the function of * /
function endMonthLeaveDays(endDay, endNoon) {
    let endLeaveDays = 0
    if (endNoon === 'morning') {
        endLeaveDays = endDay - 0.5
    } else if (endNoon === 'afternoon') {
        endLeaveDays = endDay
    }
    return Number(endLeaveDays)
}


* @param {*} start [supported: yyyY-MM-DD n] * @param {*} end [supported: YYYY-MM-DD n] */ Calculates the leave duration by the start time and end time
export default (start, end) => {
    if(! start || ! end)return 0

    const startArr = start.split(' ') // Start time
    const endArr = end.split(' ') // End time
    const startDate = startArr[0] // Start date
    const endDate = endArr[0] // End date


    const startDateArr = startDate.split(The '-') // Start date is aggregated
    const endDateArr = endDate.split(The '-') // The end date is grouped


    const startYear = startDateArr[0] // Start date: year
    const startMonth = startDateArr[1] // Start date: month
    const startDay = startDateArr[2] // Start date: day
    const startNoon = startArr[1] // Start time in the early afternoon


    const endYear = endDateArr[0] // End date: year
    const endMonth = endDateArr[1] // End date: Month
    const endDay = endDateArr[2] // End date: date
    const endNoon = endArr[1] // End time in the early afternoon


    // Total number of days in the starting month
    const startMonthAllDays = getMaxDay(startYear, startMonth)


    /** * The number of days of leave in the middle month is calculated */
    function centerMonthsLeave() {
        // Add the number of days in the middle month
        let leaveDays = 0
        let monthArr = [] // Month array
        for(let i = Number(trimZero(startMonth)); i <= Number(trimZero(endMonth)); i++) {
            monthArr.push(i)
        }

        let everyMonthDays = 0
        if (monthArr.length > 2) {
            monthArr.pop()
            monthArr.shift()
            
            monthArr.forEach(month= > {
                everyMonthDays = Number(everyMonthDays) + Number(getMaxDay(startYear, month))
            })
        }
        return (Number(leaveDays) + Number(everyMonthDays)).toFixed(1)}/** * Start month and end month leave days leave in adjacent months, or leave across months */
    function startEndMonthNext() {
        // Calculate the days of leave in the beginning month
        let startLeaveDays = startMonthLeaveDays(startMonthAllDays, startDay, startNoon) 
        
        // End the month of leave days calculation
        let endLeaveDays = endMonthLeaveDays(endDay, endNoon)

        // Days add up
        return Number(startLeaveDays) + Number(endLeaveDays) || 0
    }


    /** * The number of days of leave in the beginning year */
    function startYearLeaveDays () {
        // Start month count
        let startMonthDays = startMonthLeaveDays(startMonthAllDays, startDay, startNoon) 

        // Days of remaining months
        let otherMonthDays = 0
        for(let i = Number(trimZero(startMonth)) + 1;  i <= 12; i++) {
            otherMonthDays = Number(otherMonthDays) + Number(getMaxDay(startYear, i))
        }

        return Number(startMonthDays) + Number(otherMonthDays) || 0
    }


    /** * The number of days of leave at the end of the year */
    function endYearLeaveDays() {
        let endYearDays = 0
        // End the month count
        let endLeaveDays = endMonthLeaveDays(endDay, endNoon)

        // Add up the previous months
        for(let i = 1; i < trimZero(endMonth); i++) {
            endYearDays = Number(endYearDays) + Number(getMaxDay(endYear, i))
        }

        return Number(endYearDays) + Number(endLeaveDays)
    }


    /** ** New Year, the middle year of the holiday calculated */
    function centerYearsLeaveDays () {
        let centerYear = 0
        if(endYear - startYear > 1) {
            let centerYears = []
            for(let startYear; startYear < endYear; startYear++) {
                centerYears.push(startYear)
            }
            centerYears.pop()
            centerYears.shift()
            centerYears.forEach(year= > {
                for(let month = 1; month <=12; month++) {
                    centerYear = centerYear + getMaxDay(year, month)
                }
            })
        }
        return centerYear
    }

    // Days of absence
    let leaveAllDays = 0
    // Whether the same year
    if (startYear === endYear) {
        // Is it the same month
        if (startMonth === endMonth) {
            // The same day
            if (startDay === endDay) {
                leaveAllDays = sameDayLeave(startNoon, endNoon)

            // Take leave on alternate days in the same year and month
            } else if (startDay < endDay) {
                leaveAllDays = nextDayLeave(startDay, endDay, startNoon, endNoon)

            } else {
                console.log('The end time is on the wrong day')}The same year is not the same month
        } else if (startMonth < endMonth) {
            // In the case of two consecutive months, the sum of the remaining days in the beginning month and the days of leave in the end month
            let startEndMonthLeaveDays = startEndMonthNext()

            // The number of days of leave in the middle month
            let centerMonthsDays = centerMonthsLeave()

            // Total days of leave
            leaveAllDays = Number(startEndMonthLeaveDays) + Number(centerMonthsDays)
        } else {
            console.log('Ending in the wrong month')}// Not the same year
    } else if (startYear < endYear) {
        // The number of days of leave in the beginning year is calculated as the number of days remaining in the beginning month + the number of days remaining in the beginning month
        let startYearDays = startYearLeaveDays()

        // Number of days of leave at the end of the year: number of days in the end month + number of days in the month before the end month
        let endYearDays = endYearLeaveDays()

        // The number of days in the middle year
        let centerYear = centerYearsLeaveDays()
        
        // Total number of days off
        leaveAllDays = Number(startYearDays) + Number(endYearDays) + Number(centerYear)
    } else {
        console.log('Ended in the wrong year')}// console.log(leaveAllDays)s
    return leaveAllDays
}
Copy the code

A leave time calculator on the development of the end, in fact, plan 1 more trouble, plan 2 to achieve, there are many points can be optimized. The final packaged leave duration calculator NPM package is leave-days-calculator.

If you have other solutions or optimization implementation, feel free to leave a comment below.