阅读 799

js 分享倒计时计算方法

背景

项目中需要做一个倒计时的功能,可以根据选择的日期,算出距离今天的时间差。倒计时有多种模板,大致分为年月日、年月日时分秒以及单独的日。一开始也是在网上大致找了几种方法,但要么和项目要求不匹配,要么计算结果不准确,就自己写一个吧,本文记录分享一下。

实现

计算条件

年和月的差值计算是比较日期。举个例子:比如从2月1号0时0分0秒到3月1号0时0分0秒计为相差1个月,不管当年是闰年还是非闰年,即不管2月实际有多少天。不满1个月(计算时分秒)算0个月。年份同理。

两种方法

引用moment.js库实现

moment.js是时间处理常用的js库,这里使用了它的diff和subtract方法,大大简化了工作量。通过和原生方法对比就可看出。

        /**
            * 基于moment.js 实现的倒计时计算
            * @param endTime {String,Date} - 倒计时结束时间
            * @param maxUnit {String} - [maxUnit = "year"] 最大单位
            * @param startTime {String,Date} - 倒计时开始时间,默认为当前时刻
            * @return {Object}  - 计算完成后返回的年月日时分秒数值
         */
        function countDownTime(endTime, maxUnit = "year", startTime) {
            let aUnitArr = ["year", "month", "day", "hour", "minute", "second"]
            let iMaxIndex = aUnitArr.indexOf(maxUnit);
            let end = moment(endTime);
            let start = moment(startTime);
            let result = {}
            if (start - end > 0) {
                throw new Error("开始时间不能晚于结束时间")
            }
            //过滤掉大于最大单位的单位
            aUnitArr = aUnitArr.filter((item, index) => index >= iMaxIndex)
            result[maxUnit] = end.diff(start, maxUnit);
            if (aUnitArr.length > 1) {
                aUnitArr.reduce((previous, current) => {
                    // 结束时间不断减去高位单位时间
                    end = end.subtract(result[previous], previous);
                    result[current] = end.diff(start, current);
                    return current
                });
            }
            return result
        };
复制代码

原生js实现

        function countDownTime2(endTime, maxUnit = "year", startTime) {
            let end = new Date(endTime);
            let start = startTime ? new Date(startTime) : new Date();
            if (start - end > 0) {
                throw new Error("开始时间不能晚于结束时间")
            }
            let aUnitArr = [
                {
                    value: "second",
                    interval: 60,
                    secNum: 1 //该单位有多少秒,计算该单位最大差值用到
                },
                {
                    value: "minute",
                    interval: 60,
                    secNum: 60
                },
                {
                    value: "hour",
                    interval: 24,
                    secNum: 60 * 60
                },
                {
                    value: "day",
                    secNum: 60 * 60 * 24
                },
                {
                    value: "month",
                    interval: 12
                },
                {
                    value: "year",
                },
            ]
            let endList = getTimeList(end);
            let startList = getTimeList(start);
            const iMaxIndex = aUnitArr.findIndex(item => maxUnit === item.value);
            // 当最大单位为日时分秒时过滤。月份最大单位需根据年份反算所以不能过滤掉年份
            if (iMaxIndex > -1 && iMaxIndex < 4) {
                aUnitArr = aUnitArr.filter((item, index) => index <= iMaxIndex);
            }
            let result = {};
            aUnitArr.forEach((item, index) => {
                if (index === iMaxIndex && iMaxIndex < 4) {
                    result[item.value] = Math.floor((end - start) / item.secNum / 1000);
                    return
                }
                if (endList[index] - startList[index] >= 0) {
                    result[item.value] = endList[index] - startList[index];
                } else {
                    endList[index + 1]--;
                    result[item.value] = item.value === "day" ? 
                    	countDiffDays(start, startList[index], endList[index]) : endList[index] + item.interval - startList[index];
                }
            })
            // 最大单位是月份时特殊处理
            if (maxUnit === "month") {
                result.month += result.year * 12
                delete result.year
            }
            return result;
        }
        function getTimeList(t) {
            return [t.getSeconds(), t.getMinutes(), t.getHours(), t.getDate(), t.getMonth() + 1, t.getFullYear()];
        }
        // 计算日期差值。开始时间本月剩余天数+结束时间当月日期数
        function countDiffDays(time, startDay, endDay) {
            let curDate = new Date(time);
            let curMonth = curDate.getMonth();
            /* 这里将时间设置为下个月之前,需要把日期设置小一点,否则极端情况,如果当天日期大于下一个月的总天数,月份会设置为下下个月 */
            curDate.setDate(1)
            curDate.setMonth(curMonth + 1);
            curDate.setDate(0);//日期设置为前一个月的最后一天
            let restDays = curDate.getDate() - startDay;
            return restDays + endDay;
        };
复制代码

结语

原生js写得比较麻烦,暂时没有特别好的思路优化。如果大家有发现错误或者更好的思路,欢迎指正。

文章分类
前端
文章标签