Javascript 计算请假天数

摘要:
简单分析:1、如果休假期间在同一天内,直接计算;2.如果休假时间超过一天,我们可以将休假时间分为两部分。从开始到结束的休假时间可以视为第一部分:从第二天开始到结束,第二部分:开始日期和结束日期之间的天数=wt.off);diff.et=数学。最大值;diff.diff=差异-差异。st;如果{//删除午休diff.diff=diff.diff-;}diff.h=差异。差异/MS_小时;//TODO:根据小时差异计算天数。d+=getLeaveByHour;}}捕获{this.log;}返回差异。d、 };5.2休假时间跨越多个日期,以计算第一部分的长度:函数

转载请注明本文地址: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;
};

再贴上测试效果吧:

Javascript 计算请假天数第1张Javascript 计算请假天数第2张Javascript 计算请假天数第3张

Javascript 计算请假天数第4张Javascript 计算请假天数第5张Javascript 计算请假天数第6张

 当然,小数点后面的四舍五入的处理就看各自的情况了。

花了点时间整理封装了下,不知道怎么上传附件,有需要源码的可以留言。

对于请假天数的计算就写这么些了,不同场景肯定有不同的需求,以上算法只是抛砖引玉,更多的还需要自行修改,你也可以留言一起学习。

小菜一枚,大神路过请多多指教,诚谢。

转发请注明出处。

最后编辑时间:2019-01-10

免责声明:文章转载自《Javascript 计算请假天数》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇koa2-cors应答跨域请求实现Swiper 用法下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

数据可视化之DAX篇(一)Power BI时间智能函数如何处理2月29日的?

https://zhuanlan.zhihu.com/p/109964336 ​今年是闰年,有星友问我,在Power BI中,2月29日的上年同期是怎么计算的? 这是个好问题,正好梳理一下,PowerBI时间智能函数是如何处理不规则日期的对比数据的。 以一个模拟的订单表数据为例,订单日期涵盖了2015年、2016年和2017年,其中2016年是闰年,添加一...

php编程 之 php进阶练习

1,php的date相关操作: PHP date() 函数可把时间戳格式化为可读性更好的日期和时间。 <?php echo date("Y/m/d") . "<br>"; //返回2016/10/21 echo date("Y.m.d") . "<br>"; //返回2016.10.21 echo date("Y-m-...

pytest框架+allure2框架的基本使用(2019-09-03更新)

前提准备: pip安装allure-pytest、pytest和allure-python-commons包,安装过程如下图: pip install allure-pytest pip install pytest pip install allure-python-commons 安装成功如下: allure --version 2.12.1 py...

移动端-手机端-日历选择控件(支持Zepto和JQuery)

一. 效果图 二. 功能说明   1. 支持切换年份,月份。   2. 支持点击选中日期,也可以点击确定选择日期。 三. 使用方法   1. 添加Input   在你的页面中添加Input输入框。可以再html里,也可以JS动态加载。   我这里使用的时Input-group形式的输入框,是JS加载的。   一般使用的话,直接写个input输入框就行。...

LocalDate,LocalDateTime计算两个时间的相差时间

LcoalDateTime LocalDateTime now = LocalDateTime.now(); LocalDateTime end = LocalDateTime.now(); Duration duration = Duration.between(now,end); //相差的天数 long days = duration.toDay...

Delphi与各数据库数据类型比较

Delphi数据类型与各数据库数据类型对比如下表,如有具体说明见表中脚注: DelphiType OracleTypes SQLServerTypes MySQLTypes[1] InterBaseTypes PostgreSQLTypes SQLiteTypes ftSmallint NUMBER(p,0)[2](p<5) SMALLINT...