<input type="date">

type="date"<input> 元素创建允许用户输入日期的输入字段,可以使用验证输入的文本框或特殊的日期选择器界面。

¥<input> elements of type="date" create input fields that let the user enter a date, either with a textbox that validates the input or a special date picker interface.

结果值包括年、月和日,但不包括时间。timedatetime-local 输入类型支持时间和日期+时间输入。

¥The resulting value includes the year, month, and day, but not the time. The time and datetime-local input types support time and date+time input.

Try it

输入 UI 通常因浏览器而异;详细信息请参见 浏览器兼容性。在不受支持的浏览器中,该控件会正常降级到 <input type="text">

¥The input UI generally varies from browser to browser; see Browser compatibility for further details. In unsupported browsers, the control degrades gracefully to <input type="text">.

¥Value

表示输入中输入的日期的字符串。日期按照 日期字符串格式 进行格式化。

¥A string representing the date entered in the input. The date is formatted according to Date strings format.

你可以在 value 属性内使用日期为输入设置默认值,如下所示:

¥You can set a default value for the input with a date inside the value attribute, like so:

html
<input type="date" value="2017-06-01" />

注意:显示的日期格式将与实际的 value 不同 - 显示的日期根据用户浏览器的区域设置进行格式化,但解析的 value 始终采用 yyyy-mm-dd 格式。

¥Note: The displayed date format will differ from the actual value — the displayed date is formatted based on the locale of the user's browser, but the parsed value is always formatted yyyy-mm-dd.

你可以使用 HTMLInputElement valuevalueAsNumber 属性在 JavaScript 中获取和设置日期值。例如:

¥You can get and set the date value in JavaScript with the HTMLInputElement value and valueAsNumber properties. For example:

js
const dateControl = document.querySelector('input[type="date"]');
dateControl.value = "2017-06-01";
console.log(dateControl.value); // prints "2017-06-01"
console.log(dateControl.valueAsNumber); // prints 1496275200000, a JavaScript timestamp (ms)

此代码查找 typedate 的第一个 <input> 元素,并将其值设置为 2017-06-01(2017 年 6 月 1 日)。然后它以字符串和数字格式读回该值。

¥This code finds the first <input> element whose type is date, and sets its value to 2017-06-01 (June 1st, 2017). It then reads that value back in string and number formats.

附加属性

¥Additional attributes

所有 <input> 元素共有的属性也适用于 date 输入,但可能不会影响其表示。例如 sizeplaceholder 可能不起作用。date 输入具有以下附加属性。

¥The attributes common to all <input> elements apply to the date inputs as well, but might not influence its presentation. For example size and placeholder might not work. date inputs have the following additional attributes.

max

最晚接受日期。如果元素中输入的 value 之后出现,则该元素失败 约束验证。如果 max 属性的值不是 yyyy-mm-dd 格式的可能日期字符串,则该元素没有最大日期值。

¥The latest date to accept. If the value entered into the element occurs afterward, the element fails constraint validation. If the value of the max attribute isn't a possible date string in the format yyyy-mm-dd, then the element has no maximum date value.

如果同时设置了 maxmin 属性,则该值必须是晚于或等于 min 属性中的日期字符串。

¥If both the max and min attributes are set, this value must be a date string later than or equal to the one in the min attribute.

min

最早接受日期。如果元素中输入的 value 提前出现,则该元素失败 约束验证。如果 min 属性的值不是 yyyy-mm-dd 格式的可能日期字符串,则该元素没有最小日期值。

¥The earliest date to accept. If the value entered into the element occurs beforehand, the element fails constraint validation. If the value of the min attribute isn't a possible date string in the format yyyy-mm-dd, then the element has no minimum date value.

如果同时设置了 maxmin 属性,则该值必须是早于或等于 max 属性中的日期字符串。

¥If both the max and min attributes are set, this value must be a date string earlier than or equal to the one in the max attribute.

step

step 属性是一个数字,指定值必须遵守的粒度,或者是特殊值 any,如下所述。只有等于步进基础的值(如果指定则为 min,否则为 value,如果未提供则为适当的默认值)才有效。

