javascript Date類的擴展

摘要:javascript Date類的擴展

https://npmjs.org/package/date-utils

(function () {
    var monthsAbbr = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
    var monthsFull = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
    var daysAbbr = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
    var daysFull = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
    var dayNames = {
        su: 0,
        sun: 0,
        sunday: 0,
        mo: 1,
        mon: 1,
        monday: 1,
        tu: 2,
        tue: 2,
        tuesday: 2,
        we: 3,
        wed: 3,
        wednesday: 3,
        th: 4,
        thu: 4,
        thursday: 4,
        fr: 5,
        fri: 5,
        friday: 5,
        sa: 6,
        sat: 6,
        saturday: 6
    };
    var monthsAll = monthsFull.concat(monthsAbbr);
    var daysAll = ["su", "sun", "sunday", "mo", "mon", "monday", "tu", "tue", "tuesday", "we", "wed", "wednesday", "th", "thu", "thursday", "fr", "fri", "friday", "sa", "sat", "saturday"];
    var monthNames = {
        jan: 0,
        january: 0,
        feb: 1,
        february: 1,
        mar: 2,
        march: 2,
        apr: 3,
        april: 3,
        may: 4,
        jun: 5,
        june: 5,
        jul: 6,
        july: 6,
        aug: 7,
        august: 7,
        sep: 8,
        september: 8,
        oct: 9,
        october: 9,
        nov: 10,
        november: 10,
        dec: 11,
        december: 11
    };
    var daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

    function pad(str, length) {
        str = String(str);
        while (str.length < length) {
            str = "0" + str
        }
        return str
    }
    var isInteger = function (str) {
        if (str.match(/^(\d+)$/)) {
            return true
        }
        return false
    };
    var getInt = function (str, i, minlength, maxlength) {
        for (var x = maxlength; x >= minlength; x--) {
            var token = str.substring(i, i + x);
            if (token.length < minlength) {
                return null
            }
            if (isInteger(token)) {
                return token
            }
        }
        return null
    };
    var origParse = Date.parse;
    var getDateFromFormat = function (val, format) {
        val = val + "";
        format = format + "";
        var iVal = 0;
        var iFormat = 0;
        var c = "";
        var token = "";
        var token2 = "";
        var x, y;
        var now = new Date;
        var year = now.getYear();
        var month = now.getMonth() + 1;
        var date = 1;
        var hh = 0;
        var mm = 0;
        var ss = 0;
        var ampm = "";
        while (iFormat < format.length) {
            c = format.charAt(iFormat);
            token = "";
            while (format.charAt(iFormat) === c && iFormat < format.length) {
                token += format.charAt(iFormat++)
            }
            if (token === "yyyy" || token === "yy" || token === "y") {
                if (token === "yyyy") {
                    x = 4;
                    y = 4
                }
                if (token === "yy") {
                    x = 2;
                    y = 2
                }
                if (token === "y") {
                    x = 2;
                    y = 4
                }
                year = getInt(val, iVal, x, y);
                if (year === null) {
                    return NaN
                }
                iVal += year.length;
                if (year.length === 2) {
                    if (year > 70) {
                        year = 1900 + (year - 0)
                    } else {
                        year = 2e3 + (year - 0)
                    }
                }
            } else if (token === "MMM" || token === "NNN") {
                month = 0;
                for (var i = 0; i < monthsAll.length; i++) {
                    var monthName = monthsAll[i];
                    if (val.substring(iVal, iVal + monthName.length).toLowerCase() === monthName.toLowerCase()) {
                        if (token === "MMM" || token === "NNN" && i > 11) {
                            month = i + 1;
                            if (month > 12) {
                                month -= 12
                            }
                            iVal += monthName.length;
                            break
                        }
                    }
                }
                if (month < 1 || month > 12) {
                    return NaN
                }
            } else if (token === "EE" || token === "E") {
                for (var n = 0; n < daysAll.length; n++) {
                    var dayName = daysAll[n];
                    if (val.substring(iVal, iVal + dayName.length).toLowerCase() === dayName.toLowerCase()) {
                        iVal += dayName.length;
                        break
                    }
                }
            } else if (token === "MM" || token === "M") {
                month = getInt(val, iVal, token.length, 2);
                if (month === null || month < 1 || month > 12) {
                    return NaN
                }
                iVal += month.length
            } else if (token === "dd" || token === "d") {
                date = getInt(val, iVal, token.length, 2);
                if (date === null || date < 1 || date > 31) {
                    return NaN
                }
                iVal += date.length
            } else if (token === "hh" || token === "h") {
                hh = getInt(val, iVal, token.length, 2);
                if (hh === null || hh < 1 || hh > 12) {
                    return NaN
                }
                iVal += hh.length
            } else if (token === "HH" || token === "H") {
                hh = getInt(val, iVal, token.length, 2);
                if (hh === null || hh < 0 || hh > 23) {
                    return NaN
                }
                iVal += hh.length
            } else if (token === "KK" || token === "K") {
                hh = getInt(val, iVal, token.length, 2);
                if (hh === null || hh < 0 || hh > 11) {
                    return NaN
                }
                iVal += hh.length
            } else if (token === "kk" || token === "k") {
                hh = getInt(val, iVal, token.length, 2);
                if (hh === null || hh < 1 || hh > 24) {
                    return NaN
                }
                iVal += hh.length;
                hh--
            } else if (token === "mm" || token === "m") {
                mm = getInt(val, iVal, token.length, 2);
                if (mm === null || mm < 0 || mm > 59) {
                    return NaN
                }
                iVal += mm.length
            } else if (token === "ss" || token === "s") {
                ss = getInt(val, iVal, token.length, 2);
                if (ss === null || ss < 0 || ss > 59) {
                    return NaN
                }
                iVal += ss.length
            } else if (token === "a") {
                if (val.substring(iVal, iVal + 2).toLowerCase() === "am") {
                    ampm = "AM"
                } else if (val.substring(iVal, iVal + 2).toLowerCase() === "pm") {
                    ampm = "PM"
                } else {
                    return NaN
                }
                iVal += 2
            } else {
                if (val.substring(iVal, iVal + token.length) !== token) {
                    return NaN
                } else {
                    iVal += token.length
                }
            }
        }
        if (iVal !== val.length) {
            return NaN
        }
        if (month === 2) {
            if (year % 4 === 0 && year % 100 !== 0 || year % 400 === 0) {
                if (date > 29) {
                    return NaN
                }
            } else {
                if (date > 28) {
                    return NaN
                }
            }
        }
        if (month === 4 || month === 6 || month === 9 || month === 11) {
            if (date > 30) {
                return NaN
            }
        }
        if (hh < 12 && ampm === "PM") {
            hh = hh - 0 + 12
        } else if (hh > 11 && ampm === "AM") {
            hh -= 12
        }
        var newdate = new Date(year, month - 1, date, hh, mm, ss);
        return newdate.getTime()
    };
    Date.parse = function (date, format) {
        if (format) {
            return getDateFromFormat(date, format)
        }
        var timestamp = origParse(date),
            minutesOffset = 0,
            match;
        if (isNaN(timestamp) && (match = /^(\d{4}|[+\-]\d{6})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3,}))?)?(?:(Z)|([+\-])(\d{2})(?::?(\d{2}))?))?/.exec(date))) {
            if (match[8] !== "Z") {
                minutesOffset = +match[10] * 60 + +match[11];
                if (match[9] === "+") {
                    minutesOffset = 0 - minutesOffset
                }
            }
            match[7] = match[7] || "000";
            timestamp = Date.UTC(+match[1], +match[2] - 1, +match[3], +match[4], +match[5] + minutesOffset, +match[6], +match[7].substr(0, 3))
        }
        return timestamp
    };

    function polyfill(name, func) {
        if (Date.prototype[name] === undefined) {
            Date.prototype[name] = func
        }
    }
    Date.today = function () {
        return (new Date).clearTime()
    };
    Date.UTCtoday = function () {
        return (new Date).clearUTCTime()
    };
    Date.tomorrow = function () {
        return Date.today().add({
            days: 1
        })
    };
    Date.UTCtomorrow = function () {
        return Date.UTCtoday().add({
            days: 1
        })
    };
    Date.yesterday = function () {
        return Date.today().add({
            days: -1
        })
    };
    Date.UTCyesterday = function () {
        return Date.UTCtoday().add({
            days: -1
        })
    };
    Date.validateDay = function (day, year, month) {
        var date = new Date(year, month, day);
        return date.getFullYear() === year && date.getMonth() === month && date.getDate() === day
    };
    Date.validateYear = function (year) {
        return year >= 0 && year <= 9999
    };
    Date.validateSecond = function (second) {
        return second >= 0 && second < 60
    };
    Date.validateMonth = function (month) {
        return month >= 0 && month < 12
    };
    Date.validateMinute = function (minute) {
        return minute >= 0 && minute < 60
    };
    Date.validateMillisecond = function (milli) {
        return milli >= 0 && milli < 1e3
    };
    Date.validateHour = function (hour) {
        return hour >= 0 && hour < 24
    };
    Date.compare = function (date1, date2) {
        if (date1.valueOf() < date2.valueOf()) {
            return -1
        } else if (date1.valueOf() > date2.valueOf()) {
            return 1
        }
        return 0
    };
    Date.equals = function (date1, date2) {
        return date1.valueOf() === date2.valueOf()
    };
    Date.equalsDay = function (date1, date2) {
        return date1.toYMD() === date2.toYMD()
    };
    Date.getDayNumberFromName = function (name) {
        return dayNames[name.toLowerCase()]
    };
    Date.getMonthNumberFromName = function (name) {
        return monthNames[name.toLowerCase()]
    };
    Date.getMonthNameFromNumber = function (number) {
        return monthsFull[number]
    };
    Date.getMonthAbbrFromNumber = function (number) {
        return monthsAbbr[number]
    };
    Date.isLeapYear = function (year) {
        return new Date(year, 1, 29).getDate() === 29
    };
    Date.getDaysInMonth = function (year, month) {
        if (month === 1) {
            return Date.isLeapYear(year) ? 29 : 28
        }
        return daysInMonth[month]
    };
    polyfill("getMonthAbbr", function () {
        return monthsAbbr[this.getMonth()]
    });
    polyfill("getMonthName", function () {
        return monthsFull[this.getMonth()]
    });
    polyfill("getLastMonthName", function () {
        var i = this.getMonth();
        i = i == 0 ? 11 : i - 1;
        return monthsFull[i]
    });
    polyfill("getUTCOffset", function () {
        var tz = pad(Math.abs(this.getTimezoneOffset() / .6), 4);
        if (this.getTimezoneOffset() > 0) {
            tz = "-" + tz
        }
        return tz
    });
    polyfill("toCLFString", function () {
        return pad(this.getDate(), 2) + "/" + this.getMonthAbbr() + "/" + this.getFullYear() + ":" + pad(this.getHours(), 2) + ":" + pad(this.getMinutes(), 2) + ":" + pad(this.getSeconds(), 2) + " " + this.getUTCOffset()
    });
    polyfill("toYMD", function (separator) {
        separator = typeof separator === "undefined" ? "-" : separator;
        return this.getFullYear() + separator + pad(this.getMonth() + 1, 2) + separator + pad(this.getDate(), 2)
    });
    polyfill("toDBString", function () {
        return this.getUTCFullYear() + "-" + pad(this.getUTCMonth() + 1, 2) + "-" + pad(this.getUTCDate(), 2) + " " + pad(this.getUTCHours(), 2) + ":" + pad(this.getUTCMinutes(), 2) + ":" + pad(this.getUTCSeconds(), 2)
    });
    polyfill("clearTime", function () {
        this.setHours(0);
        this.setMinutes(0);
        this.setSeconds(0);
        this.setMilliseconds(0);
        return this
    });
    polyfill("clearUTCTime", function () {
        this.setUTCHours(0);
        this.setUTCMinutes(0);
        this.setUTCSeconds(0);
        this.setUTCMilliseconds(0);
        return this
    });
    polyfill("add", function (obj) {
        if (obj.milliseconds !== undefined) {
            this.setMilliseconds(this.getMilliseconds() + obj.milliseconds)
        }
        if (obj.seconds !== undefined) {
            this.setSeconds(this.getSeconds() + obj.seconds)
        }
        if (obj.minutes !== undefined) {
            this.setMinutes(this.getMinutes() + obj.minutes)
        }
        if (obj.hours !== undefined) {
            this.setHours(this.getHours() + obj.hours)
        }
        if (obj.days !== undefined) {
            this.setDate(this.getDate() + obj.days)
        }
        if (obj.weeks !== undefined) {
            this.setDate(this.getDate() + obj.weeks * 7)
        }
        if (obj.months !== undefined) {
            this.setMonth(this.getMonth() + obj.months)
        }
        if (obj.years !== undefined) {
            this.setFullYear(this.getFullYear() + obj.years)
        }
        return this
    });
    polyfill("addMilliseconds", function (milliseconds) {
        return this.add({
            milliseconds: milliseconds
        })
    });
    polyfill("addSeconds", function (seconds) {
        return this.add({
            seconds: seconds
        })
    });
    polyfill("addMinutes", function (minutes) {
        return this.add({
            minutes: minutes
        })
    });
    polyfill("addHours", function (hours) {
        return this.add({
            hours: hours
        })
    });
    polyfill("addDays", function (days) {
        return this.add({
            days: days
        })
    });
    polyfill("addWeeks", function (weeks) {
        return this.add({
            days: weeks * 7
        })
    });
    polyfill("addMonths", function (months) {
        return this.add({
            months: months
        })
    });
    polyfill("addYears", function (years) {
        return this.add({
            years: years
        })
    });
    polyfill("remove", function (obj) {
        if (obj.seconds !== undefined) {
            this.setSeconds(this.getSeconds() - obj.seconds)
        }
        if (obj.minutes !== undefined) {
            this.setMinutes(this.getMinutes() - obj.minutes)
        }
        if (obj.hours !== undefined) {
            this.setHours(this.getHours() - obj.hours)
        }
        if (obj.days !== undefined) {
            this.setDate(this.getDate() - obj.days)
        }
        if (obj.weeks !== undefined) {
            this.setDate(this.getDate() - obj.weeks * 7)
        }
        if (obj.months !== undefined) {
            this.setMonth(this.getMonth() - obj.months)
        }
        if (obj.years !== undefined) {
            this.setFullYear(this.getFullYear() - obj.years)
        }
        return this
    });
    polyfill("removeMilliseconds", function (milliseconds) {
        throw new Error("Not implemented")
    });
    polyfill("removeSeconds", function (seconds) {
        return this.remove({
            seconds: seconds
        })
    });
    polyfill("removeMinutes", function (minutes) {
        return this.remove({
            minutes: minutes
        })
    });
    polyfill("removeHours", function (hours) {
        return this.remove({
            hours: hours
        })
    });
    polyfill("removeDays", function (days) {
        return this.remove({
            days: days
        })
    });
    polyfill("removeWeeks", function (weeks) {
        return this.remove({
            days: weeks * 7
        })
    });
    polyfill("removeMonths", function (months) {
        return this.remove({
            months: months
        })
    });
    polyfill("removeYears", function (years) {
        return this.remove({
            years: years
        })
    });
    polyfill("addWeekdays", function (weekdays) {
        var day = this.getDay();
        if (day === 0) {
            day = 7
        }
        var daysOffset = weekdays;
        var weekspan = Math.floor((weekdays + day - 1) / 5);
        if (weekdays > 0) {
            daysOffset += weekspan * 2;
            if (day > 5) {
                daysOffset -= day - 5
            }
        } else {
            daysOffset += Math.min(weekspan * 2, 0);
            if (day > 6) {
                daysOffset -= 1
            }
        }
        return this.addDays(daysOffset)
    });
    polyfill("setTimeToNow", function () {
        var n = new Date;
        this.setMilliseconds(n.getMilliseconds());
        this.setSeconds(n.getSeconds());
        this.setMinutes(n.getMinutes());
        this.setHours(n.getHours())
    });
    polyfill("clone", function () {
        return new Date(this.valueOf())
    });
    polyfill("between", function (start, end) {
        return this.valueOf() >= start.valueOf() && this.valueOf() <= end.valueOf()
    });
    polyfill("compareTo", function (date) {
        return Date.compare(this, date)
    });
    polyfill("equals", function (date) {
        return Date.equals(this, date)
    });
    polyfill("equalsDay", function (date) {
        return Date.equalsDay(this, date)
    });
    polyfill("isToday", function () {
        return Date.equalsDay(this, Date.today())
    });
    polyfill("isAfter", function (date) {
        date = date ? date : new Date;
        return this.compareTo(date) > 0
    });
    polyfill("isBefore", function (date) {
        date = date ? date : new Date;
        return this.compareTo(date) < 0
    });
    polyfill("isWeekend", function (date) {
        return this.getDay() % 6 === 0
    });
    polyfill("getDaysBetween", function (date) {
        return (date.clone().valueOf() - this.valueOf()) / 864e5 | 0
    });
    polyfill("getHoursBetween", function (date) {
        return (date.clone().valueOf() - this.valueOf()) / 36e5 | 0
    });
    polyfill("getMinutesBetween", function (date) {
        return (date.clone().valueOf() - this.valueOf()) / 6e4 | 0
    });
    polyfill("getSecondsBetween", function (date) {
        return (date.clone().valueOf() - this.valueOf()) / 1e3 | 0
    });
    polyfill("getMillisecondsBetween", function (date) {
        return date.clone().valueOf() - this.valueOf() | 0
    });
    polyfill("getMonthsBetween", function (date) {
        var daysDiff, daysInMonth, months = Math.ceil(new Date(date - this).getUTCDate() / 31),
            testDate = new Date(this.getTime()),
            totalDays = Date.getDaysInMonth;
        testDate.setUTCMonth(testDate.getUTCMonth() + months);
        while (testDate.getTime() < date.getTime()) {
            testDate.setUTCMonth(testDate.getUTCMonth() + 1);
            months++
        }
        if (testDate.getTime() !== date.getTime()) {
            testDate.setUTCMonth(testDate.getUTCMonth() - 1);
            months--
        }
        if (date.getUTCMonth() === testDate.getUTCMonth()) {
            daysDiff = new Date(date - testDate).getUTCDate();
            daysInMonth = totalDays(testDate.getUTCFullYear(), testDate.getUTCMonth());
            return months + daysDiff / daysInMonth
        } else {
            daysInMonth = totalDays(testDate.getUTCFullYear(), testDate.getUTCMonth());
            daysDiff = daysInMonth - testDate.getUTCDate() + 1;
            return months + +(daysDiff / daysInMonth).toFixed(5) + +(date.getUTCDate() / totalDays(date.getUTCFullYear(), date.getUTCMonth())).toFixed(5)
        }
    });
    polyfill("getOrdinalNumber", function () {
        return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 864e5) + 1
    });
    polyfill("toFormat", function (format) {
        return toFormat(format, getReplaceMap(this))
    });
    polyfill("toUTCFormat", function (format) {
        return toFormat(format, getUTCReplaceMap(this))
    });
    polyfill("getWeekNumber", function () {
        var onejan = new Date(this.getFullYear(), 0, 1);
        return Math.ceil(((this - onejan) / 864e5 + onejan.getDay() + 1) / 7)
    });
    polyfill("getFullWeekNumber", function () {
        var weekNumber = "" + this.getWeekNumber();
        if (weekNumber.length === 1) {
            weekNumber = "0" + weekNumber
        }
        return weekNumber
    });
    var toFormat = function (format, replaceMap) {
        var f = [format],
            i, l, s;
        var replace = function (str, rep) {
            var i = 0,
                l = f.length,
                j, ll, t, n = [];
            for (; i < l; i++) {
                if (typeof f[i] == "string") {
                    t = f[i].split(str);
                    for (j = 0, ll = t.length - 1; j < ll; j++) {
                        n.push(t[j]);
                        n.push([rep])
                    }
                    n.push(t[ll])
                } else {
                    n.push(f[i])
                }
            }
            f = n
        };
        for (i in replaceMap) {
            replace(i, replaceMap[i])
        }
        s = "";
        for (i = 0, l = f.length; i < l; i++) s += typeof f[i] == "string" ? f[i] : f[i][0];
        return f.join("")
    };
    var getReplaceMap = function (date) {
        var hours = date.getHours() % 12 ? date.getHours() % 12 : 12;
        return {
            YYYY: date.getFullYear(),
            YY: String(date.getFullYear()).slice(-2),
            MMMM: monthsFull[date.getMonth()],
            MMM: monthsAbbr[date.getMonth()],
            MM: pad(date.getMonth() + 1, 2),
            MI: pad(date.getMinutes(), 2),
            M: date.getMonth() + 1,
            DDDD: daysFull[date.getDay()],
            DDD: daysAbbr[date.getDay()],
            DD: pad(date.getDate(), 2),
            D: date.getDate(),
            HH24: pad(date.getHours(), 2),
            HH: pad(hours, 2),
            H: hours,
            SS: pad(date.getSeconds(), 2),
            PP: date.getHours() >= 12 ? "PM" : "AM",
            P: date.getHours() >= 12 ? "pm" : "am",
            LL: pad(date.getMilliseconds(), 3)
        }
    };
    var getUTCReplaceMap = function (date) {
        var hours = date.getUTCHours() % 12 ? date.getUTCHours() % 12 : 12;
        return {
            YYYY: date.getUTCFullYear(),
            YY: String(date.getUTCFullYear()).slice(-2),
            MMMM: monthsFull[date.getUTCMonth()],
            MMM: monthsAbbr[date.getUTCMonth()],
            MM: pad(date.getUTCMonth() + 1, 2),
            MI: pad(date.getUTCMinutes(), 2),
            M: date.getUTCMonth() + 1,
            DDDD: daysFull[date.getUTCDay()],
            DDD: daysAbbr[date.getUTCDay()],
            DD: pad(date.getUTCDate(), 2),
            D: date.getUTCDate(),
            HH24: pad(date.getUTCHours(), 2),
            HH: pad(hours, 2),
            H: hours,
            SS: pad(date.getUTCSeconds(), 2),
            PP: date.getUTCHours() >= 12 ? "PM" : "AM",
            P: date.getUTCHours() >= 12 ? "pm" : "am",
            LL: pad(date.getUTCMilliseconds(), 3)
        }
    }
})();