Skip to content

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 属性

使用 minmax 属性限制可选日期范围:

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 输入框时会弹出日历控件,用户可以通过以下方式操作:

  1. 鼠标点击:直接点击日历上的日期数字
  2. 键盘导航
    • / 键在同一列上下移动
    • / 键在同一行左右移动
    • PageUp / PageDown 切换月份
    • Home / End 跳到月份的第一天 / 最后一天
  3. 手动输入:用户也可以直接在输入框中键入日期字符串

获取用户选择的日期

通过 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>

最佳实践

  1. 始终提供 label 标签:确保每个 date 输入都有明确的 <label> 关联
  2. 合理设置 min/max:根据业务需求限制可选日期范围
  3. 使用 JavaScript 动态计算:对于"今天"等动态值,使用 JavaScript 设置而非硬编码
  4. 处理降级场景:在不支持原生控件的浏览器中提供替代方案或明确提示
  5. 结合 required 验证:当日期为必填项时,添加 required 属性
  6. 考虑本地化需求:日期显示格式可通过 CSS 控制部分样式,但提交值始终为 ISO 格式
  7. 提供日期范围联动:涉及起止日期时,确保结束日期自动跟随开始日期变化

下一节

继续学习:time 时间输入

参考链接