¥The step attribute is a number that specifies the granularity that the value must adhere to, or the special value any, which is described below. Only values which are equal to the basis for stepping (min if specified, value otherwise, and an appropriate default value if neither of those is provided) are valid.

字符串值 any 意味着不暗示任何步进,并且允许任何值(除非其他约束,例如 minmax)。

¥A string value of any means that no stepping is implied, and any value is allowed (barring other constraints, such as min and max).

注意:当用户输入的数据不符合步进配置时,user agent 可能会四舍五入到最接近的有效值,当有两个同样接近的选项时,优先选择正方向的数字。

¥Note: When the data entered by the user doesn't adhere to the stepping configuration, the user agent may round to the nearest valid value, preferring numbers in the positive direction when there are two equally close options.

对于 date 输入,step 的值以天为单位给出;并被视为等于 86,400,000 乘以 step 值的毫秒数(基础数值以毫秒为单位)。step 默认值为 1,表示 1 天。

¥For date inputs, the value of step is given in days; and is treated as a number of milliseconds equal to 86,400,000 times the step value (the underlying numeric value is in milliseconds). The default value of step is 1, indicating 1 day.

注意:将 any 指定为 step 的值与 date 输入的 1 具有相同的效果。

¥Note: Specifying any as the value for step has the same effect as 1 for date inputs.

使用日期输入

¥Using date inputs

日期输入提供了一个用于选择日期的简单界面,并且它们规范了发送到服务器的数据格式,无论用户的区域设置如何。

¥Date inputs provide an easy interface for choosing dates, and they normalize the data format sent to the server regardless of the user's locale.

在本节中,我们将介绍 <input type="date"> 的基本用法和更复杂的用法。

¥In this section, we'll look at basic and then more complex uses of <input type="date">.

日期的基本用途

¥Basic uses of date

<input type="date"> 最简单的用法是将一个 <input> 与其 <label> 结合起来,如下所示:

¥The simplest use of <input type="date"> involves one <input> combined with its <label>, as seen below:

html
<form action="https://example.com">
  <label>
    Enter your birthday:
    <input type="date" name="bday" />
  </label>

  <p><button>Submit</button></p>
</form>

此 HTML 将在 bdayhttps://example.com 键下提交输入的日期 — 从而生成类似 https://example.com/?bday=1955-06-08 的 URL。

¥This HTML submits the entered date under the key bday to https://example.com — resulting in a URL like https://example.com/?bday=1955-06-08.

设置最大和最小日期

¥Setting maximum and minimum dates

你可以使用 minmax 属性来限制用户可以选择的日期。在以下示例中,我们设置最小日期为 2017-04-01,最大日期为 2017-04-30

¥You can use the min and max attributes to restrict the dates that can be chosen by the user. In the following example, we set a minimum date of 2017-04-01 and a maximum date of 2017-04-30:

html
<form>
  <label>
    Choose your preferred party date:
    <input type="date" name="party" min="2017-04-01" max="2017-04-30" />
  </label>
</form>

结果是只能选择 2017 年 4 月的日期 - 文本框的月份和年份部分将不可编辑,并且无法在选择器小部件中选择 2017 年 4 月以外的日期。

¥The result is that only days in April 2017 can be selected — the month and year parts of the textbox will be uneditable, and dates outside April 2017 can't be selected in the picker widget.

注意:你应该能够使用 step 属性来改变每次日期增加时跳跃的天数(例如,仅使星期六可选)。然而,在撰写本文时,这似乎还没有在任何实现中。

¥Note: You should be able to use the step attribute to vary the number of days jumped each time the date is incremented (e.g. to only make Saturdays selectable). However, this does not seem to be in any implementation at the time of writing.

控制输入大小

¥Controlling input size

<input type="date"> 不支持 size 等表单大小调整属性。首选 CSS 来确定尺码。

¥<input type="date"> doesn't support form sizing attributes such as size. Prefer CSS for sizing it.

验证

¥Validation

默认情况下,<input type="date"> 不会验证超出其格式的输入值。这些界面通常不允许你输入任何非日期的内容(这很有帮助),但你可以将该字段留空或在浏览器中输入无效日期,其中输入会回退到类型 text(例如 4 月 32 日) 。

