前言:最近在用到JS日期操作時,發現有一些不方便,於是搜素了一些網上的資料,基於一個開源工具類-yDate 進行了個性化定制,封裝成了一個日期工具類
工具函數大概介紹:
1.普通的日期操作
2. 獲得一些絕對時間,如1970年 到現在的絕對年,月份,日期,描述,毫秒數等等
3. 日期比較,克隆,開始時間,結束時間,字符串(輸出時可以自定義格式)輸出等
4. 日期相加,相減(返回一個新的日期對象), 比如1月31日 1天會自動變為 2月1日等等
5. 簡化構造,可以傳入字符串進行構造等等
6. 更多請看源碼
說明-基於yDate:| yDate.js | Copyright (c) 2013 yao.yl | email: redrainyi@126.com | Date: 2012-09-03 | *
原地址: http://www.oschina.net/code/snippet_913265_20123
源碼如下:
/** * @description 日期工具類 * 原作來源: | yDate.js | Copyright (c) 2013 yao.yl | email: redrainyi@126.com | Date: 2012-09-03 | * * 地址: http://www.oschina.net/code/snippet_913265_20123#comments * 改動說明: 針對yDate進行了一些個性化的修改,以及增加了一些工具函數 * @author dailc dailc * @version 2.0 * @time 2016-01-14 12:57:57 * 功能模塊: * Date相關模塊******************************** * core/MobileFrame/DateUtil * 1.構造方法 * 2.對象的相關功能函數-見源碼和文檔 * Date相關模塊結束***************************** */ (function(exports) { "use strict"; var objectPrototypeToString = Object.prototype.toString; /** * 日期匹配的正則表達式 * Y:年 * M:月 * D:日 * h:小時 * m:分鍾 * s:秒 * i:毫秒 * w:星期(小寫的) * W:星期(大寫的) */ var SIGN_DATE_REG = /([YMDhmsiWw])(\1*)/g; /** * 默認的pattern * 'YYYY-MM-DD hh:mm:ss:iii' */ var DEFAULT_PATTERN = 'YYYY-MM-DD hh:mm:ss:iii'; /** * @description 判斷一個值是否是日期類型 * @param {Object} value */ function isDate(value) { return objectPrototypeToString.call(value) === '[object Date]'; }; /** * @description 復制一個日期,如果傳入的不是日期,會返回一個最新的日期 * @param {Date} targetDate */ function cloneDate(targetDate, callBack) { //絕對時間,從1970.1.1開始的毫秒數 var absoluteTime = (isDate(targetDate)) ? targetDate.getTime() : undefined; var mDate = new Date(absoluteTime); var year = mDate.getFullYear(), // month = mDate.getMonth(), // date = mDate.getDate(), // hours = mDate.getHours(), // minutes = mDate.getMinutes(), // seconds = mDate.getSeconds(); // //!! 代表將后面的轉為一個布爾表達式 例如 !!a 就相當於 a||false (!!callBack) && callBack(mDate, year, month, date, hours, minutes, seconds); return mDate; }; /** * @description 日期解析,將日期字符串根據特定的匹配字符串解析為日期格式 * 解析失敗會返回null,如果傳入了奇怪的匹配字符串,會產生奇怪的時間 * @param {String} dateString 日期字符串 * @param {String} pattern 匹配字符串,可以手動傳入,或者采取默認 * 手動傳入需要和日期字符串保持一致 */ function parseDate(dateString, pattern) { try { //() 是為了提取匹配的字符串。表達式中有幾個()就有幾個相應的匹配字符串。 //(\s*)表示連續空格的字符串。 //[]是定義匹配的字符范圍。比如 [a-zA-Z0-9] 表示相應位置的字符要匹配英文字符和數字。 //[\s*]表示空格或者*號。 //{}一般用來表示匹配的長度,比如 \s{3} 表示匹配三個空格,\s[1,3]表示匹配一到三個空格。 //(\1)是后向引用,代表后面引用前面第一個()中的內容 //根據日期格式來匹配 var matchs1 = (pattern || (dateString.length === 10 ? 'YYYY-MM-DD' : (dateString.length === 19 ? 'YYYY-MM-DD hh:mm:ss' : 'YYYY-MM-DD hh:mm:ss:iii'))).match(SIGN_DATE_REG); //根據整數來匹配,將實際的時間數據提取出來 var matchs2 = dateString.match(/(\d)+/g); if (matchs1.length > 0) { //第一個匹配字符串需要大於0才行 //生成一個最原始的時間-1970-01-01年的 var mDate = new Date(1970, 0, 1); //遍歷,分別設置年月日,分秒等等 for (var i = 0; i < matchs1.length; i++) { //這個分別是 年,月,日 時,分,秒等等 var mTarget = parseInt(matchs2[i], 10); switch (matchs1[i].charAt(0) || '') { //這個matchs1[i]有可能是 YYYY 所以只去第一個字符 case 'Y': mDate.setFullYear(mTarget); break; case 'M': mDate.setMonth(mTarget - 1); break; case 'D': mDate.setDate(mTarget); break; case 'h': mDate.setHours(mTarget); break; case 'm': mDate.setMinutes(mTarget); break; case 's': mDate.setSeconds(mTarget); break; case 'i': mDate.setMilliseconds(mTarget); break; default: //默認不操作 } } return mDate; } } catch (e) { } return null; }; /** * @description 將字符串多余的長度補齊0 * @param {String} s * @param {Number} len */ function paddingFillWith0(s, len) { var len = len - (s + "").length; for (var i = 0; i < len; i++) { s = "0" + s; } return s; } /** * @description 格式化時間,返回格式化后的字符串 * 如果格式不合要求,返回null * @param {Date} value 目標時間 * @param {String} pattern 匹配字符串 */ function formatDateToString(value, pattern) { if (!isDate(value)) { return ''; } try { //默認為輸出所有的 pattern = pattern || DEFAULT_PATTERN; return pattern.replace(SIGN_DATE_REG, function($0) { //如果傳入一個yyyy-MM-dd 的表達式 //實際上這個函數會分別回調多次 沒符合一次匹配就回調一次 //$0:yyyy $0:MM $0:dd 依次類推 //console.log('$0:'+$0); switch ($0.charAt(0)) { case 'Y': return paddingFillWith0(value.getFullYear(), $0.length); case 'M': return paddingFillWith0(value.getMonth() + 1, $0.length); case 'D': return paddingFillWith0(value.getDate(), $0.length); case 'h': return paddingFillWith0(value.getHours(), $0.length); case 'm': return paddingFillWith0(value.getMinutes(), $0.length); case 's': return paddingFillWith0(value.getSeconds(), $0.length); case 'i': return paddingFillWith0(value.getMilliseconds(), $0.length); case 'w': return value.getDay(); case 'W': //自動將星期轉為了大寫 var week = ['日', '一', '二', '三', '四', '五', '六']; return paddingFillWith0(week[value.getDay()], $0.length); default: return ''; } }); } catch (e) { console.log('error:' + e); return ''; } }; /** * @description 得到實際日期最大值 * @param {Date} date */ function getActualMaximum(date) { var vDate = new Date(date.getTime()); vDate.setMonth(vDate.getMonth() + 1); vDate.setDate(0); return vDate.getDate(); } /** * @description 定義一個自定義日期類的構造方法, * 里面封裝日期的常用操作,不通過自帶的日期來操作 * @constructor 這是一個構造方法 */ function MyDate() { var p0 = arguments[0]; var p1 = arguments[1]; //isFinite 用於判斷是否是無窮大 //如果 number 是有限數字(或可轉換為有限數字),那么返回 true //如果 number 是 NaN(非數字),或者是正、負無窮大的數,則返回 false if (typeof p0 === 'number' && isFinite(value)) { this.myDate = new Date(p0); //millis } else if (isDate(p0)) { this.myDate = new Date(p0.getTime()); } else if (typeof p0 === 'string') { if (typeof p1 !== 'string' && typeof p1 !== 'undefined') { p1 = undefined; } this.myDate = parseDate(p0, p1); } else if (arguments.length == 0) { this.myDate = new Date(); } else { throw 'MyDate Constructor Error!'; } }; /** * @description 給一個日期設置年份 * @param {Number} finalYear * @param {Date} mDate * @param {MyDate} self */ function setYearG(finalYear, mDate, self) { mDate.setFullYear(finalYear); } /** * @description 給一個日期設置月份 * 之所以要單獨將設置月份(年,日,時...)的函數抽取出來,是因為 * 在日期時間 加,減操作時,會涉及到一個進位問題: 比如,1月31日的下一天應該是2月1日... * 所以單獨封裝成函數便於調用 * 之所以沒有 直接調用plusMonth,plusYear... * 是因為這個操作中間有回調,多個回調嵌套后,無法同步返回最准確的數據 * (可以自行測試) * @param {Number} finalYear * @param {Date} mDate * @param {MyDate} self */ function setMonthG(finalMon, mDate, self) { //month 為 0-11 if (finalMon > 11) { finalMon = finalMon - 12; setYearG(mDate.getFullYear() + 1, mDate, self); } else if (finalMon < 0) { finalMon += 12; setYearG(mDate.getFullYear() - 1, mDate, self); } /* * 關於月份順延的bug 發現如下規律:只要setMonth()的參數為小於31天的月份時就會變為下一個月。 原因是:因為當前月份是31天,而設置的月份小於31天,就會把日期順延。在setMonth的說明是這樣的: dateObj.setMonth(numMonth[, dateVal]) dateVal 可選項。一個代表日期的數值。 如果沒有提供此參數,那么將使用通過調用 getDate 方法而得到的數值。 所以,從對dataVal參數的說明可以看出,在設置月份的同時, 使用getDate獲取日期,並使用得到的日期值設置了日期。 於是就會發生月份順延的情況。 解決方法: 1、設置月份時,將日期設為1,記setMonth(month, 1), 當然可以在setMonth之前先調用setDate()設置日期; 2、也可以在初始化Date對象時,就指定一個日期,也就是使用: dateObj = new Date(year, month, date[, hours[, minutes[, seconds[,ms]]]]) 的形式。 3、也可以使用setFullYear()同時設置年、月、日,即setFullYear(numYear[, numMonth[, numDate]])。 *bug簡單說明: * 如果當前是10月31日,然后設置月份為11,由於11月沒有31天,所以月份會順延 * 自動變為12月,所以解決方法是要在設置月份前先把日期設置下,然后之后再繼續設置日期 * (因為日期肯定是需要改變的) * * * * */ mDate.setMonth(finalMon, 1); } /** * @description 給一個日期設置日期 * @param {Number} finalYear * @param {Date} mDate * @param {MyDate} self */ function setDateG(finalDay, mDate, self) { var month = mDate.getMonth(); var monthDays = self.getMonthDays(month + 1); if (finalDay > monthDays) { finalDay -= monthDays; setMonthG(mDate.getMonth() + 1, mDate, self); } else if (finalDay <= 0) { var lastMonthDay = month > 0 ? self.getMonthDays((month + 1 - 1)) : self.getMonthDays(12); finalDay += lastMonthDay; setMonthG(mDate.getMonth() - 1, mDate, self); } mDate.setDate(finalDay); } /** * @description 給一個日期設置小時 * @param {Number} finalYear * @param {Date} mDate * @param {MyDate} self */ function setHourG(finalHour, mDate, self) { if (finalHour >= 24) { finalHour -= 24; setDateG(mDate.getDate() + 1, mDate, self); } else if (finalHour < 0) { finalHour += 24; setDateG(mDate.getDate() - 1, mDate, self); } mDate.setHours(finalHour); } /** * @description 給一個日期設置分鍾 * @param {Number} finalYear * @param {Date} mDate * @param {MyDate} self */ function setMinG(finalMin, mDate, self) { if (finalMin >= 60) { finalMin -= 60; setHourG(mDate.getHours() + 1, mDate, self); } else if (finalHour < 0) { finalMin += 60; setHourG(mDate.getHours() - 1, mDate, self); } mDate.setMinutes(finalMin); } /** * @description 給一個日期設置秒 * @param {Number} finalYear * @param {Date} mDate * @param {MyDate} self */ function setSecG(finalSec, mDate, self) { if (finalSec >= 60) { finalSec -= 60; setMinG(mDate.getMinutes() + 1, mDate, self); } else if (finalSec < 0) { finalSec += 60; setMinG(mDate.getMinutes() - 1, mDate, self); } mDate.setSeconds(finalSec); } /** * @description 通過擴充原型添加方法 */ MyDate.prototype = { /** * @description 得到一個月有多少天 * @param {Number} month 對應的月份 */ getMonthDays: function(month) { switch (month) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: return 31; break; case 4: case 6: case 9: case 11: return 30; break; case 2: if (this.isLeapYear()) { return 29; } else { return 28; } break; default: return 0; break; } }, /** * @description 年份相加,返回一個新的日期 * @param {Object} value */ plusYear: function(value) { var self = this; return new MyDate(cloneDate(this.myDate, function(mDate, year, month, date, hours, minutes, seconds) { setYearG(year + value, mDate, self); })); }, plusMonth: function(value) { var self = this; return new MyDate(cloneDate(this.myDate, function(mDate, year, month, date, hours, minutes, seconds) { setMonthG(month + value, mDate, self); })); }, plusDate: function(value) { var self = this; return new MyDate(cloneDate(this.myDate, function(mDate, year, month, date, hours, minutes, seconds) { var finalDay = date + value; setDateG(finalDay, mDate, self); })); }, plusHours: function(value) { var self = this; return new MyDate(cloneDate(this.myDate, function(mDate, year, month, date, hours, minutes, seconds) { var finalHour = hours + value; setHourG(finalHour, mDate, self); })); }, plusMinutes: function(value) { var self = this; return new MyDate(cloneDate(this.myDate, function(mDate, year, month, date, hours, minutes, seconds) { var finalMin = minutes + value; setMinG(finalMin, mDate, self); })); }, plusSeconds: function(value) { var self = this; return new MyDate(cloneDate(this.myDate, function(mDate, year, month, date, hours, minutes, seconds) { var finalSec = seconds + value; setSecG(finalSec, mDate, self); })); }, minusYear: function(value) { return this.plusYear(-value); }, minusMonth: function(value) { return this.plusMonth(-value); }, minusDate: function(value) { return this.plusDate(-value); }, minusHours: function(value) { return this.plusHours(-value); }, minusMinutes: function(value) { return this.plusMinutes(-value); }, minusSeconds: function(value) { return this.plusSeconds(-value); }, setYear: function(value) { this.myDate.setFullYear(value); }, setMonth: function(value) { this.myDate.setMonth(value - 1); }, setDate: function(value) { this.myDate.setDate(value); }, setHours: function(value) { this.myDate.setHours(value); }, setMinutes: function(value) { this.myDate.setMinutes(value); }, setSeconds: function(value) { this.myDate.setSeconds(value); }, setMilliseconds: function(value) { this.myDate.setMilliseconds(value); }, getYear: function() { return this.myDate.getFullYear(); }, getMonth: function() { //比普通月份小1 return this.myDate.getMonth(); }, getDate: function() { return this.myDate.getDate(); }, getHours: function() { return this.myDate.getHours(); }, getMinutes: function() { return this.myDate.getMinutes(); }, getSeconds: function() { return this.myDate.getSeconds(); }, getMilliseconds: function() { return this.myDate.getMilliseconds(); }, /** * @description 得到從1970至今多少年 */ getAbsoluteYear: function() { return this.myDate.getFullYear() - 1970; }, getAbsoluteMonth: function() { return this.getAbsoluteYear() * 12 + this.myDate.getMonth(); }, /** * @description 獲得絕對日期 * 這里采取的方法為 得到從1970至今的毫秒數,然后轉為天 */ getAbsoluteDate: function() { var absoluteMillons = this.getAbsoluteMillonsTime(); //毫秒-秒-分-時-天 return parseInt(absoluteMillons / 1000 / 60 / 60 / 24, 10); }, getAbsoluteHours: function() { return this.getAbsoluteDate() * 24 + this.myDate.getHours(); }, getAbsoluteMinutes: function() { return this.getAbsoluteHours() * 60 + this.myDate.getMinutes(); }, getAbsoluteSeconds: function() { return this.getAbsoluteMinutes() * 60 + this.myDate.getSeconds(); }, /** * @description 得到從1970年開始到現在的毫秒數 * 單位是毫秒 */ getAbsoluteMillonsTime: function() { return this.myDate.getTime(); }, getDayOfWeek: function(pattern) { //0(周日) 到 6(周六 //var week = ['日','一','二','三','四','五','六']; return this.myDate.getDay(); }, isLeapYear: function() { return (0 == this.myDate.getYear() % 4 && ((this.myDate.getYear() % 100 != 0) || (this.myDate.getYear() % 400 == 0))); }, toDate: function() { return cloneDate(this.myDate); }, clone: function() { return new MyDate(cloneDate(this.myDate)); }, /** * @description 得到一個日期的最小時間 * @param {String}method = [YYYY|MM|DD|hh|mm|ss] field 分別代表年,月,日,時,分,秒的抉擇 */ getBegin: function(field) { return new MyDate(cloneDate(this.myDate, function(mDate, year, month, date, hours, minutes, seconds) { switch (field) { case 'YYYY': //year mDate.setMonth(0); mDate.setDate(1); mDate.setHours(0); mDate.setMinutes(0); mDate.setSeconds(0); mDate.setMilliseconds(0); break; case 'MM': //month mDate.setDate(1); mDate.setHours(0); mDate.setMinutes(0); mDate.setSeconds(0); mDate.setMilliseconds(0); case 'DD': //date mDate.setHours(0); mDate.setMinutes(0); mDate.setSeconds(0); mDate.setMilliseconds(0); break; case 'hh': //hour mDate.setMinutes(0); mDate.setSeconds(0); mDate.setMilliseconds(0); break; case 'mm': //minute mDate.setSeconds(0); mDate.setMilliseconds(0); break; case 'ss': //seconds mDate.setMilliseconds(0); break; default: //Ignore } })); }, /** * @description 得到一個日期的最大時間 * @param {String}method = [YYYY|MM|DD|hh|mm|ss] field 分別代表年,月,日,時,分,秒的抉擇 */ getEnd: function(field) { return new MyDate(cloneDate(this.myDate, function(mDate, year, month, date, hours, minutes, seconds) { switch (field) { case 'YYYY': //year mDate.setMonth(11); mDate.setDate(31); mDate.setHours(23); mDate.setMinutes(59); mDate.setSeconds(59); mDate.setMilliseconds(999); break; case 'MM': //month mDate.setDate(getActualMaximum(mDate)); mDate.setHours(23); mDate.setMinutes(59); mDate.setSeconds(59); mDate.setMilliseconds(999); case 'DD': //date mDate.setHours(23); mDate.setMinutes(59); mDate.setSeconds(59); mDate.setMilliseconds(999); break; case 'hh': //hour mDate.setMinutes(59); mDate.setSeconds(59); mDate.setMilliseconds(999); break; case 'mm': //minute mDate.setSeconds(59); mDate.setMilliseconds(999); break; case 'ss': //seconds mDate.setMilliseconds(999); break; default: //Ignore } })); }, /** * @description 和另一個日期比較,另一個日期必須為MyDate型 * @param {Date} targetDate 目標日期,MyDate型 * @param {String} method = [YYYY|MM|DD|hh|mm|ss|iii] pettern 選擇字符串,目前支持 yyyy,MM,dd,HH,mm,ss以及iii * 分別代表比較到某一個層次,默認為比較到毫秒 * @return {Number} 返回結果 * -1:比較字符對象不合法 * 0:兩個日期相等 * 1:本日期大於目標日期 * 2:本日期小於目標日期 */ compare: function(targetDate, pattern) { //如果不是時間類型,而且不是MyDate類型 if (!isDate(targetDate) && !(targetDate instanceof MyDate)) { return -1; } //默認為毫秒 pattern = pattern || 'iii'; if (pattern === 'YYYY') { if (this.getAbsoluteYear() == targetDate.getAbsoluteYear()) { return 0; } else if (this.getAbsoluteYear() > targetDate.getAbsoluteYear()) { return 1; } else { return 2; } } else if (pattern === 'MM') { if (this.getAbsoluteMonth() == targetDate.getAbsoluteMonth()) { return 0; } else if (this.getAbsoluteMonth() > targetDate.getAbsoluteMonth()) { return 1; } else { return 2; } } else if (pattern === 'DD') { if (this.getAbsoluteDate() == targetDate.getAbsoluteDate()) { return 0; } else if (this.getAbsoluteDate() > targetDate.getAbsoluteDate()) { return 1; } else { return 2; } } else if (pattern === 'hh') { if (this.getAbsoluteHours() == targetDate.getAbsoluteHours()) { return 0; } else if (this.getAbsoluteHours() > targetDate.getAbsoluteHours()) { return 1; } else { return 2; } } else if (pattern === 'mm') { if (this.getAbsoluteMinutes() == targetDate.getAbsoluteMinutes()) { return 0; } else if (this.getAbsoluteMinutes() > targetDate.getAbsoluteMinutes()) { return 1; } else { return 2; } } else if (pattern === 'ss') { if (this.getAbsoluteSeconds() == targetDate.getAbsoluteSeconds()) { return 0; } else if (this.getAbsoluteSeconds() > targetDate.getAbsoluteSeconds()) { return 1; } else { return 2; } } else { if (this.getAbsoluteMillonsTime() == targetDate.getAbsoluteMillonsTime()) { return 0; } else if (this.getAbsoluteMillonsTime() > targetDate.getAbsoluteMillonsTime()) { return 1; } else { return 2; } } }, isMoreThan: function(targetDate, pattern) { return this.compare(targetDate, pattern) == 1 ? true : false; }, isLessThan: function(targetDate, pattern) { return this.compare(targetDate, pattern) == 2 ? true : false; }, isEqual: function(targetDate, pattern) { return this.compare(targetDate, pattern) == 0 ? true : false; }, toString: function(pattern) { return formatDateToString(this.myDate, pattern); } }; exports.MyDate = MyDate; })(window.DateUtil={});
使用例子:
var MyDate = DateUtil.MyDate; var date1 = new MyDate(“2016-01-01 01:02:03:000”); date1.getYear(); date1.setYear(2014);