Skip to content

datetime-local 日期时间输入

<input type="datetime-local"> 是 HTML5 引入的日期时间组合选择控件,允许用户在同一个输入框中选择日期和时间。该控件将 datetime 的功能合二为一,提交值格式为 YYYY-MM-DDTHH:MM,适用于需要同时选择日期和时间的场景。

前置知识

阅读本节前,建议先了解:time 时间输入

基础概念

什么是 datetime-local 输入

type="datetime-local" 输入框提供了日期和时间的组合选择界面。与分别使用 datetime 两个控件相比,datetime-local 的特点包括:

  • 一体化控件:日期和时间在同一个控件中完成选择
  • 紧凑界面:减少表单中的控件数量
  • 格式统一:提交值为 YYYY-MM-DDTHH:MMYYYY-MM-DDTHH:MM:SS
  • 不含时区信息:名称中的 "local" 表示使用本地时区,不包含 UTC 偏移量
  • 移动端友好:在移动设备上提供原生的日期时间选择器

与旧版 datetime 的区别

HTML5 早期规范中曾定义 <input type="datetime">,但已被废弃。两者的关键区别:

特性datetime(已废弃)datetime-local(当前标准)
时区包含 UTC 时区偏移不含时区信息(本地时间)
格式YYYY-MM-DDTHH:MMZYYYY-MM-DDTHH:MM
浏览器支持几乎无浏览器实现现代浏览器均支持
状态从规范中移除活跃标准

浏览器支持

浏览器支持情况控件外观
Chrome✅ 完整支持日历 + 时间选择
Firefox✅ 支持(93+)日历 + 时间输入
Safari✅ 支持(14.1+)日历 + 时间滚轮
Edge✅ 完整支持日历 + 时间选择
Opera✅ 完整支持日历 + 时间选择

提交值格式

YYYY-MM-DDTHH:MM        —— 日期和分钟
YYYY-MM-DDTHH:MM:SS     —— 包含秒

例如:2025-07-14T14:30 表示本地时间 2025 年 7 月 14 日 14:30。

语法

基本用法

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>datetime-local 基本示例</title>
</head>
<body>
    <h2>选择日期和时间</h2>
    <form>
        <label for="event-time">活动时间:</label>
        <input type="datetime-local" id="event-time" name="event_time">
        <button type="submit">提交</button>
    </form>
</body>
</html>

设置默认值

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>datetime-local 默认值</title>
</head>
<body>
    <h2>设置默认日期时间</h2>
    <form>
        <label for="deadline">截止时间:</label>
        <!-- 设置默认值为 2025-08-01 18:00 -->
        <input
            type="datetime-local"
            id="deadline"
            name="deadline"
            value="2025-08-01T18:00"
        >
        <button type="submit">保存</button>
    </form>
</body>
</html>

min 和 max 属性

限制可选日期时间范围:

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>datetime-local 范围限制</title>
</head>
<body>
    <h2>预约时间范围</h2>
    <form>
        <label for="appointment">预约时间:</label>
        <input
            type="datetime-local"
            id="appointment"
            name="appointment"
            min="2025-07-15T09:00"
            max="2025-12-31T18:00"
            required
        >
        <button type="submit">提交预约</button>
    </form>
</body>
</html>
属性说明格式
min最小可选日期时间YYYY-MM-DDTHH:MM
max最大可选日期时间YYYY-MM-DDTHH:MM

详细说明

step 步进控制

step 属性的单位为秒,控制时间精度:

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>datetime-local step 示例</title>
</head>
<body>
    <h2>步进控制</h2>
    <form>
        <div>
            <label for="dt-minute">分钟精度(默认):</label>
            <input type="datetime-local" id="dt-minute" name="dt_minute" step="60">
        </div>
        <div>
            <label for="dt-second">秒级精度:</label>
            <input type="datetime-local" id="dt-second" name="dt_second" step="1">
        </div>
        <div>
            <label for="dt-hour">整点精度(1小时=3600秒):</label>
            <input type="datetime-local" id="dt-hour" name="dt_hour" step="3600">
        </div>
    </form>
</body>
</html>
step 值(秒)含义
11 秒精度
60(默认)1 分钟精度
90015 分钟精度
36001 小时精度
864001 天精度
any不限制步进