¥By default, <input type="date"> doesn't validate the entered value beyond its format. The interfaces generally don't let you enter anything that isn't a date — which is helpful — but you can leave the field empty or enter an invalid date in browsers where the input falls back to type text (like the 32nd of April).

如果你使用 minmax 来限制可用日期(请参阅 设置最大和最小日期),则当你尝试提交超出范围的日期时,支持的浏览器将显示错误。但是,如果用户的设备不完全支持日期选择器,你需要仔细检查提交的结果,以确保该值在这些日期内。

¥If you use min and max to restrict the available dates (see Setting maximum and minimum dates), supporting browsers will display an error if you try to submit a date that is out of bounds. However, you'll need to double-check the submitted results to ensure the value is within these dates, if the date picker isn't fully supported on the user's device.

你还可以使用 required 属性强制填写日期 - 如果你尝试提交空日期字段,则会显示错误。这应该适用于大多数浏览器,即使它们回退到文本输入。

¥You can also use the required attribute to make filling in the date mandatory — an error will be displayed if you try to submit an empty date field. This should work in most browsers, even if they fall back to a text input.

让我们看一个最小和最大日期的示例,并且还设置了一个必填字段:

¥Let's look at an example of minimum and maximum dates, and also made a field required:

html
<form>
  <label>
    Choose your preferred party date (required, April 1st to 20th):
    <input
      type="date"
      name="party"
      min="2017-04-01"
      max="2017-04-20"
      required />
    <span class="validity"></span>
  </label>

  <p>
    <button>Submit</button>
  </p>
</form>

如果你尝试提交日期不完整(或日期超出设定范围)的表单,浏览器会显示错误。现在尝试使用示例:

¥If you try to submit the form with an incomplete date (or with a date outside the set bounds), the browser displays an error. Try playing with the example now:

这是上面示例中使用的 CSS。我们利用 :valid:invalid pseudo-elements 根据当前值是否有效在输入旁边添加一个图标。我们必须将图标放在输入旁边的 <span> 上,而不是输入本身,因为在 Chrome 中,至少输入生成的内容放置在表单控件内,并且无法有效设置样式或显示。

¥Here's the CSS used in the above example. We make use of the :valid and :invalid pseudo-elements to add an icon next to the input, based on whether the current value is valid. We had to put the icon on a <span> next to the input, not on the input itself, because in Chrome at least the input's generated content is placed inside the form control, and can't be styled or shown effectively.

css
label {
  display: flex;
  align-items: center;
}

span::after {
  padding-left: 5px;
}

input:invalid + span::after {
  content: "✖";
}

input:valid + span::after {
  content: "✓";
}

警告:客户端表单验证不能替代服务器上的验证。有人很容易修改 HTML,或者完全绕过你的 HTML 并将数据直接提交到你的服务器。如果你的服务器无法验证接收到的数据,则可能会因格式错误、太大、类型错误等数据而遭受灾难。

¥Warning: Client-side form validation is no substitute for validating on the server. It's easy for someone to modify the HTML, or bypass your HTML entirely and submit the data directly to your server. If your server fails to validate the received data, disaster could strike with data that is badly-formatted, too large, of the wrong type, etc.

处理浏览器支持

¥Handling browser support

不支持此输入类型的浏览器会优雅地降级为文本输入,但这会在用户界面(提供的控件不同)和数据处理的一致性方面产生问题。

¥Browsers that don't support this input type gracefully degrade to a text input, but this creates problems in consistency of user interface (the presented controls are different) and data handling.

第二个问题更为严重;如果支持日期输入,该值将标准化为 yyyy-mm-dd 格式。但是对于文本输入,浏览器无法识别日期应该采用什么格式,而且人们书写日期的格式有很多种。例如:

¥The second problem is the more serious one; with date input supported, the value is normalized to the format yyyy-mm-dd. But with a text input, the browser has no recognition of what format the date should be in, and there are many formats in which people write dates. For example:

  • ddmmyyyy
  • dd/mm/yyyy
  • mm/dd/yyyy
  • dd-mm-yyyy
  • mm-dd-yyyy
  • Month dd, yyyy

解决此问题的一种方法是日期输入中的 pattern 属性。即使日期选择器不使用它,文本输入后备也会使用它。例如,尝试在不支持的浏览器中查看以下内容:

¥One way around this is the pattern attribute on your date input. Even though the date picker doesn't use it, the text input fallback will. For example, try viewing the following in an unsupporting browser:

html
<form>
  <label>
    Enter your birthday:
    <input type="date" name="bday" required pattern="\d{4}-\d{2}-\d{2}" />
    <span class="validity"></span>
  </label>
  <p>
    <button>Submit</button>
  </p>
</form>

提交后,如果你的输入与模式 ####-##-##(其中 # 是 0 到 9 的数字)不匹配,你将看到浏览器显示错误并高亮输入无效。当然,这并不能阻止人们输入无效日期或不正确的格式。所以我们仍然有一个问题。

¥If you submit it, you'll see that the browser displays an error and highlights the input as invalid if your entry doesn't match the pattern ####-##-## (where # is a digit from 0 to 9). Of course, this doesn't stop people from entering invalid dates, or incorrect formats. So we still have a problem.

css
span {
  position: relative;
}

span::after {
  right: -18px;
  position: absolute;
}

input:invalid + span::after {
  content: "✖";
}

input:valid + span::after {
  content: "✓";
}

目前,以跨浏览器方式处理表单中的日期的最佳方法是让用户在单独的控件中输入日、月和年,或者使用 JavaScript 库(例如 jQuery 日期选择器)。

¥At the moment, the best way to deal with dates in forms in a cross-browser way is to have the user enter the day, month, and year in separate controls, or to use a JavaScript library such as jQuery date picker.

示例

¥Examples

在此示例中,我们创建 2 组用于选择日期的 UI 元素:一个原生 <input type="date"> 选择器和一组 3 个 <select> 元素,适用于不支持原生日期输入的旧浏览器。

¥In this example, we create 2 sets of UI elements for choosing dates: a native <input type="date"> picker and a set of 3 <select> elements for older browsers that don't support the native date input.

HTML

HTML 看起来像这样:

¥The HTML looks like so:

html
<form>
  <div class="nativeDatePicker">
    <label for="bday">Enter your birthday:</label>
    <input type="date" id="bday" name="bday" />
    <span class="validity"></span>
  </div>
  <p class="fallbackLabel">Enter your birthday:</p>
  <div class="fallbackDatePicker">
    <span>
      <label for="day">Day:</label>
      <select id="day" name="day"></select>
    </span>
    <span>
      <label for="month">Month:</label>
      <select id="month" name="month">
        <option selected>January</option>
        <option>February</option>
        <option>March</option>
        <option>April</option>
        <option>May</option>
        <option>June</option>
        <option>July</option>
        <option>August</option>
        <option>September</option>
        <option>October</option>
        <option>November</option>
        <option>December</option>
      </select>
    </span>
    <span>
      <label for="year">Year:</label>
      <select id="year" name="year"></select>
    </span>
  </div>
</form>

月份是硬编码的(因为它们始终相同),而日期和年份值是根据当前选择的月份和年份以及当前年份动态生成的(有关这些函数如何工作的详细说明,请参阅下面的代码注释。 )

¥The months are hardcoded (as they are always the same), while the day and year values are dynamically generated depending on the currently selected month and year, and the current year (see the code comments below for detailed explanations of how these functions work.)

css
span {
  padding-left: 5px;
}

input:invalid + span::after {
  content: "✖";
}

input:valid + span::after {
  content: "✓";
}

JavaScript

代码的另一部分可能令人感兴趣的是功能检测代码 - 检测浏览器是否支持 <input type="date">

¥The other part of the code that may be of interest is the feature detection code — to detect whether the browser supports <input type="date">.

我们创建一个新的 <input> 元素,尝试将其 type 设置为 date,然后立即检查其类型是什么 - 不支持的浏览器将返回 text,因为 date 类型会回退到类型 text。如果不支持 <input type="date">,我们将隐藏原生选择器并显示后备 (<select>)。

¥We create a new <input> element, try setting its type to date, then immediately check what its type is — unsupporting browsers will return text, because the date type falls back to type text. If <input type="date"> isn't supported, we hide the native picker and show the fallback (<select>) instead.

