编辑代码


// 加年
function addYear(var1, years) {
     //获取日期格式并创建Date
    var dateComponent = parseDateComponents(var1)
    if( dateComponent == null || dateComponent.format.indexOf("yyyy")===-1) 
        return null; //null:日期格式错误或不支持计算
    dateComponent.date.setFullYear(dateComponent.date.getFullYear() + years)
    //按原格式返回日期
    return recoverDateFormat(dateComponent.date, dateComponent.format); 
}

// 加月
function addMonth(var1,months) {
     //获取日期格式并创建Date
    var  dateComponent = parseDateComponents(var1)
    // 判断格式合法性
    if( dateComponent==null || dateComponent.format.indexOf("MM")===-1) 
        return null;  //null:日期格式错误或不支持计算)
    dateComponent.date.setMonth(dateComponent.date.getMonth() + months)
    // 按原格式返回日期
    return recoverDateFormat(dateComponent.date, dateComponent.format)
}

// 加日
function addDay(var1,days) {
    //获取日期格式并创建Date
    var  dateComponent = parseDateComponents(var1)
    // 合法性判断
    if( dateComponent==null || dateComponent.format.indexOf("dd")===-1) 
        return null;  //null:日期格式错误或不支持计算
    dateComponent.date.setDate(dateComponent.date.getDate() + days)
    // 按原格式返回日期
    return recoverDateFormat(dateComponent.date, dateComponent.format)
}

// 加时
function addHour(var1,hours) {
    if(isNaN(hours)) throw "参数hours必须为数字";
    //获取日期格式并创建Date
    var  dateComponent = parseDateComponents(var1)
    // 合法性判断
    if( dateComponent==null || dateComponent.format.indexOf("HH")===-1) 
        return null;  //null:日期格式错误或不支持计算
    dateComponent.date.setTime(dateComponent.date.getTime() + hours*60*60*1000)
    // 按原格式返回日期
    return recoverDateFormat(dateComponent.date, dateComponent.format)
}

// 加分钟
function addMinutes(var1,minutes) {
    if(isNaN(minutes)) throw "参数minutes必须为数字";
    //获取日期格式并创建Date
    var dateComponent = parseDateComponents(var1)
    // 合法性判断
    if( dateComponent==null || dateComponent.format.indexOf("mm")===-1) 
        return null  //null:日期格式错误或不支持计算
    dateComponent.date.setTime(dateComponent.date.getTime() + minutes*60*1000)
    // 按原格式返回日期
    return recoverDateFormat(dateComponent.date, dateComponent.format)
}

// 加秒
function addSeconds(var1,seconds) {
     if(isNaN(seconds)) throw "参数seconds必须为数字";
    //获取日期格式并创建Date
    var dateComponent = parseDateComponents(var1)
    // 合法性判断
    if(dateComponent==null || dateComponent.format.indexOf("ss")===-1) 
        return null;  //null:日期格式错误或不支持计算
    dateComponent.date.setTime(dateComponent.date.getTime() + seconds*1000)
    // 按原格式返回日期
    return recoverDateFormat(dateComponent.date, dateComponent.format)
}

//  求时间差(年)
function yearSpan(var1, var2) {
    // 获取日期格式并创建Date
    var dateComponent1 = parseDateComponents(var1);
    var dateComponent2 = parseDateComponents(var2);
    // 合法性判断
    if(dateComponent1==null || dateComponent2==null 
        || dateComponent1.format!=dateComponent2.format || dateComponent1.format.indexOf('yyyy')===-1)
        return null;  //null:日期格式不一致或不支持运算

    var date1 = dateComponent1.date
    var date2 = dateComponent2.date
    // date1中放小日期,date2中大日期
    if(date1 > date2) { 
        var temp = date1;
        date1 = date2;
        date2 = temp; 
    }
    var yearDiff = date2.getFullYear() - date1.getFullYear();
    // 设置date1年份为date2年份,考虑年份后的内容,若不完整满一年则需减1
    date1.setFullYear(date2.getFullYear());
    return date2 < date1 ? yearDiff - 1 : yearDiff;
}

