1. 程式人生 > >Javascript 計算請假天數

Javascript 計算請假天數

代碼 spa ima -s var BYD 相減 必須 clas

轉載請註明本文地址:https://www.cnblogs.com/qiaoge0923/p/10219155.html


計算請假天數,籠統來說就是計算兩個日期的差值。對於JS來說,兩個時間直接相減,得到的是這兩個時間差的毫秒數。

先上代碼後貼圖。

1.測試數據

後文中用到的測試數據如下:

var dateStart = ‘2018-12-01 04:15‘,
    dateEnd = ‘2018-12-08 12:15‘;
var MS_HOUR = 1000*60*60;

2.時間差毫秒數

普通計算兩個時間差的方法如下:

function getDiff(start, end)
{
    
var s = Date.parse(start), e = Date.parse(end); //取絕對值 return Math.abs(e - s); } console.log(getDiff(dateStart, dateEnd)); 輸出: 633600000

3.時間差小時數

計算兩個時間差的小時數:

function getDiffByHour(start, end)
{
    /****
     * start:請假開始時間
     * end:請假結束時間
     * 計算小時數(1位小數)
     * **
*/ var s = Date.parse(start), e = Date.parse(end); //取絕對值 var diff = Math.abs(e - s); return (diff / (1000 * 60 * 60)).toFixed(1); } console.log(getDiffByHour(dateStart, dateEnd)); 輸出: 176.0

4.簡單請假規則

不同單位對請假的限制條件不同,現規定請假天數計算規則如下:

1、請假半天記0.5天;

2、小於半天部分,1小時計0.1天,2小時計0.2天,以此類推

那麽計算邏輯也還比較簡單:

function getDiffByDay(start, end)
{
    /****
     * start:請假開始時間
     * end:請假結束時間
     * 計算天數,半天按0.5天計算,小於半天,1小時計0.1天,2小時計0.2天,3小時計0.3天,4小時計0.4天(1位小數)
     * ***/
    var s = Date.parse(start),
        e = Date.parse(end);
    //取絕對值
    var diff = Math.abs(e - s);

    var result = 0,
        hour = Math.floor(diff / (1000 * 60 * 60)),
        day = Math.floor(diff / (1000 * 60 * 60 * 24));

    result = day;
    if (day > 0)
    {
        //去掉天數部分,僅留小時數
        hour -= day * 24;
    }
    if (hour > 5)
    {
        //如果大於半天(5小時)
        result += 0.5;
        hour = Math.floor((diff - (day * 24 + 5) * 1000 * 60 * 60) / (1000 * 60 * 60));
    }
    if (hour > 1)
    {
        result += hour * 0.1;
    }
    return result;
}
console.log(getDiffByDay(dateStart, dateEnd));

輸出:
7.8

5.復雜請假規則

倘若規定上下班時間,中午休息時間,工作時長等等,那計算的邏輯就相當復雜了。

現規定上下班及午休時間如下:

上班時間:8:00

下班時間:18:00

午休時間:12:00-14:00

(正常日工作時長:8小時)

那麽,請假1小時則為1/8天,4小時即為0.5天。

簡單分析:

1.請假時段在同一天內,直接計算;

2.請假時段跨越了多天的情況,我們可以把請假時間分成兩個部分,請假時間 start 至 end,可以看成第一部分: start的時間起到第二天 end時間止的請假時長,第二部分:start日期與end日期之間的天數(不含start和end)。

例如:請假時段 ‘2018-01-01 8:00’ 至 ‘2018-01-03 12:00‘,那麽請假時長可以分為 ‘2018-01-01 8:00‘至‘2018-01-02 12:00‘的時長(過濾閑暇時間和午休時間),和‘2018-01-01‘至‘2018-01-03‘間的天數,即為 1.5+1=2.5天。

5.1 請假時間在同一個日期

這種情況下,直接是end-start然後除去午休時間,最後得到的小時數來計算天數。

function getLeaveDayInOneDay(start, end, wt)
{
    /**
     * 獲取一天內的請假天數
     * @start:起始時間
     * @end:截止時間
     * @wt:作息時間,包含上下班時間和午休時間
     * */
    var diff = { };
    diff.d = 0;
    /**
     * diff:
     * {
     *      d:天數
     *      h:小時數
     *      st:起始時間毫秒數
     *      et:截止時間毫秒數
     * }
     * */
    try
    {
        var startInt = Date.parse(start),
            endInt = Date.parse(end);

        if (startInt <= wt.on && wt.off <= endInt)
        { //全天
            diff.d = 1.0;
        }
        else if (startInt <= wt.on && wt.noonOn <= endInt && endInt <= wt.noonOff)
        { //上半天
            diff.d = 0.5;
        }
        else if (wt.noonOn <= startInt && startInt <= wt.noonOff && wt.off <= endInt)
        { //下半天
            diff.d = 0.5;
        }
        else
        {
            //去除極端情況,確保請假時間在工作時間內
            diff.st = Math.max(wt.on, startInt); //取上班時間內
            diff.st = diff.st <= wt.noonOn ? diff.st : (wt.noonOff <= diff.st ? diff.st : wt.noonOff && wt.on != endInt);
            diff.st = Math.min(diff.st, wt.off); //取下班時間內

            diff.et = Math.max(diff.st, endInt);
            diff.et = Math.min(diff.et, wt.off);
            diff.et = diff.et <= wt.noonOn ? diff.et : (wt.noonOff <= diff.et ? diff.et : wt.noonOn && startInt != wt.off);
            diff.et = Math.max(wt.on, diff.et);

            diff.diff = diff.et - diff.st;
            if (diff.st <= wt.noonOn && wt.noonOff <= diff.et)
            { //去除午休時段
                diff.diff = diff.diff - (wt.noonOff - wt.noonOn);
            }
            diff.h = diff.diff / MS_HOUR;
            //TODO:根據小時數計算天數
            diff.d += getLeaveByHour(diff.h, wt.wh);
        }
    }
    catch (e)
    {
        this.log("計算【" + start + "】到【" + end + "】期間的請假天數發生異常:" + e.message);
    }return diff.d;
};

5.2 請假時間跨越多個日期

計算第一部分的時長:

function getLeaveDaysInTwoDay(start, end, wtObjStr)
{
    /**
     * 獲取start到第二天end時間內的請假時長
     * @start:起始時間
     * @end:截止時間
     * @wtObjStr:作息時間,包含上下班時間和午休時間
     *     {
     *         wh:日工作時長,整型,如8
     *         on:上班時間,字符串,如‘09:00‘
     *         off:下班時間,字符串,如‘18:00‘
     *         noonOn:中午開始時間,字符串,如‘12:00‘
     *         noonOff:中午結束時間,字符串,如‘14:00‘
     * }
     * 值得註意的是,如果未設置作息時間,則上班時間為00:00,下班時間為23:59,中午時間均為下班時間,這個應該在setWorkTime中進行設置
     * */
    var wt = { },
        _date = ‘2019-01-08‘,
        _date2 = ‘2019-01-09‘;
    var start = Date.parse(_date + ‘ ‘ + start.Format(‘hh:mm:ss‘)),
        end = Date.parse(_date2 + ‘ ‘ + end.Format(‘hh:mm:ss‘));
    wt.wh = wtObjStr.wh;
    wt.on = Date.parse(_date + ‘ ‘ + wtObjStr.on);
    wt.off = Date.parse(_date + ‘ ‘ + wtObjStr.off);
    wt.noonOn = Date.parse(_date + ‘ ‘ + wtObjStr.noonOn);
    wt.noonOff = Date.parse(_date + ‘ ‘ + wtObjStr.noonOff);

    wt.on2 = Date.parse(_date2 + ‘ ‘ + wtObjStr.on);
    wt.off2 = Date.parse(_date2 + ‘ ‘ + wtObjStr.off);
    wt.noonOn2 = Date.parse(_date2 + ‘ ‘ + wtObjStr.noonOn);
    wt.noonOff2 = Date.parse(_date2 + ‘ ‘ + wtObjStr.noonOff);

    var diff = 0;
    start = Math.max(start, wt.on);
    start = start <= wt.noonOn ? start : (wt.noonOff < start ? start : wt.noonOff);
    start = Math.min(start, wt.off);

    end = Math.max(end, wt.on2);
    end = end <= wt.noonOn2 ? end : (wt.noonOff2 < end ? end : wt.noonOn2);
    end = Math.min(end, wt.off2);

    diff = wt.off - start;
    if (start <= wt.noonOn) diff -= (wt.noonOff - wt.noonOn);
    diff += (end - wt.on2);
    if (end >= wt.noonOff2) diff -= (wt.noonOff2 - wt.noonOn2);

    return getLeaveByHour(diff / MS_HOUR, wt.wh);
};

再來看第二部分,先籠統計算一下天數:

function getDaysOfPeriod(start, end)
{
    /**
     * 獲取一段時期內的天數,包含起止日期
     * @start:起始時間
     * @end:截止時間
     * */
    try
    {
        var startObj = {
            ‘y‘: start.getFullYear(),
            ‘m‘: start.getMonth() + 1,
            ‘d‘: start.getDate()
        },
        endObj = {
            ‘y‘: end.getFullYear(),
            ‘m‘: end.getMonth() + 1,
            ‘d‘: end.getDate()
        };
        //start和end必須包含,所以需要+1
        var startPart = start.getTotalDaysOfMonth() - startObj.d + 1,
            monthPart = 0,
            endPart = endObj.d;

        if (startObj.y != endObj.y)
        { //跨年的情況
            var startMonths = 12 - startObj.m; //獲取start年份中剩下的月份數
            for (var i = startObj.m + 1; i <= startObj.m + startMonths; i++)
            {
                monthPart += (new Date(startObj.y, i - 1, 1)).getTotalDaysOfMonth();
            }
            for (var i = 1; i <= endObj.m - 1; i++)
            {
                monthPart += (new Date(endObj.y, i - 1, 1)).getTotalDaysOfMonth();
            }
        }
        else
        {
            if (startObj.m != endObj.m)
            { //跨月
                for (var i = startObj.m + 1; i < endObj.m; i++)
                {
                    monthPart += (new Date(startObj.y, i - 1, 1)).getTotalDaysOfMonth();
                }
            }
            else
            {
                startPart = 0;
                endPart = endObj.d - startObj.d + 1;
            }
        }
        this.log("【" + start + "】到【" + end + "】期間的天數:" + (startPart + monthPart + endPart));
        return startPart + monthPart + endPart;
    } catch(e) {
        this.log("計算【" + start + "】到【" + end + "】期間的天數發生異常:" + e.message);
        return 0;
    }
}; 

這個天數除去起止日期即為第二部分。

主函數如下:

function getLeaveDays(start, end)
{
    /**
     * 獲取一段時間內的請假天數,包含上下班時間和午休時間
     * @start:起始時間
     * @end:截止時間
     * */
    var startInt = Date.parse(start),
        endInt = Date.parse(end),
        startObj = {
            ‘y‘: start.getFullYear(),
            ‘m‘: start.getMonth() + 1,
            ‘d‘: start.getDate(),
            ‘h‘: start.getHours(),
            ‘mi‘: start.getMinutes()

        },
        endObj = {
            ‘y‘: end.getFullYear(),
            ‘m‘: end.getMonth() + 1,
            ‘d‘: end.getDate(),
            ‘h‘: end.getHours(),
            ‘mi‘: end.getMinutes()
        };
    var diff = 0,wt = { },
        _date = start.Format(‘yyyy-MM-dd‘);

    wt.wh = this._work.wh;    
    wt.on = Date.parse(_date + ‘ ‘ + this._work.on);    
    wt.off = Date.parse(_date + ‘ ‘ + this._work.off);    
    wt.noonOn = Date.parse(_date + ‘ ‘ + this._work.noonOn);
    wt.noonOff = Date.parse(_date + ‘ ‘ + this._work.noonOff);    
    //請假起止時間不在同一日期
    if(startObj.y !== endObj.y || startObj.m !== endObj.m || startObj.d !== endObj.d) {
        var days = getDaysOfPeriod(start, end);
        /**
         * days包含start和end,days>=2,所以請假時間可以按兩個部分計算:
         * start那天到第二天end時間的請假時長+start和end中間天數
         */
        if (days < 2)
        {
            this.log(‘計算一段時間內(非同一天)的天數不能少於2‘);
            return 0;
        }
        diff += days - 2;
        diff += getLeaveDaysInTwoDay(start, end, this._work);
    } else { //請假起止時間在同一日期內
        diff = getLeaveDayInOneDay(start, end, wt);
    }
    return diff;
};

function getLeaveByHour(hour, workLen)
{
    var diff = 0;
    var dv = Math.floor(hour / workLen);
    if (dv >= 1)
    {
        diff += dv;
        hour -= dv * workLen;
    }
    if (hour >= workLen / 2)
    {
        diff += 0.5;
        hour -= workLen / 2;
    }
    if (hour >= 1)
    {
        diff += parseFloat((hour / workLen).toFixed(1));
    }
    return diff;
};

再貼上測試效果吧:

技術分享圖片技術分享圖片技術分享圖片

技術分享圖片技術分享圖片技術分享圖片

當然,小數點後面的四舍五入的處理就看各自的情況了。

花了點時間整理封裝了下,不知道怎麽上傳附件,有需要源碼的可以留言。

對於請假天數的計算就寫這麽些了,不同場景肯定有不同的需求,以上算法只是拋磚引玉,更多的還需要自行修改,你也可以留言一起學習。

小菜一枚,大神路過請多多指教,誠謝。

轉發請註明出處。

最後編輯時間:2019-01-10

Javascript 計算請假天數