校驗表單時可能會遇到校驗日期是否正確。可以利用JS的內置對象Date
幫助我們完成日期校驗。
思路是首先用被校驗日期(假設為A,可能為字符串或數字)創建一個Date
對象(假設為B)。
然后判斷A和B的年、月、日是否全部相等。如果是,說明A是合法的;否則,A的范圍有誤。
用代碼表示為:
// 被校驗日期A:2008年3月15日
var year = 2008,
month = 3,
date = 15;
// 創建Date對象B
var B = new Date(year, month-1, date);
// 判斷A和B的年月日是否全部相等
if (year === B.getFullYear() && month === B.getMonth()+1 && date === B.getDate()) {
// 全部相等,被校驗日期合法
} else {
// 不全部相等,被校驗日期的年、月、日至少有一個錯誤。
}
這里容易踩坑的地方是,Date
對象月份從零開始:0表示一月,1表示二月,...,11表示十二月。
為什么要構建一個Date
對象?這就要涉及到Date
構造函數的語法了。
官網上上給出了四種調用構造函數的形式:
- 第一種:
new Date()
- 第二種:
new Date(value)
- 第三種:
new Date(dateString)
- 第四種:
new Date(new Date(year, month[, date[, hours[, minutes[, seconds[, milliseconds]]]]]);
解釋如下:
- 第一種:根據系統設置,返回當前日期時間。
- 第二種:value為整數型,表示從1970年1月1日 00:00:00 距現在所過去的毫秒數。
- 第三種:dateString為字符串型,其格式需滿足指定格式。
- 第四種:各參數都是整數型。
當拿到了被校驗日期的年、月、日之后,計算毫秒數或構造日期格式字符串都比較麻煩。所以這里使用第四種。
這時,調用Date
構造函數的另一條規則就起作用了:如果參數值超過了合理范圍,則它會被調整到臨近值。我理解的就是,構造函數會為不合理的參數做進位運算。
舉個例子,new Date(2013,13,1)
相當於new Date(2014,1,1)
,也就是 2013年14月1日被進位成 2014年2月1日。
再回到之前的校驗代碼:
// 被校驗日期A:2013年14月1日
var year = 2013,
month = 14,
date = 1;
// 創建Date對象B
var B = new Date(2013, 13, 1);
// B --> new Date(2014, 1, 1);
// B.getFullYear() === 2014
// B.getMonth() === 1
// B.getDate() === 1
// 可以看到,year !== B.getFullYear() 並且 month !== B.getMonth()
// 所以判斷出被校驗日期是非法的。
再增強一下我們的程序,使之可以判斷多種格式的被校驗日期:
- 年、月、日,例如(2008, 3, 15)、('2008', '3', '15')
- 特殊字符分割的字符串,例如('2008-03-15', '-')、('2008/3/15', '/')
- 連續8位的數字格式,例如'20080315'、20080315
我寫了一段簡易的代碼,僅供參考:
function isValidDate() {
var year = 0,
month = 0,
date = 0;
if (arguments.length === 3) {
// 2008 3 15
// '2008' '3' '15'
year = Number(arguments[0]);
month = Number(arguments[1]);
date = Number(arguments[2]);
} else if (arguments.length === 2) {
// '2008-03-15' '-'
// '2008/3/15' '/'
// 參數必須為字符串類型,分隔符不能為空字符串或數字
var str = arguments[0],
seperator = arguments[1],
dateArray = str.split(seperator);
year = Number(dateArray[0]);
month = Number(dateArray[1]);
date = Number(dateArray[2]);
} else if (arguments.length === 1) {
// '20080315'
// 20080315
// 參數必須為8位,且只能為數字
var str = String(arguments[0]);
year = Number(str.slice(0, 4));
month = Number(str.slice(4, 6));
date = Number(str.slice(6));
}
var dateObj = new Date(year, month-1, date),
nYear = dateObj.getFullYear(),
nMonth = dateObj.getMonth() + 1,
nDate = dateObj.getDate();
if (year === nYear && month === nMonth && date === nDate) {
return true;
} else {
return false;
}
}
// 測試
isValidDate.assert = function(value) {
if (value) {
console.log('pass');
} else {
console.log('failed');
}
}
isValidDate.test = function() {
var assert = isValidDate.assert;
assert(isValidDate(2008, 2, 29)===true);
assert(isValidDate(2008, 3, 33)===false);
assert(isValidDate(2017, 13, 01)===false);
assert(isValidDate(2018, 5, 12)===true);
assert(isValidDate('2008-2-29','-')===true);
assert(isValidDate('2008/02/29','/')===true);
assert(isValidDate('2008 03 17',' ')===true);
assert(isValidDate('2008,13,01',',')===false);
assert(isValidDate('2008,12,01',',')===true);
assert(isValidDate('20080229')===true);
assert(isValidDate('20081329')===false);
assert(isValidDate('20081131')===false);
assert(isValidDate(20080229)===true);
assert(isValidDate(20081329)===false);
assert(isValidDate(20081131)===false);
}
isValidDate.test();