// 求时间差(月)
function monthSpan(var1, var2){
    // 获取日期格式并创建Date
    var dateComponent1 = parseDateComponents(var1);
    var dateComponent2 = parseDateComponents(var2);
    if(dateComponent1==null || dateComponent2==null 
        || dateComponent1.format!=dateComponent2.format || dateComponent1.format.indexOf('MM')===-1)
        return null;  //null:日期格式不一致或不支持运算

    var date1 = dateComponent1.date;
    var date2 = dateComponent2.date;
    if(date1 > date2) { 
        var temp = date1;
        date1 = date2;
        date2 = temp; 
    }
    // 计算基础月份差(不考虑日和时间)
    var monthDiff = (date2.getFullYear() - date1.getFullYear()) * 12 
                + (date2.getMonth() - date1.getMonth());

    // 考虑月份后的内容,若调整后date1晚于实际date2,说明未满完整月份
    date1.setMonth(date1.getMonth() + monthDiff)
    return date2 < date1 ? --monthDiff : monthDiff;
}daySpan

// 求时间差(天)
function daySpan(var1, var2){
    // 获取日期格式并创建Date
    var dateComponent1 = parseDateComponents(var1);
    var dateComponent2 = parseDateComponents(var2);
    //判断格式合法性和一致性
    if(dateComponent1==null || dateComponent2==null 
        || dateComponent1.format!=dateComponent2.format || dateComponent1.format.indexOf('dd')===-1)
        return null;  //null:日期格式不一致或不支持运算

    var date1 = dateComponent1.date;
    var date2 = dateComponent2.date;
    if(date1 > date2) { 
        var temp = date1;
        date1 = date2;
        date2 = temp; 
    }
    return Math.floor((date2 - date1)/(1000*60*60*24));
}

// 求时间差(分钟)
function minuteSpan(var1, var2){
    // 获取日期格式并创建Date
    var dateComponent1 = parseDateComponents(var1);
    var dateComponent2 = parseDateComponents(var2);
    //判断格式合法性和一致性
    if(dateComponent1==null || dateComponent2==null 
        || dateComponent1.format!=dateComponent2.format || dateComponent1.format.indexOf('mm')===-1)
        return null;  //null:日期格式不一致或不支持运算

    var date1 = dateComponent1.date;
    var date2 = dateComponent2.date;
    if(date1 > date2) { 
        var temp = date1;
        date1 = date2;
        date2 = temp; 
    }
    return Math.floor((date2 - date1)/(1000*60));
}

// 比较日期时间大小
function compareTime(var1, var2) {
    var validFormat = [
        "yyyy-MM-dd HH:mm:ss",
        "yyyy-MM-dd HH:mm",
        "yyyy-MM-dd HH",
        "yyyy-MM-dd",
        "yyyy-MM",
        "yyyy",
        "HH:mm:ss",
        "HH:mm"
    ];
    if( emptyVar(var1) && emptyVar(var2) ) return 0;
    if( emptyVar(var1) || emptyVar(var2) ) throw "某个日期为空";
    // 获取日期格式并创建Date
    var dateComponent1 = parseDateComponents(var1);
    var dateComponent2 = parseDateComponents(var2);
    // 格式合法性判断
    if(validFormat.indexOf(dateComponent1.format)===-1 || validFormat.indexOf(dateComponent2.format)===-1)
        throw "不支持的格式";
    
    var date1 = dateComponent1.date;
    var date2 = dateComponent2.date;
    //获取短格式
    var shortFormat = getShortFormat(dateComponent1.format, dateComponent2.format);

    if(dateComponent1.format == dateComponent2.format){
        // 按指定格式比较日期大小
        return equalFormatCompare(date1, date2, dateComponent1.format)
    }else if(shortFormat != null){
        var result = equalFormatCompare(date1, date2, shortFormat);
        if(result != 0) 
            return result;
        else 
            throw "格式不一致时,不可得出相等";
    }else{
        throw "不可比较";
    }
}