valueAsDate 和 valueAsNumber

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>datetime-local 值属性</title>
</head>
<body>
    <h2>获取日期时间值</h2>
    <label for="my-dt">选择日期时间:</label>
    <input type="datetime-local" id="my-dt" name="my_dt" value="2025-07-14T14:30">

    <div id="output"></div>

    <script>
        const dtInput = document.getElementById('my-dt');
        const output = document.getElementById('output');

        dtInput.addEventListener('input', function () {
            // value 字符串
            const str = this.value; // "2025-07-14T14:30"

            // valueAsDate — 返回本地时区的 Date 对象
            const date = this.valueAsDate;

            // valueAsNumber — 返回 Unix 时间戳(毫秒)
            const timestamp = this.valueAsNumber;

            if (date) {
                const year = date.getFullYear();
                const month = date.getMonth() + 1;
                const day = date.getDate();
                const hour = date.getHours();
                const minute = date.getMinutes();

                output.innerHTML = `
                    <p>value: ${str}</p>
                    <p>可读格式: ${year}年${month}月${day}日 ${hour}:${minute.toString().padStart(2, '0')}</p>
                    <p>Unix 时间戳: ${timestamp}</p>
                `;
            }
        });
    </script>
</body>
</html>

JavaScript 动态设置当前时间

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>动态设置 datetime-local</title>
</head>
<body>
    <h2>动态设置日期时间</h2>
    <form>
        <label for="now">当前日期时间:</label>
        <input type="datetime-local" id="now" name="now">
        <label for="tomorrow">明天此刻:</label>
        <input type="datetime-local" id="tomorrow" name="tomorrow">
    </form>

    <script>
        // 获取当前本地时间的 datetime-local 格式字符串
        function toLocalISOString(date) {
            const offset = date.getTimezoneOffset();
            const local = new Date(date.getTime() - offset * 60000);
            return local.toISOString().slice(0, 16);
        }

        // 设置当前时间
        const nowInput = document.getElementById('now');
        nowInput.value = toLocalISOString(new Date());

        // 设置明天同一时间
        const tomorrow = new Date();
        tomorrow.setDate(tomorrow.getDate() + 1);
        document.getElementById('tomorrow').value = toLocalISOString(tomorrow);
    </script>
</body>
</html>

与 date + time 组合的对比

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>datetime-local vs date + time</title>
</head>
<body>
    <h2>两种方式对比</h2>

    <h3>方式一:datetime-local(一体化)</h3>
    <form>
        <label for="dt">出发时间:</label>
        <input type="datetime-local" id="dt" name="departure_dt" required>
        <button type="submit">提交</button>
    </form>

    <h3>方式二:date + time(分离)</h3>
    <form>
        <label for="d">出发日期:</label>
        <input type="date" id="d" name="departure_date" required>
        <br>
        <label for="t">出发时间:</label>
        <input type="time" id="t" name="departure_time" required>
        <button type="submit">提交</button>
    </form>

    <table border="1" cellpadding="8" style="margin-top: 16px;">
        <tr>
            <th>对比维度</th>
            <th>datetime-local</th>
            <th>date + time</th>
        </tr>
        <tr>
            <td>控件数量</td>
            <td>1 个</td>
            <td>2 个</td>
        </tr>
        <tr>
            <td>提交数据</td>
            <td>departure_dt=2025-07-14T14:30</td>
            <td>departure_date=2025-07-14&departure_time=14:30</td>
        </tr>
        <tr>
            <td>用户操作</td>
            <td>一步完成</td>
            <td>两步完成</td>
        </tr>
        <tr>
            <td>灵活性</td>
            <td>较低</td>
            <td>较高(可分别设置 min/max)</td>
        </tr>
        <tr>
            <td>适用场景</td>
            <td>简单日期时间选择</td>
            <td>需要独立控制日期和时间范围</td>
        </tr>
    </table>
