date 日期输入
<input type="date"> 是 HTML5 引入的日期选择控件,允许用户通过浏览器内置的日历控件选择一个具体的日期。该控件自动处理日期格式,提交的值统一为 YYYY-MM-DD 格式,极大地简化了日期输入的开发工作。
前置知识
阅读本节前,建议先了解:optgroup 分组下拉框
基础概念
什么是 date 输入
type="date" 输入框提供了一个专门用于选择日期的界面。与使用普通文本框让用户手动输入日期相比,date 输入具有以下优势:
- 内置日历控件:点击输入框弹出日历,用户通过点击选择日期
- 格式统一:无论用户所在地区如何设置,提交值始终为
YYYY-MM-DD - 自动验证:无法选择不存在的日期(如 2 月 30 日)
- 键盘友好:支持键盘方向键导航日期
- 移动端优化:在移动设备上显示原生日期选择器
浏览器支持
type="date" 在所有现代浏览器中均得到良好支持:
| 浏览器 | 支持情况 | 控件外观 |
|---|---|---|
| Chrome | ✅ 完整支持 | 日历弹出框 |
| Firefox | ✅ 完整支持 | 日历弹出框 |
| Safari | ✅ 支持(14.1+) | 日历弹出框 |
| Edge | ✅ 完整支持 | 日历弹出框 |
| Opera | ✅ 完整支持 | 日历弹出框 |
在不支持 type="date" 的浏览器中,控件会自动降级为普通文本输入框。
提交值格式
date 输入提交的值严格遵循 ISO 8601 日期格式:
YYYY-MM-DD例如:2025-07-14 表示 2025 年 7 月 14 日。
语法
基本用法
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>date 日期输入示例</title>
</head>
<body>
<h2>选择日期</h2>
<form>
<label for="birthday">出生日期:</label>
<input type="date" id="birthday" name="birthday">
<button type="submit">提交</button>
</form>
</body>
</html>设置默认值
通过 value 属性设置默认选中日期,格式必须为 YYYY-MM-DD:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>date 默认值示例</title>
</head>
<body>
<h2>默认选中今天</h2>
<form>
<label for="today">今天的日期:</label>
<!-- 设置默认值为今天 -->
<input type="date" id="today" name="today" value="2025-07-14">
<button type="submit">提交</button>
</form>
<script>
// 通过 JavaScript 动态设置默认值为当天日期
const dateInput = document.getElementById('today');
const today = new Date().toISOString().split('T')[0];
dateInput.value = today;
</script>
</body>
</html>min 和 max 属性
使用 min 和 max 属性限制可选日期范围:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>date 范围限制示例</title>
</head>
<body>
<h2>限制日期选择范围</h2>
<form>
<p>只能选择 2025 年内的日期:</p>
<label for="event-date">活动日期:</label>
<input
type="date"
id="event-date"
name="event_date"
min="2025-01-01"
max="2025-12-31"
>
<button type="submit">提交</button>
</form>
</body>
</html>| 属性 | 说明 | 格式 |
|---|---|---|
min | 最小可选日期 | YYYY-MM-DD |
max | 最大可选日期 | YYYY-MM-DD |
详细说明
日历控件交互
大多数浏览器在点击 date 输入框时会弹出日历控件,用户可以通过以下方式操作:
- 鼠标点击:直接点击日历上的日期数字
- 键盘导航:
↑/↓键在同一列上下移动←/→键在同一行左右移动PageUp/PageDown切换月份Home/End跳到月份的第一天 / 最后一天
- 手动输入:用户也可以直接在输入框中键入日期字符串
获取用户选择的日期
通过 JavaScript 可以读取和操作 date 输入的值:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>获取 date 值示例</title>
</head>
<body>
<h2>日期选择器</h2>
<label for="select-date">选择日期:</label>
<input type="date" id="select-date" name="select_date">
<p id="result">尚未选择日期</p>
<script>
const dateInput = document.getElementById('select-date');
const result = document.getElementById('result');
// 监听日期变化事件
dateInput.addEventListener('change', function () {
if (this.value) {
// value 是 "YYYY-MM-DD" 格式的字符串
const dateValue = this.value;
result.textContent = `您选择的日期是:${dateValue}`;
// 转换为 Date 对象进行进一步处理
const dateObj = new Date(dateValue + 'T00:00:00');
const year = dateObj.getFullYear();
const month = dateObj.getMonth() + 1;
const day = dateObj.getDate();
const weekDays = ['日', '一', '二', '三', '四', '五', '六'];
const weekDay = weekDays[dateObj.getDay()];
result.textContent += `(${year}年${month}月${day}日 星期${weekDay})`;
}
});
// 获取输入框关联的 Date 对象
dateInput.addEventListener('input', function () {
// valueAsDate 属性直接返回 Date 对象
const dateAsDate = this.valueAsDate;
if (dateAsDate) {
console.log('Date 对象:', dateAsDate);
console.log('时间戳:', dateAsDate.getTime());
}
});
</script>
</body>
</html>valueAsDate 属性
<input type="date"> 专门提供了 valueAsDate 属性,可以直接获取或设置 Date 对象:
javascript
const dateInput = document.getElementById('my-date');
// 读取 Date 对象
const selectedDate = dateInput.valueAsDate;
console.log(selectedDate.getFullYear()); // 获取年份
// 设置 Date 对象
dateInput.valueAsDate = new Date(2025, 11, 25); // 设置为 2025-12-25步进值 step
step 属性控制日期选择的粒度:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>date step 示例</title>
</head>
<body>
<h2>日期步进控制</h2>
<form>
<p>只能选择每周一(step=7):</p>
<label for="weekly">每周一日期:</label>
<!-- min 设为某个周一,step=7 表示每隔 7 天可选 -->
<input
type="date"
id="weekly"
name="weekly_date"
min="2025-01-06"
step="7"
value="2025-01-06"
>
<button type="submit">提交</button>
</form>
</body>
</html>| step 值 | 含义 |
|---|---|
1(默认) | 每天都可选 |
7 | 每隔 7 天可选(每周固定) |
30 | 大约每月可选 |
any | 不限制步进 |
表单提交数据
当用户提交包含 date 输入的表单时,数据以 URL 编码形式发送:
birthday=2025-07-14实战示例
生日选择器
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>生日选择器</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
max-width: 600px;
margin: 40px auto;
padding: 0 20px;
}
.form-group {
margin-bottom: 16px;
}
label {
display: block;
margin-bottom: 6px;
font-weight: 600;
}
input[type="date"] {
padding: 8px 12px;
border: 2px solid #ddd;
border-radius: 6px;
font-size: 16px;
width: 100%;
max-width: 300px;
box-sizing: border-box;
}
input[type="date"]:focus {
border-color: #4a90d9;
outline: none;
box-shadow: 0 0 0 3px rgba(74, 144, 217, 0.2);
}
.age-display {
margin-top: 12px;
padding: 12px;
background: #f0f7ff;
border-radius: 6px;
display: none;
}
button {
padding: 10px 24px;
background: #4a90d9;
color: #fff;
border: none;
border-radius: 6px;
font-size: 16px;
cursor: pointer;
}
button:hover {
background: #357abd;
}
</style>
</head>
<body>
<h2>🎂 生日选择器</h2>
<form id="birthday-form">
<div class="form-group">
<label for="birthday">请选择您的出生日期:</label>
<input
type="date"
id="birthday"
name="birthday"
max="2025-07-14"
required
>
</div>
<button type="submit">计算年龄</button>
</form>
<div class="age-display" id="age-display">
<p id="age-text"></p>
<p id="constellation-text"></p>
</div>
<script>
const form = document.getElementById('birthday-form');
const birthdayInput = document.getElementById('birthday');
const ageDisplay = document.getElementById('age-display');
const ageText = document.getElementById('age-text');
const constellationText = document.getElementById('constellation-text');
form.addEventListener('submit', function (e) {
e.preventDefault();
const birthday = new Date(birthdayInput.value + 'T00:00:00');
const today = new Date();
// 计算年龄
let age = today.getFullYear() - birthday.getFullYear();
const monthDiff = today.getMonth() - birthday.getMonth();
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthday.getDate())) {
age--;
}
// 计算星座
const month = birthday.getMonth() + 1;
const day = birthday.getDate();
const constellations = [
{ name: '摩羯座', start: [1, 1], end: [1, 19] },
{ name: '水瓶座', start: [1, 20], end: [2, 18] },
{ name: '双鱼座', start: [2, 19], end: [3, 20] },
{ name: '白羊座', start: [3, 21], end: [4, 19] },
{ name: '金牛座', start: [4, 20], end: [5, 20] },
{ name: '双子座', start: [5, 21], end: [6, 21] },
{ name: '巨蟹座', start: [6, 22], end: [7, 22] },
{ name: '狮子座', start: [7, 23], end: [8, 22] },
{ name: '处女座', start: [8, 23], end: [9, 22] },
{ name: '天秤座', start: [9, 23], end: [10, 23] },
{ name: '天蝎座', start: [10, 24], end: [11, 22] },
{ name: '射手座', start: [11, 23], end: [12, 21] },
{ name: '摩羯座', start: [12, 22], end: [12, 31] },
];
let constellation = '';
for (const c of constellations) {
if (
(month === c.start[0] && day >= c.start[1]) ||
(month === c.end[0] && day <= c.end[1])
) {
constellation = c.name;
break;
}
}
// 显示结果
ageDisplay.style.display = 'block';
ageText.textContent = `您的年龄是 ${age} 岁`;
constellationText.textContent = `您的星座是 ${constellation}`;
});
</script>
</body>
</html>酒店预订日期范围
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>酒店预订日期范围</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
max-width: 700px;
margin: 40px auto;
padding: 0 20px;
}
.date-range {
display: flex;
gap: 16px;
align-items: center;
}
.form-group {
margin-bottom: 16px;
}
label {
display: block;
margin-bottom: 6px;
font-weight: 600;
}
input[type="date"] {
padding: 8px 12px;
border: 2px solid #ddd;
border-radius: 6px;
font-size: 16px;
}
input[type="date"]:focus {
border-color: #28a745;
outline: none;
}
.nights {
margin-top: 12px;
padding: 12px;
background: #d4edda;
border-radius: 6px;
}
.error {
color: #dc3545;
margin-top: 8px;
display: none;
}
</style>
</head>
<body>
<h2>酒店预订</h2>
<form id="booking-form">
<div class="form-group">
<label for="checkin">入住日期:</label>
<input type="date" id="checkin" name="checkin" required>
</div>
<div class="form-group">
<label for="checkout">退房日期:</label>
<input type="date" id="checkout" name="checkout" required>
</div>
<p class="error" id="error-msg"></p>
<div class="nights" id="nights-display" style="display: none;">
<p id="nights-text"></p>
</div>
<button type="submit">预订</button>
</form>
<script>
const checkinInput = document.getElementById('checkin');
const checkoutInput = document.getElementById('checkout');
const errorMsg = document.getElementById('error-msg');
const nightsDisplay = document.getElementById('nights-display');
const nightsText = document.getElementById('nights-text');
// 设置入住日期的最小值为今天
const today = new Date().toISOString().split('T')[0];
checkinInput.min = today;
checkinInput.value = today;
// 入住日期变化时,更新退房日期的最小值
checkinInput.addEventListener('change', function () {
// 退房日期至少晚于入住日期一天
const nextDay = new Date(this.value);
nextDay.setDate(nextDay.getDate() + 1);
checkoutInput.min = nextDay.toISOString().split('T')[0];
// 如果退房日期早于新的最小值,自动调整
if (checkoutInput.value && checkoutInput.value <= this.value) {
checkoutInput.value = nextDay.toISOString().split('T')[0];
}
updateNights();
});
checkoutInput.addEventListener('change', updateNights);
function updateNights() {
if (checkinInput.value && checkoutInput.value) {
const checkin = new Date(checkinInput.value);
const checkout = new Date(checkoutInput.value);
if (checkout <= checkin) {
errorMsg.textContent = '退房日期必须晚于入住日期';
errorMsg.style.display = 'block';
nightsDisplay.style.display = 'none';
} else {
errorMsg.style.display = 'none';
const nights = Math.ceil((checkout - checkin) / (1000 * 60 * 60 * 24));
nightsDisplay.style.display = 'block';
nightsText.textContent = `共入住 ${nights} 晚`;
}
}
}
</script>
</body>
</html>注意事项
时区问题
type="date" 不包含时间信息,因此不涉及时区转换问题。但需要注意以下场景:
javascript
// value 属性返回的是 "YYYY-MM-DD" 字符串,不含时区信息
const dateStr = dateInput.value; // "2025-07-14"
// valueAsDate 返回的是本地时区的午夜 Date 对象
const dateObj = dateInput.valueAsDate; // 本地时间 2025-07-14T00:00:00
// 转换为 UTC 时要注意
console.log(dateObj.toISOString()); // 可能显示为前一天的 UTC 时间(东八区)移动端兼容性
在移动设备上,type="date" 会触发系统原生的日期选择器,体验优于桌面浏览器:
- iOS:底部滑出的滚轮式日期选择器
- Android:Material Design 风格的日历控件
降级处理
对于不支持 type="date" 的老旧浏览器,控件会降级为普通文本输入框。可以通过 JavaScript 检测并增强:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>date 降级检测</title>
</head>
<body>
<h2>日期输入降级检测</h2>
<form>
<label for="start-date">开始日期:</label>
<input type="date" id="start-date" name="start_date">
<p id="fallback-hint" style="color: #999; font-size: 14px; display: none;">
请输入日期,格式:YYYY-MM-DD(例如:2025-07-14)
</p>
</form>
<script>
const dateInput = document.getElementById('start-date');
const fallbackHint = document.getElementById('fallback-hint');
// 检测浏览器是否支持 type="date"
const testInput = document.createElement('input');
testInput.setAttribute('type', 'date');
const isDateSupported = testInput.type === 'date';
if (!isDateSupported) {
// 浏览器不支持 date 控件,显示手动输入提示
fallbackHint.style.display = 'block';
dateInput.placeholder = 'YYYY-MM-DD';
}
</script>
</body>
</html>readonly 和 disabled
html
<!-- 只读:用户不能修改,但值会随表单提交 -->
<input type="date" name="created_date" value="2025-07-14" readonly>
<!-- 禁用:用户不能修改,值也不会提交 -->
<input type="date" name="disabled_date" value="2025-07-14" disabled>最佳实践
- 始终提供 label 标签:确保每个
date输入都有明确的<label>关联 - 合理设置 min/max:根据业务需求限制可选日期范围
- 使用 JavaScript 动态计算:对于"今天"等动态值,使用 JavaScript 设置而非硬编码
- 处理降级场景:在不支持原生控件的浏览器中提供替代方案或明确提示
- 结合 required 验证:当日期为必填项时,添加
required属性 - 考虑本地化需求:日期显示格式可通过 CSS 控制部分样式,但提交值始终为 ISO 格式
- 提供日期范围联动:涉及起止日期时,确保结束日期自动跟随开始日期变化
下一节
继续学习:time 时间输入