// 截取日期时间
function formatDate(var1, format) {
    // 支持的格式
    var isValidFormats = [
        'yyyy',
        'yyyy-MM',
        'yyyy-MM-dd',
        'dd-MMM-yyyy',
        'yyyy-MM-dd HH',
        'dd-MMM-yyyy HH',
        'yyyy-MM-dd HH:mm',
        'dd-MMM-yyyy HH:mm',
        'HH:mm',
        'HH:mm:ss'
    ];
     //获取日期格式并创建Date
    var dateComponent = parseDateComponents(var1);
    // 合法性判断
    if(dateComponent==null || isValidFormats.indexOf(format)===-1 || dateComponent.format.indexOf(format)===-1)
        return null;    //不支持的格式或中英文格式不对应

    return recoverDateFormat(dateComponent.date, format)
}

// 对不同格式的日期进行解析,返回格式和创建的Date
function parseDateComponents(dateStr) {
    var monthNames =  ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
    var dateComponents = {year: null, month: 0, day: 1, hour: 0, minute: 0, second: 0}
    //可能的日期格式
    var patterns = [
        { regex: /^(\d{4})$/, format: "yyyy" },
        { regex: /^(\d{4})-(\d{2})$/, format: "yyyy-MM" },
        { regex: /^(\d{4})-(\d{2})-(\d{2})$/, format: "yyyy-MM-dd" },
        { regex: /^(\d{4})-(\d{2})-(\d{2}) (\d{2})$/, format: "yyyy-MM-dd HH" },
        { regex: /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2})$/, format: "yyyy-MM-dd HH:mm" },
        { regex: /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/, format: "yyyy-MM-dd HH:mm:ss" },
        { regex: /^(\d{2}):(\d{2}):(\d{2})$/, format: "HH:mm:ss" },
        { regex: /^(\d{2}):(\d{2})$/, format: "HH:mm" },
        { regex: /^(\d{2})$/, format: "HH" },
        { regex: /^(\d{2})-(\d{4})$/, format: "MM-yyyy" },
        { regex: /^(\d{2})-(\d{2})-(\d{4})$/, format: "MM-dd-yyyy" },
        { regex: /^(\d{2})-(\d{2})-(\d{4}) (\d{2})$/, format: "MM-dd-yyyy HH" },
        { regex: /^(\d{2})-(\d{2})-(\d{4}) (\d{2}):(\d{2})$/, format: "MM-dd-yyyy HH:mm" },
        { regex: /^(\d{2})-(\d{2})-(\d{4}) (\d{2}):(\d{2}):(\d{2})$/, format: "MM-dd-yyyy HH:mm:ss" },

        { regex: /^(\d{2})-([A-Za-z]{3})-(\d{4})$/, format: "dd-MMM-yyyy" },
        { regex: /^(\d{2})-([A-Za-z]{3})-(\d{4}) (\d{2})$/, format: "dd-MMM-yyyy HH" },
        { regex: /^(\d{2})-([A-Za-z]{3})-(\d{4}) (\d{2}):(\d{2})$/, format: "dd-MMM-yyyy HH:mm" },
        { regex: /^(\d{2})-([A-Za-z]{3})-(\d{4}) (\d{2}):(\d{2}):(\d{2})$/, format: "dd-MMM-yyyy HH:mm:ss" },
        { regex: /^([A-Za-z]{3})-(\d{4})$/, format: "MMM-yyyy" },
        { regex: /^([A-Za-z]{3})-(\d{2})-(\d{4})$/, format: "MMM-dd-yyyy" },
        { regex: /^([A-Za-z]{3})-(\d{2})-(\d{4}) (\d{2})$/, format: "MMM-dd-yyyy HH" },
        { regex: /^([A-Za-z]{3})-(\d{2})-(\d{4}) (\d{2}):(\d{2})$/, format: "MMM-dd-yyyy HH:mm" },
        { regex: /^([A-Za-z]{3})-(\d{2})-(\d{4}) (\d{2}):(\d{2}):(\d{2})$/, format: "MMM-dd-yyyy HH:mm:ss" },
        { regex: /^(\d{4})-([A-Za-z]{3})$/, format: "yyyy-MMM" },
        { regex: /^(\d{4})-([A-Za-z]{3})-(\d{2})$/, format: "yyyy-MMM-dd" },
        { regex: /^(\d{4})-([A-Za-z]{3})-(\d{2}) (\d{2})$/, format: "yyyy-MMM-dd HH" },
        { regex: /^(\d{4})-([A-Za-z]{3})-(\d{2}) (\d{2}):(\d{2})$/, format: "yyyy-MMM-dd HH:mm" },
        { regex: /^(\d{4})-([A-Za-z]{3})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/, format: "yyyy-MMM-dd HH:mm:ss" },    
    ];

    for (var i = 0; i < patterns.length; i++){
        var pattern = patterns[i];
        var match = dateStr.match(pattern.regex);
        if(match) {
            var parts = pattern.format.split(/[- :]/);
            if(parts.indexOf('yyyy') !== -1)
                dateComponents.year = +match[parts.indexOf('yyyy')+1];
            if(parts.indexOf('MMM') !== -1){
                var monthEngName = match[parts.indexOf('MMM')+1]
                dateComponents.month = monthNames.indexOf(monthEngName);
            }
            if(parts.indexOf('MM') !== -1)
                dateComponents.month = +match[parts.indexOf('MM')+1] -1;
            if(parts.indexOf('dd') !== -1)
                dateComponents.day = +match[parts.indexOf('dd')+1];
            if(parts.indexOf('HH') !== -1)
                dateComponents.hour = +match[parts.indexOf('HH')+1];
            if(parts.indexOf('mm') !== -1)
                dateComponents.minute = +match[parts.indexOf('mm')+1];
            if(parts.indexOf('ss') !== -1)
                dateComponents.second = +match[parts.indexOf('ss')+1];

            var date = new Date(dateComponents.year, dateComponents.month, dateComponents.day,
                                dateComponents.hour, dateComponents.minute, dateComponents.second)
            return {format:pattern.format, date:date}; 
        }
    }
    return null;
}

