1. 计时器(有requireJs时define,否则加入window或global)
(()=>{
    "use strict";
    const frozenErrStr = "Frozen object is not supported for this function!";
    const frozenErrFn = function(){console.error(frozenErrStr);};

    /**返回冻结的计时器时间对象*/
    const frozenTimerObjFn = function(timerObj){
        return new Proxy(timerObj,{
            set: function(obj, prop, value){
                frozenErrFn();
                return false;
            },
            deleteProperty: function(target, property){
                frozenErrFn();
                return false;
            },
            defineProperty: function(target, prop, descriptor){
                frozenErrFn();
                return false;
            },
            setPrototypeOf: function(target, prototype) {
                frozenErrFn();
                return false;
            },
            preventExtensions(target) {
                frozenErrFn();
                return false;
            },
        });
    }

    /**
     * 秒数转天时分秒
     * @param timeObj 计时对象
     * @param timeSec 时间间隔(秒)
     * @returns timerObj ==>> {day,hour,min,sec}
     */
    const diffTime = (timeObj,timeSec)=>{
        //一分钟内
        if(timeSec<=59){
            timeObj.day=0;
            timeObj.hour=0;
            timeObj.min=0;
            timeObj.sec=timeSec;
        }
        //一小时内
        else if(timeSec<=3599){
            timeObj.day=0;
            timeObj.hour=0;
            const min=Math.floor(timeSec/60);
            timeObj.min=min;
            timeObj.sec=timeSec%60;
        }
        //一天内
        else if(timeSec<=86399){
            timeObj.day=0;
            const min=Math.floor(timeSec/60);
            timeObj.sec=timeSec%60;
            timeObj.hour=Math.floor(min/60);
            timeObj.min=min%60;
        }
        //一天及以上
        else{
            const min=Math.floor(timeSec/60);
            timeObj.sec=timeSec%60;
            const hour=Math.floor(min/60);
            timeObj.min=min%60;
            const day=Math.floor(hour/24);
            timeObj.hour=hour%24;
            timeObj.day=day;
        }

        // const timeMin = timeSec <= 59 ? 0 : Math.floor(timeSec/60);
        // const timeHour = timeSec <= 3599 ? 0 : Math.floor(timeMin/60);
        // const timeDay = timeSec <= 86399 ? 0 : Math.floor(timeHour/24);

        // timeObj.sec=timeSec%60;
        // timeObj.min=timeMin%60;
        // timeObj.hour=timeHour%24;
        // timeObj.day=timeDay;
    };

    const newTimerObj = function(){
        return {startTime:new Date().getTime(),stopTime:null,day:0,hour:0,min:0,sec:0,interval:null};
    }

    const timerObj2Str = timerObj=>{
        const zero = "0";
        return (timerObj.day>=1 ? (timerObj.day+" ").padStart(3,zero) : "") +
            (timerObj.hour+":").padStart(3,zero) +
            (timerObj.min+":").padStart(3,zero) +
            (timerObj.sec+"").padStart(2,zero);
    };

    const simpleTimeFormat = date=>{
        if(!date)return "";
        const zero = "0";
        return (date.getHours()+":").padStart(3,zero) + (date.getMinutes()+":").padStart(3,zero) + (date.getSeconds()+"").padStart(2,zero);
    };

    const simpleDateTimeFormat = date=>{
        if(!date)return "";
        const zero = "0";
        return simpleTimeFormat(date) + " " + (date.getMonth()+1+"-").padStart(3,zero) + (date.getDate()+" ").padStart(3,zero) + (date.getFullYear()+"").padStart(2,zero);
    }

    /**
     * 简单但功能完善的计时器,
     * 默认创建后自动开始计时,start(date)开始计时,stop()停止计时,reset(date)复位,restart()重新计时,getTimeObj(obj)获取计时对象
     * @param callback 计时时的回调函数 function(timeObj){-每秒想做的事-} timeObj为字符串或{day,hour,min,sec,startTime,stopTime},默认控制台打印格式化时间字符
     * @param this4cb 回调函数内想要指向的this,默认为调用者
     * @param ifObjPara4cb 为空则回调函数的参数为格式化时间字符串,不为空则为冻结对象{day,hour,min,sec}
     * @param extraFixSec 额外的修正频率(大于1小于31),为空不额外再修正,不为空时,sec%extraFixSec==0时修正
     * @param notStartOnCreate 为true则创建时不开始计时
     * @param inTimerObj 如果传入对象,则获取一个完全可控的timerObj
     */
    function simpleTimer(callback,this4cb,ifObjPara4cb,extraFixSec,notStartOnCreate,inTimerObj){
        if(this4cb == null || typeof this4cb != 'object'){
            this4cb = this;
        }
        if(inTimerObj!=null && typeof inTimerObj != "object"){
            inTimerObj = {};
        }

        //计时对象
        const timerObj = inTimerObj?Object.assign(inTimerObj,newTimerObj()):newTimerObj();

        //冻结的计时对象代理
        const frozenTimerObj = inTimerObj?timerObj:frozenTimerObjFn(timerObj);

        //重设回调函数
        timerObj.setCallback = (newCb,newThis4cb,newifObjPara4cb)=>{
            if(newCb == null || typeof newCb != 'function'){
                if(callback == null || typeof callback != 'function'){
                    this4cb = null;
                    ifObjPara4cb = null;
                    callback = timeStr => console.log(timeStr);
                }else{
                    console.error("typeof newCb must be function!");
                    return false;
                }
            }else{
                callback = newCb.bind(this4cb);
            }

            if(typeof newThis4cb != 'object'){
                console.warn("typeof newThis4cb must be object!");
            }else{
                this4cb = newThis4cb;
            }

            if(newifObjPara4cb){
                ifObjPara4cb = true;
            }else{
                ifObjPara4cb = false;
            }

            return true;
        };
        timerObj.setCallback(callback,this4cb,ifObjPara4cb);

        /**开始到当前时间差,并更新timerObj*/
        timerObj.diffTimerObj=()=>{
            diffTime(timerObj,Math.floor((new Date().getTime()-timerObj.startTime)/1000));
        };

        /**每当sec到60时修正一次,并在此计时进位,extraFixSec时额外修正*/
        let ifDiff = null;
        //设置额外的时间间隔
        timerObj.setExtraFixSec = (extraFixSec)=>{
            if(typeof extraFixSec != "number" || extraFixSec<=1 || extraFixSec>=31){
                extraFixSec = null;
            }
            ifDiff = extraFixSec != null ? ()=>(++timerObj.sec>=60 || (extraFixSec != null && timerObj.sec%extraFixSec == 0)) : ()=>(++timerObj.sec>=60);
            return true;
        };
        timerObj.setExtraFixSec(extraFixSec);

        //开始计时
        timerObj.start = function(date){
            if(this.interval!=null){
                clearInterval(this.interval);
            }
            if(date){
                this.startTime = date.getTime();
            }
            if(this.startTime == null){
                this.startTime = new Date().getTime();
            }
            this.stopTime = null;
            this.diffTimerObj();
            if(ifObjPara4cb){
                callback(frozenTimerObj);
            }
            else{
                callback(timerObj2Str(timerObj));
            }
            //每秒计时一次
            this.interval = setInterval(()=>{
                if(ifDiff()){
                    timerObj.diffTimerObj();
                }
                if(ifObjPara4cb){
                    callback(frozenTimerObj);
                }
                else{
                    callback(timerObj2Str(timerObj));
                }
            },1000);

        }.bind(timerObj);

        //停止计时
        timerObj.stop = ()=>{
            clearInterval(timerObj.interval);
            timerObj.stopTime = new Date().getTime();
        };

        //复位
        timerObj.reset = (date)=>{
            timerObj.start(date||new Date());
        };

        //重新计时
        timerObj.restart = ()=>{
            if(timerObj.stopTime!=null && timerObj.startTime!=null){
                //停止时长
                const time = new Date().getTime() - timerObj.stopTime;
                timerObj.startTime=new Date(timerObj.startTime+time).getTime();
                timerObj.start();
            }else{
                timerObj.start(new Date(timerObj.startTime));
            }
        };

        //获取计时对象,当参数不为空且为对象时,将值写入该对象,否则返回frozenTimerObj
        timerObj.getTimeObj = (obj)=>{
            if(obj!=null && typeof obj=="object"){
                obj.day = frozenTimerObj.day;
                obj.hour = frozenTimerObj.hour;
                obj.min = frozenTimerObj.min;
                obj.sec = frozenTimerObj.sec;
                obj.startTime = frozenTimerObj.startTime;
                obj.stopTime = frozenTimerObj.stopTime;
            }else{
                obj = frozenTimerObj;
            }
            return obj;
        };

        //获取总秒数
        timerObj.getSeconds = ()=>{
            return timerObj.sec + timerObj.min*60 + timerObj.hour*3600 + timerObj.day*86400;
        }

        if(!notStartOnCreate){
            //直接开始计时
            timerObj.start();
        }

        return frozenTimerObj;
    }

    const retObj = Object.freeze({new:simpleTimer,frozenTimerObjFn,diffTime,newTimerObj,timerObj2Str,simpleTimeFormat,simpleDateTimeFormat});
    let defineOk = false;
    if(typeof define === 'function')
        try {
            define(retObj);
            defineOk = true;
        } catch (error) {}
    if(!defineOk){
        if(typeof window === 'object')
            window.simpleTimer = retObj;
        else if(typeof global == 'object')
            global.simpleTimer = retObj;
    }
    window.simpleTimer = retObj;
})();
  1. 测试