js
// Obtain UI widgets
const nativePicker = document.querySelector(".nativeDatePicker");
const fallbackPicker = document.querySelector(".fallbackDatePicker");
const fallbackLabel = document.querySelector(".fallbackLabel");

const yearSelect = document.querySelector("#year");
const monthSelect = document.querySelector("#month");
const daySelect = document.querySelector("#day");

// hide fallback initially
fallbackPicker.style.display = "none";
fallbackLabel.style.display = "none";

// test whether a new date input falls back to a text input or not
const test = document.createElement("input");

try {
  test.type = "date";
} catch (e) {
  console.log(e.message);
}

// if it does, run the code inside the if () {} block
if (test.type === "text") {
  // hide the native picker and show the fallback
  nativePicker.style.display = "none";
  fallbackPicker.style.display = "block";
  fallbackLabel.style.display = "block";

  // populate the days and years dynamically
  // (the months are always the same, therefore hardcoded)
  populateDays(monthSelect.value);
  populateYears();
}

function populateDays(month) {
  // delete the current set of <option> elements out of the
  // day <select>, ready for the next set to be injected
  while (daySelect.firstChild) {
    daySelect.removeChild(daySelect.firstChild);
  }

  // Create variable to hold new number of days to inject
  let dayNum;

  // 31 or 30 days?
  if (
    [
      "January",
      "March",
      "May",
      "July",
      "August",
      "October",
      "December",
    ].includes(month)
  ) {
    dayNum = 31;
  } else if (["April", "June", "September", "November"].includes(month)) {
    dayNum = 30;
  } else {
    // If month is February, calculate whether it is a leap year or not
    const year = yearSelect.value;
    const isLeap = new Date(year, 1, 29).getMonth() === 1;
    dayNum = isLeap ? 29 : 28;
  }

  // inject the right number of new <option> elements into the day <select>
  for (let i = 1; i <= dayNum; i++) {
    const option = document.createElement("option");
    option.textContent = i;
    daySelect.appendChild(option);
  }

  // if previous day has already been set, set daySelect's value
  // to that day, to avoid the day jumping back to 1 when you
  // change the year
  if (previousDay) {
    daySelect.value = previousDay;

    // If the previous day was set to a high number, say 31, and then
    // you chose a month with less total days in it (e.g. February),
    // this part of the code ensures that the highest day available
    // is selected, rather than showing a blank daySelect
    if (daySelect.value === "") {
      daySelect.value = previousDay - 1;
    }

    if (daySelect.value === "") {
      daySelect.value = previousDay - 2;
    }

    if (daySelect.value === "") {
      daySelect.value = previousDay - 3;
    }
  }
}

function populateYears() {
  // get this year as a number
  const date = new Date();
  const year = date.getFullYear();

  // Make this year, and the 100 years before it available in the year <select>
  for (let i = 0; i <= 100; i++) {
    const option = document.createElement("option");
    option.textContent = year - i;
    yearSelect.appendChild(option);
  }
}

// when the month or year <select> values are changed, rerun populateDays()
// in case the change affected the number of available days
yearSelect.onchange = () => {
  populateDays(monthSelect.value);
};

monthSelect.onchange = () => {
  populateDays(monthSelect.value);
};

//preserve day selection
let previousDay;

// update what day has been set to previously
// see end of populateDays() for usage
daySelect.onchange = () => {
  previousDay = daySelect.value;
};

注意:请记住,有些年份有 53 周(参见 每年几周)!开发生产应用时需要考虑到这一点。

¥Note: Remember that some years have 53 weeks in them (see Weeks per year)! You'll need to take this into consideration when developing production apps.

技术总结

¥Technical summary

表示 YYYY-MM-DD 格式的日期的字符串,或为空
活动 changeinput
支持的通用属性 autocompletelistreadonlystep
IDL 属性 list, value, valueAsDate, valueAsNumber.
DOM 接口

HTMLInputElement

方法 select(), stepDown(), stepUp()
隐式 ARIA 角色 no corresponding role

规范

Specification
HTML Standard
# date-state-(type=date)

¥Specifications

浏览器兼容性

BCD tables only load in the browser

¥Browser compatibility

也可以看看