// 格式转化
function recoverDateFormat(date, formatString) {
    var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
    var pad = function(n) {
        return n < 10 ? '0' + n : n.toString();
    };
    var year = date.getFullYear();
    var month = date.getMonth();
    var day = date.getDate();
    var hours = date.getHours();
    var minutes = date.getMinutes();
    var seconds = date.getSeconds();
    var monthStr = months[month];
    var replacements = {
        'yyyy': year,
        'MMM': monthStr,
        'MM': pad(month + 1),
        'dd': pad(day),
        'HH': pad(hours),
        'mm': pad(minutes),
        'ss': pad(seconds)
    };
    var result = formatString;
    // 替换顺序需要考虑长的部分先替换
    result = result.replace(/yyyy/g, replacements['yyyy']);
    result = result.replace(/MMM/g, replacements['MMM']);
    result = result.replace(/MM/g, replacements['MM']);
    result = result.replace(/dd/g, replacements['dd']);
    result = result.replace(/HH/g, replacements['HH']);
    result = result.replace(/mm/g, replacements['mm']);
    result = result.replace(/ss/g, replacements['ss']);
    return result;
}

// 判断日期时间是否为空
function emptyVar(value) {
    return (
        value == null || // null 或 undefined
        (typeof value === "string" && value.trim() === "")  // 空字符串
    );
}

