[JavaScript] 檢驗輸入日期是否真實存在
這是 JavaScript 的一個作業的一部份,我把他拆成三個部份寫,第一個是要檢驗從 <input type="text" /> 標籤獲得使用者輸入字串,必須符合 yyyy/mm/dd 的格式,例如 2022/02/10 、2022/04/31 或 2022/02/29:
而且要檢查符合格式的字串所代表的日期,是否真實存在,若輸入不符合格式或不存在的日期就提示並阻擋。大部份網路上找到的這方面問題的解法,都是針對月份是1、3、5、7、8、10、12月則有 31 日,剩餘月份為 30 日,最後檢查閏年平年判斷 2 月是 28 日還是 29 日。這裡我想用不同的解法,並做成了筆記。
格式檢查
首先 HTML 部份
<label for="date">日期:</label> <input type="text" id="date" placeholder="yyyy/mm/dd" onblur="checkDate()" /> <div id="dateWarning"></div>
<input> 標籤有 id="date",在失去焦點時註冊事件 checkDate(),下面置放一個<div> 標籤 id="dateWarning" 做為提示的區域。先對輸入字串檢查是否符合 yyyy/mm/dd 的形式,這裡用正規表示式 Regular Expression:
function checkDate() { let dateText = document.getElementById('date').value; // 取輸入的值的字串 let dateWarning = document.getElementById('dateWarning'); // 取錯誤提示的元素 let regexp = new RegExp(/^[0-9]{1,4}\/((0[1-9])|(1[0-2]))\/((0[1-9])|([12][0-9])(3[01]))$/); // RegularExpression if (!regexp.test(dateText)) { // 匹配測試不符合此格式時 dateWarning.innerHTML = '格式必須符合「年 / 月 / 日」'; return; . . . }
正規表示式雖然長但蠻簡單的,分隔年月日的 / 是特殊字元,要用跳脫字元 \/ ;
然後年的部份 [0-9]{1,4} 匹配了 4 個數字、3 個數字、2 個數字或 1 個數字;
而月的部份因為有01、02、....09、10、11、12月,依十位數字為 0 或 1 分成兩種,十位數字若為 0,則個位數字可為 1 到 9,所以正規表示式為 0[1-9] ,若十位數字是 1,則個位數字可為0、1、2,所以是 1[0-2] ,這兩種都可以就用或符號 | 相連,所以月的部份為 ((0[1-9])|(1[0-2])) ;
最後日的部份有01、02、....09、10、11、12、...、19、20、21、...、29、30、31,依十位數字為 0 或 1 或 2 或 3 分成四種,當十位數字為 0 時,個位數字可為 1 到 9,得 0[1-9] ,若十位數字為 1 或 2 時,個位數字可為 0 到 9,得 [12][0-9] ,若十位數字為 3 時,個位數字可為0、1,得 3[01] ,全部用 | 連接,所以日的部份為 ((0[1-9])|([12][0-9])(3[01]))
JavaScript 的 Date 物件
檢查是否為存在的日期,我利用了 JavaScript 的 Date 物件,所以先介紹一些相關函式方法,因為我的主題在年月日,所以時分秒相關方法就省略:
建構函式 new Date(Year, Month, Day) :用年月日可建構代表該日期的物件,要注意 Month 是0 到 11,一月的 Month = 0,二月的 Month = 1,.... ,十二月的 Month = 11,所以 new Date( 2022, 1, 10 ) 會得到 2022 年 2 月 10 日的物件。
建構函式 new Date(string) :可用如「2022/02/10」、「2015-04-17」、「1995.11.23」的字串建構,所以 new Date( '2022/02/10' ) 會得到 2022 年 2 月 10 日的物件。
.getFullYear():回傳 Date 物件的年份(以 4 位數字表示)
.getMonth():回傳 Date 物件的月份,一月 = 0,二月 = 1,.... ,十二月 = 11
.getDate():回傳 Date 物件的日期,1日 = 1,2日 = 2,.... ,31日 = 31
.getDay():回傳當週的星期,星期日 = 0,星期一 = 1, ... ,星期六 = 6
這裡比較有趣的點是即使是不存在的日期,也可以建構 Date 物件,而日期會被推移,例如 5 月有 31 天:
- new Date( 2015, 4, 31 ) 得 2015 年 5 月 31 日的物件
- new Date( 2015, 4, 32 ) 得 2015 年 6 月 1 日的物件
- new Date( 2015, 4, 33 ) 得 2015 年 6 月 2 日的物件
超過則會往下個月推移,同樣的,不足的會往前推:
- new Date( 2015, 4, 1 ) 得 2015 年 5 月 1 日的物件
- new Date( 2015, 4, 0 ) 得 2015 年 4 月 30 日的物件
- new Date( 2015, 4, -1 ) 得 2015 年 4 月 29 日的物件
檢查日期是否合法
由於錯誤的日期會被推移,所以檢查輸入的日期 day ,和建構成 Date 物件後的日期 day 是否一致,就可以判斷是否合法日期了,前者取得<input> 的 value 字串,取其尾巴兩個數字的子字串,後者取建構出來的的 Date 物件呼叫 .getDate() ,比對兩者即可:
function checkDate() { . . . let dateByText = dateText.slice(-2); // 取出輸入的結尾2字,即日期 let dateByObj = new Date(dateText).getDate(); // 將輸入字串轉為物件,取出日期 if (dateByText != dateByObj) { // 比對 dateWarning.innerHTML = '不存在的日期'; return; } dateWarning.innerHTML = ' '; // 日期沒問題,清空錯誤的提示 return; }
留言
張貼留言