え！<input type="date">で作った入力フォームの年には6桁入力できるんですか！？

こんにちは！withサーバーチームの@10keiと申します。

簡単な入力フォームを作成する際、日付の入力項目には`<input type="date">`を使うと便利ですよねー。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="abMbBJQ" data-preview="true" data-user="Keito13" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/Keito13/pen/abMbBJQ">
  Untitled</a> by KeitoSato (<a href="https://codepen.io/Keito13">@Keito13</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

入力補助のカレンダーもブラウザが用意してくれます。おてがる！😄

ところでこのフォームですが、入力補助のカレンダーを使わずとも、キーボードから直接入力することができます。
生年月日など、現在の日時から離れた年の入力をしたい時は、直接入力した方が早い時もありますね。

さて、では弊社アプリの誕生日（iOS版のリリース日）を試しに入力してみましょうか。
えーと、2016年3⽉29⽇だから、「20160329」っと…

![chrome-capture-2023-11-22.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391935/c0311adf-593f-2d01-5473-01d284e3fdb2.gif)

ん？

あぇ！？

**201603年！！！？？**

## 年の最大値は9999年じゃない！？

`<input type="date">`で作成した日付の入力フォームにおいて
年の最大値は9999年ではありません。
なんと、**275760年**まで入力することが可能です。

JavaScriptなどのDate型と同様に
[1970年1月1日から、100,000,000日後までをサポートしているからです。](https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Numbers_and_dates#date_%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88:~:text=Unix%20%E3%82%BF%E3%82%A4%E3%83%A0%E3%82%B9%E3%82%BF%E3%83%B3%E3%83%97,%E6%97%A5%E3%81%BE%E3%81%A7%E3%81%A7%E3%81%99%E3%80%82)

これは`type="date"`に限らず
`type="datetime-local"`や`type="month"`も同様の入力範囲となっています。

ですが、2000年代に生きる我々にとって、年月日の入力は通常8桁で完結するものであり
4桁入力した時点で年の入力を終え、月の入力に自ずと移ってくれると思うのが自然です。

年に6桁の入力ができてしまうと
ユーザーの入力ミスを誘ってしまうUIだと言えるでしょう。

## RDBMSのDATE型サポート範囲にも注意！
さらに厄介なことに、RDBMSによってはDATE型のサポート範囲が`9999-12-31`までとなっています。

* DATE型サポート範囲が`9999-12-31`までの主要RDBMS
    * [MySQL](https://dev.mysql.com/doc/refman/8.0/ja/datetime.html#:~:text=DATE%20%E5%9E%8B%E3%81%AF%E3%80%81%E6%97%A5%E4%BB%98%E9%83%A8%E5%88%86,%2D12%2D31'%20%E3%81%A7%E3%81%99%E3%80%82)
    * [SQLite](https://www.sqlite.org/lang_datefunc.html#:~:text=corresponding%20to%20dates%20between%20%2D4713%2D11%2D24%2012%3A00%3A00%20and%209999%2D12%2D31%2023%3A59%3A59%2C%20inclusive)
    * [Oracle](https://docs.oracle.com/cd/E15817_01/server.111/e05765/datatype.htm#17913:~:text=Oracle%20Database%E3%81%A7%E3%81%AF%E3%80%81%E3%83%A6%E3%83%AA%E3%82%A6%E3%82%B9%E6%9A%A6%E3%81%AE%E8%A5%BF%E6%9A%A6%E5%89%8D4712%E5%B9%B41%E6%9C%881%E6%97%A5%E3%81%8B%E3%82%89%E8%A5%BF%E6%9A%A69999%E5%B9%B412%E6%9C%8831%E6%97%A5%E3%81%BE%E3%81%A7%E3%81%AE%E6%97%A5%E4%BB%98%E3%82%92%E6%A0%BC%E7%B4%8D%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99)
    * [Microsoft SQL Server](https://learn.microsoft.com/ja-jp/sql/t-sql/data-types/date-transact-sql?view=sql-server-ver16#:~:text=%E3%81%A6%E3%81%8F%E3%81%A0%E3%81%95%E3%81%84%E3%80%82-,%E7%AF%84%E5%9B%B2,-0001%2D01%2D01)
　
* DATE型サポート範囲が`9999-12-31`**ではない**主要RDBMS
    * [PostgreSQL](https://www.postgresql.org/docs/current/datatype-datetime.html)

ユーザーに入力させた日付フォームの値をそのまま保存するシステムだった場合、使用しているRDBMSによっては

年に6桁の入力ができてしまうことで、入力ミスの誘発だけでなく
エラーまで発生させてしまう要因となり得ます。

## max属性で入力の最大値を設定してあげよう
日付の入力を受け取る際、サーバー側で値のバリデーションを確実に行い、予期せぬエラーを防ぐ様にしましょう！
また、そもそも年に入力できる値の範囲を制限し、入力ミスを防いであげれば、よりユーザーフレンドリーなフォームになりますね。

**こんな時はmax属性を付与してあげると良いでしょう！**

サービスによって、入力が想定される最大の日付を`max`に設定するのが理想ですが
特に思い当たる日付がなければ、`9999-12-31`をとりあえず最大値にしてあげれば
年に5桁以上の桁数が入力されることは防ぐことができます。[^1]

ちなみに、[pattern属性はdateなどの型においては無効](https://developer.mozilla.org/ja/docs/Web/HTML/Element/input#pattern:~:text=%E9%80%81%E4%BF%A1%E3%81%95%E3%82%8C%E3%82%8B-,pattern,%E3%81%AA%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AB%20value%20%E3%81%8C%E4%B8%80%E8%87%B4%E3%81%99%E3%82%8B%E5%BF%85%E8%A6%81%E3%81%8C%E3%81%82%E3%82%8B%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3,-placeholder)になりますので
こちらではユーザーの入力制御を行うことはできません。注意！[^2]

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="jOJOyMv" data-preview="true" data-user="Keito13" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/Keito13/pen/jOJOyMv">
  Untitled</a> by KeitoSato (<a href="https://codepen.io/Keito13">@Keito13</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

**`<input type="date">`を使って日付の入力項目を作成する際は、最大値を忘れずに設定しましょう！**

[^1]:Chromeではキーボード入力でも、max属性で設定した日付までの入力に制限してくれますが、Firefox, Safariでは`275760-12-31`まで入力が出来てしまいます（ただし、maxに設定した日付を超えた入力がされていると:invalidにはなってくれる）

[^2]:現在ではあまり意識する必要はないと思いますが、date型のinput要素に対応していないブラウザの対応のために、pattern属性をつけることもあったようです。([ブラウザーの互換性の扱い - MDN](https://developer.mozilla.org/ja/docs/Web/HTML/Element/input/date#%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%83%BC%E3%81%AE%E4%BA%92%E6%8F%9B%E6%80%A7%E3%81%AE%E6%89%B1%E3%81%84))

## 参考
https://developer.mozilla.org/ja/docs/Web/HTML/Element/input/date

https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Numbers_and_dates#date_%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88

https://dev.mysql.com/doc/refman/8.0/ja/datetime.html#:~:text=DATE%20%E5%9E%8B%E3%81%AF%E3%80%81%E6%97%A5%E4%BB%98%E9%83%A8%E5%88%86,%2D12%2D31'%20%E3%81%A7%E3%81%99%E3%80%82