// 获取短格式
function getShortFormat(format1, format2){
    if(format1.indexOf(format2)!==-1)
        return format2;
    else if(format2.indexOf(format1)!==-1)
        return format1;
    else
        return null;
}
// 工具:比较指定格式部分的日期大小
function equalFormatCompare(date1, date2, formatStr){
    // 标准化日期为需要的部分
    var normalizeDate = function(date, formatStr){
        var year = formatStr.indexOf('yyyy') !== -1 ? date.getFullYear() : undefined;
        var month = formatStr.indexOf('MM') !== -1 ? date.getMonth() : undefined;
        var day = formatStr.indexOf('dd') !== -1 ? date.getDate() : undefined;
        var hour = formatStr.indexOf('HH') !== -1 ? date.getHours() : undefined;
        var minute = formatStr.indexOf('mm') !== -1 ? date.getMinutes() : undefined;
        var second = formatStr.indexOf('ss') !== -1 ? date.getSeconds() : undefined;

        return new Date(year||1970, month||0, day||1, hour||0, minute||0, second||0);
    }
    var normalizeDate1 = normalizeDate(date1, formatStr);
    var normalizeDate2 = normalizeDate(date2, formatStr);
    if(normalizeDate1 < normalizeDate2 ) 
        return 1;
    else if(normalizeDate1 > normalizeDate2) 
        return -1;
    else 
        return 0;
}
// 示例:
console.log(addYear('2024-04-01 20:30:21', 1)); //2025-04-01 20:30:21
console.log(addYear('20-Dec-2024', 1)); //20-Dec-2025
console.log(addYear('2024 20:30:21', 1)); //null(日期格式错误或不支持计算)
console.log(addMonth('20-Dec-2024 00:00:00',2)); //20-Feb-2025 00:00:00
console.log(addMonth('2024 00:00:00',2)); //null(日期格式错误或不支持计算)
console.log(addDay('2024-02-20 00:00:00',12)); //2024-03-03 00:00:00
console.log(addDay('01-Oct-2021 00:00:10',12)); //13-Oct-2021 00:00:10
console.log(addDay('2024-02',11)); //null (日期格式错误或不支持计算)
console.log(addHour('2024-02-01 20:40:00',2)); //2024-02-01 22:40:00
console.log(addHour('2024-02-01 20:40:00',1.2)); //2024-02-01 21:52:00
console.log(addHour('01-Dec-2025 20:40:00',2)); //01-Dec-2025 22:40:00
console.log(addHour('20:40:00',5.5)); //02:10:00
console.log(addHour('2025 20:40:00',2)); //null (日期格式错误或不支持计算)
console.log(addMinutes('2024-02-29 23:40:00','37')); //2024-03-01 00:17:00
console.log(addMinutes('20:40:00',5.5)); //20:45:30
console.log(addMinutes('2024 23:40:00',20.5)); //null (日期格式错误或不支持计算)
console.log(addSeconds('2024-01-17 23:40:00',20)); //2024-01-17 23:40:20
console.log(addSeconds('2024 23:40:00',20)); //null (日期格式错误或不支持计算)

console.log(yearSpan('2024-01-17 01:00:00','2025-01-17 01:02:20')); //1
console.log(yearSpan('28-Oct-2024 01:02:20','01-Dec-2025 01:00:00')); //1
console.log(yearSpan('01:00:00','01:02:20')); //null(日期格式不一致或不支持运算)
console.log(monthSpan('2024-01-29','2025-01-28')); //11
console.log(monthSpan('Oct-2024','Dec-2024')); //2
console.log(monthSpan('2025-28 09:00:00','2020-01 00:00:00')); //null(日期格式不一致或不支持运算)
console.log(daySpan('2025-02-28','2025-06-01')); //93
console.log(daySpan('01-Oct-2025','01-Dec-2025')); //61
console.log(daySpan('2025-02','2025-06')); //null(日期格式不一致或不支持运算)
console.log(minuteSpan('2025-02-28 10:00:01','2025-02-28 20:00:00')); //599
console.log(minuteSpan('01-Dec-2024 20:00:00','01-Dec-2024 20:10:12')); //10
console.log(minuteSpan('2025-02-28 20','2025-02-28 10')); //null(日期格式不一致或不支持运算)

console.log(compareTime('2025-02-28 20:00:00','2025-02-28 20:00:00')); // 0
console.log(compareTime('2025-05-01 20:00:00','2025-02-28 20:00:00')); // -1
console.log(compareTime('2025-01-28 20:00:00','2025-03-28')); // 1

console.log(formatDate("2024-02-01 20:00:00", "yyyy-MM-dd HH:mm")); // 2024-02-01 20:00
console.log(formatDate("01-Dec-2024 20:00:00", "dd-MMM-yyyy")); // 01-Dec-2024
console.log(formatDate("2024-02-01 20:00:00", "HH:mm:ss")); // 20:00:00
console.log(formatDate("2024-02-01 20:00:00", "dd-MMM-yyyy HH:mm")); // null(不支持的格式或中英文格式不对应)