//无requireJs
var myTimer = simpleTimer.new();
//有requireJs
define(['./simpleTimer'], function (simpleTimer){
    simpleTimer.new();
});
  1. 单独的秒数转天时分秒
/**
 * 秒数转天时分秒格式
 * @param timer 为对象时表示{day,hour,min,sec},为数字或字符串时表示秒数
 * @returns DD HH:MM:SS
 */
function sec2time(timer){
    if(timer==null) return null;
    let timerObj = null;
    if(typeof timer == "object"){
        timerObj = timer;
    }else{
        const timeSec = Number(timer);
        if(timeSec<0 || timeSec==NaN) return null;
        timerObj = {};

        const timeMin = timeSec <= 59 ? 0 : Math.floor(timeSec/60);
        const timeHour = timeSec <= 3599 ? 0 : Math.floor(timeMin/60);
        const timeDay = timeSec <= 86399 ? 0 : Math.floor(timeHour/24);

        timerObj.sec=timeSec%60;
        timerObj.min=timeMin%60;
        timerObj.hour=timeHour%24;
        timerObj.day=timeDay;
    }

    const zero = "0";
    const timeStr = (timerObj.day>=1 ? (timerObj.day+" ").padStart(3,zero) : "") +
        (timerObj.hour+":").padStart(3,zero) +
        (timerObj.min+":").padStart(3,zero) +
        (timerObj.sec+"").padStart(2,zero);
    return timeStr;
}
03-08 22:39