一、今天的學習目標
前幾天我已經讓 /add 可以接收三個欄位:
title
date
time
而且也有使用 Regex 檢查日期是不是 8 位數、時間是不是 4 位數。
const dateRegex = /^\d{8}$/;
const timeRegex = /^\d{4}$/;
這樣可以擋掉像:
2026-10-05
18:30
這種不符合目前輸入規則的格式。
但今天遇到一個新的問題。
就算格式正確,也不代表內容真的合理。
例如:
20260230
2960
這兩組資料分別都是 8 位數和 4 位數,但實際上:
2 月 30 日不存在
29:60 也不是合法時間
所以今天的目標,就是在原本的格式驗證後面,再增加一層「實際日期時間驗證」。
整體流程變成:
使用者輸入資料
↓
檢查格式
↓
拆出年月日時分
↓
檢查日期是否存在
↓
檢查時間是否合理
↓
檢查是不是過去的時間
↓
全部通過才繼續
二、今天新增的程式邏輯
原本的 add.js 已經會取得使用者輸入的資料:
const title = interaction.options.getString('title');
const date = interaction.options.getString('date');
const time = interaction.options.getString('time');
接著先維持原本的 Regex 驗證:
const dateRegex = /^\d{8}$/;
const timeRegex = /^\d{4}$/;
const errors = [];
if (!dateRegex.test(date)) {
errors.push('日期格式錯誤,請輸入 8 位數日期,例如 20260903');
}
if (!timeRegex.test(time)) {
errors.push('時間格式錯誤,請輸入 4 位數時間,例如 1830');
}
if (errors.length > 0) {
await interaction.reply(errors.join('\n'));
return;
}
這一層只負責確認:
日期是不是 8 位數
時間是不是 4 位數
格式通過之後,我再把資料拆開:
const year = parseInt(date.slice(0, 4));
const month = parseInt(date.slice(4, 6));
const day = parseInt(date.slice(6, 8));
const hour = parseInt(time.slice(0, 2));
const minute = parseInt(time.slice(2, 4));
例如:
date = 20261005
會被拆成:
year = 2026
month = 10
day = 5
而:
time = 1830
則會被拆成:
hour = 18
minute = 30
這裡我也使用 parseInt(),把原本的字串轉成數字,因為後面要進行數值比較。
接著先檢查時間範圍:
if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
errors.push('時間不存在,請輸入正確的時間,例如 1830');
}
因為 24 小時制中:
hour 必須介於 0~23
minute 必須介於 0~59
所以像:
2960
就會被擋下來。
接著建立 JavaScript 的 Date:
const eventDate = new Date(
year,
month - 1,
day,
hour,
minute
);
這裡有一個要注意的地方:
JavaScript 的 Date 月份是從 0 開始計算。
也就是:
0 = 1 月
1 = 2 月
...
11 = 12 月
所以輸入的月份要寫成:
month - 1
接著檢查日期是否真的存在:
const isValidDate =
eventDate.getFullYear() === year &&
eventDate.getMonth() === month - 1 &&
eventDate.getDate() === day;
if (!isValidDate) {
errors.push('日期不存在,請輸入正確的日期');
}
這一步主要是為了解決像:
20260230
這種問題。
因為 JavaScript 的 Date 遇到超出範圍的日期時,有可能自動往後進位。
所以我不能只建立 Date,還需要再把建立後的年月日讀出來,跟使用者原本輸入的資料比對。
如果不一樣,就代表原本輸入的日期不存在。
最後再檢查是否為過去的時間:
const now = new Date();
if (eventDate <= now) {
errors.push('不能建立過去的行程');
}
這裡的 now 代表目前時間。
如果:
eventDate <= now
就代表使用者輸入的是現在或過去的時間,因此不允許建立。
完成所有檢查後,如果有任何錯誤,就一次回覆:
if (errors.length > 0) {
await interaction.reply(errors.join('\n'));
return;
}
如果完全沒有錯誤,才繼續顯示整理後的行程資訊:
const formattedDate =
`${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
const formattedTime =
`${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}`;
await interaction.reply(
`行程名稱:${title}\n日期:${formattedDate}\n時間:${formattedTime}`
);
三、今日修改的完整程式碼與測試結果
今天主要修改的是 commands/add.js:
async function handleAddCommand(interaction) {
const title = interaction.options.getString('title');
const date = interaction.options.getString('date');
const time = interaction.options.getString('time');
const dateRegex = /^\d{8}$/;
const timeRegex = /^\d{4}$/;
const errors = [];
if (!dateRegex.test(date)) {
errors.push('日期格式錯誤,請輸入 8 位數日期,例如 20260903');
}
if (!timeRegex.test(time)) {
errors.push('時間格式錯誤,請輸入 4 位數時間,例如 1830');
}
if (errors.length > 0) {
await interaction.reply(errors.join('\n'));
return;
}
const year = parseInt(date.slice(0, 4));
const month = parseInt(date.slice(4, 6));
const day = parseInt(date.slice(6, 8));
const hour = parseInt(time.slice(0, 2));
const minute = parseInt(time.slice(2, 4));
if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
errors.push('時間不存在,請輸入正確的時間,例如 1830');
}
const eventDate = new Date(
year,
month - 1,
day,
hour,
minute
);
const isValidDate =
eventDate.getFullYear() === year &&
eventDate.getMonth() === month - 1 &&
eventDate.getDate() === day;
if (!isValidDate) {
errors.push('日期不存在,請輸入正確的日期');
}
const now = new Date();
if (eventDate <= now) {
errors.push('不能建立過去的行程');
}
if (errors.length > 0) {
await interaction.reply(errors.join('\n'));
return;
}
const formattedDate =
`${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
const formattedTime =
`${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}`;
await interaction.reply(
`行程名稱:${title}\n日期:${formattedDate}\n時間:${formattedTime}`
);
}
module.exports = handleAddCommand;
這次我測試了幾種不同情況。
正常資料:
date:20261006
time:1830
可以正常顯示行程資訊。
不存在的日期:
date:20260230
time:1830
會顯示:
日期不存在,請輸入正確的日期
錯誤的時間:
date:20261006
time:2960
會顯示:
時間不存在,請輸入正確的時間,例如 1830
如果輸入已經過去的日期時間,也會顯示:
不能建立過去的行程
今天最大的收穫是理解到「格式正確」和「資料合理」是兩件不同的事情。
Regex 只能檢查輸入的外觀是不是符合規則,但如果要真的拿來建立行程,需要進一步確認日期存在、時間是否合理,而且時間點是在未來。