</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;
        }
        .form-group { margin-bottom: 16px; }
        label { display: block; margin-bottom: 6px; font-weight: 600; }
        input, textarea {
            width: 100%;
            max-width: 400px;
            padding: 8px 12px;
            border: 2px solid #ddd;
            border-radius: 6px;
            font-size: 16px;
            box-sizing: border-box;
        }
        input:focus, textarea:focus {
            border-color: #e67e22;
            outline: none;
        }
        .preview {
            margin-top: 20px;
            padding: 16px;
            background: #fef5e7;
            border-radius: 8px;
            display: none;
        }
        button {
            padding: 10px 24px;
            background: #e67e22;
            color: #fff;
            border: none;
            border-radius: 6px;
            cursor: pointer;
        }
        button:hover { background: #d35400; }
    </style>
</head>
<body>
    <h2>发布活动</h2>
    <form id="event-form">
        <div class="form-group">
            <label for="event-name">活动名称:</label>
            <input type="text" id="event-name" name="event_name" required>
        </div>
        <div class="form-group">
            <label for="start-dt">开始时间:</label>
            <input type="datetime-local" id="start-dt" name="start_dt" required>
        </div>
        <div class="form-group">
            <label for="end-dt">结束时间:</label>
            <input type="datetime-local" id="end-dt" name="end_dt" required>
        </div>
        <div class="form-group">
            <label for="event-desc">活动描述:</label>
            <textarea id="event-desc" name="description" rows="3"></textarea>
        </div>
        <button type="button" id="preview-btn">预览</button>
        <button type="submit">发布</button>
    </form>

    <div class="preview" id="preview">
        <h3>活动预览</h3>
        <p id="preview-content"></p>
    </div>

    <script>
        const startDt = document.getElementById('start-dt');
        const endDt = document.getElementById('end-dt');
        const preview = document.getElementById('preview');
        const previewContent = document.getElementById('preview-content');

        // 设置开始时间最小值为当前
        function toLocalISOString(date) {
            const offset = date.getTimezoneOffset();
            const local = new Date(date.getTime() - offset * 60000);
            return local.toISOString().slice(0, 16);
        }
        startDt.min = toLocalISOString(new Date());

        // 开始时间变化时,更新结束时间的最小值
        startDt.addEventListener('change', function () {
            const start = new Date(this.value);
            // 结束时间至少比开始时间晚 30 分钟
            start.setMinutes(start.getMinutes() + 30);
            endDt.min = toLocalISOString(start);
            if (endDt.value && new Date(endDt.value) <= new Date(this.value)) {
                endDt.value = toLocalISOString(start);
            }
        });

        // 预览功能
        document.getElementById('preview-btn').addEventListener('click', function () {
            const name = document.getElementById('event-name').value;
            const desc = document.getElementById('event-desc').value;
            if (startDt.value && endDt.value) {
                preview.style.display = 'block';
                previewContent.innerHTML = `
                    <strong>${name}</strong><br>
                    开始:${startDt.value.replace('T', ' ')}<br>
                    结束:${endDt.value.replace('T', ' ')}<br>
                    ${desc ? '描述:' + desc : ''}
                `;
            }
        });
    </script>
</body>
</html>

注意事项

时区问题

datetime-local 不包含时区信息,这既是优点也是潜在陷阱:

javascript
// 假设用户在北京时间(UTC+8)选择了 2025-07-14T14:30
const dtInput = document.getElementById('my-dt');

// value 字符串不含时区
console.log(dtInput.value); // "2025-07-14T14:30"

// valueAsDate 返回本地时区的 Date 对象
const date = dtInput.valueAsDate;
console.log(date.toISOString()); // "2025-07-14T06:30:00.000Z"(UTC 时间)
console.log(date.toString());    // 本地时间的完整字符串

WARNING

如果需要在服务端处理时区,建议服务端约定时区规则,或配合 <select> 单独提供时区选择。

移动端体验

在 iOS 和 Android 上,datetime-local 触发原生日期时间选择器,体验流畅。但部分老旧 Android 设备可能降级为文本输入。

设置默认值为当前时间的技巧

JavaScript 的 Date.toISOString() 返回 UTC 时间,直接使用会导致时区偏差:

javascript
// 错误方式(会差 8 小时)
input.value = new Date().toISOString().slice(0, 16);

// 正确方式(转换为本地时间)
function toLocalISOString(date) {
    const offset = date.getTimezoneOffset();
    const local = new Date(date.getTime() - offset * 60000);
    return local.toISOString().slice(0, 16);
}
input.value = toLocalISOString(new Date());

readonly 和 disabled

html
<!-- 只读:显示但不能编辑,值会提交 -->
<input type="datetime-local" name="created_at" value="2025-07-14T10:00" readonly>

<!-- 禁用:灰色显示,值不会提交 -->
<input type="datetime-local" name="expired_at" value="2025-07-14T10:00" disabled>

最佳实践

  1. 选择合适的控件:简单日期时间选择用 datetime-local,需要精细控制用 date + time 分离
  2. 动态设置 min:使用 JavaScript 设置最小值为当前时间,避免选择过去的时间
  3. 正确处理时区:获取/设置 valueAsDate 时注意时区转换
  4. 提供预览:日期时间对用户来说不够直观,提供可读的预览信息
  5. 设置合理步进:根据场景选择精度,如日程安排用 30 分钟,航班时刻用 5 分钟
  6. 添加说明文字:在控件旁注明时间格式和时区信息

下一节

继续学习:month 月份输入

参考链接