ロケールごとの日付表記の違い
プログラムで取り扱う日付文字列は 2020-01-01
2020/01/01
といった「ゼロパディング、ハイフン or スラッシュ区切り」などがありますが、ユーザーフレンドリーにするため以下のような形式で表記することがあるかと思います。
- 1月1日(水)
- Jan 1(Wed)
例えばmoment.jsを利用すると以下のようになります。
moment.locale('ja');
moment('2020-01-01').format('M月D日(ddd)')
// > "1月1日(水)"
moment.locale('en');
moment('2020-01-01').format('MMM D(ddd)');
// > "Jan 1(Wed)"
自由な書式フォーマットの指定ができるので便利ですが、日付の計算や比較をするわけでもなく、ただフォーマットするだけであれば、標準APIであるIntl.DateTimeFormat
を使うという選択肢もあります。
Intlとは
各言語に依存した日付や数値フォーマットを共通化するための国際化API(Internationalization API)です。
日付のフォーマットにはIntl.DateTimeFormat
を利用します。
Intl.DateTimeFormat
基本的な使い方
ロケールと各項目の書式を指定してフォーマットします。
const options = {
month: 'short',
day: 'numeric',
weekday: 'short',
};
new Intl.DateTimeFormat('ja-JP', options).format(new Date('2020-01-01'));
// > "1月1日(水)"
new Intl.DateTimeFormat('en-US', options).format(new Date('2020-01-01'));
// >> "Wed, Jan 1"
moment.js
のように日付の表記順などの細かい指定はできませんが、ロケールごとの書式指定が不要になるという点ではメリットがあります。
optionsの指定による表記一覧
何を指定するとどう表記されるか明示されているドキュメントが見当たらなかったので、一覧を出してみました。
例えばja-JP
の場合month
はlong/short/narrow
ですべて同じ表記になりますがen-US
の場合は表記が異なります。
指定方法によっては結局ロケールごとの書式指定が必要になってしまいます。
year, month, day, weekdayの表記一覧(Chrome)
options | ja-JP | en-US |
---|---|---|
{ year: 'numeric' } | 2020年 | 2020 |
{ year: '2-digit' } | 20年 | 20 |
{ month: 'numeric' } | 1月 | 1 |
{ month: '2-digit' } | 01月 | 01 |
{ month: 'long' } | 1月 | January |
{ month: 'short' } | 1月 | Jan |
{ month: 'narrow' } | 1月 | J |
{ day: 'numeric' } | 1日 | 1 |
{ day: '2-digit' } | 01日 | 01 |
{ weekday: 'long' } | 水曜日 | Wednesday |
{ weekday: 'short' } | 水 | Wed |
{ weekday: 'narrow' } | 水 | W |
{ year: 'numeric', month: 'numeric' } | 2020/1 | 1/2020 |
{ year: 'numeric', month: '2-digit' } | 2020/01 | 01/2020 |
{ year: 'numeric', month: 'long' } | 2020年1月 | January 2020 |
{ year: 'numeric', month: 'short' } | 2020年1月 | Jan 2020 |
{ year: 'numeric', month: 'narrow' } | 2020年1月 | J 2020 |
{ year: '2-digit', month: 'numeric' } | 20/1 | 1/20 |
{ year: '2-digit', month: '2-digit' } | 20/01 | 01/20 |
{ year: '2-digit', month: 'long' } | 20年1月 | January 20 |
{ year: '2-digit', month: 'short' } | 20年1月 | Jan 20 |
{ year: '2-digit', month: 'narrow' } | 20年1月 | J 20 |
{ month: 'numeric', day: 'numeric' } | 1/1 | 1/1 |
{ month: 'numeric', day: '2-digit' } | 1/01 | 1/01 |
{ month: '2-digit', day: 'numeric' } | 01/1 | 01/1 |
{ month: '2-digit', day: '2-digit' } | 01/01 | 01/01 |
{ month: 'long', day: 'numeric' } | 1月1日 | January 1 |
{ month: 'long', day: '2-digit' } | 1月01日 | January 01 |
{ month: 'short', day: 'numeric' } | 1月1日 | Jan 1 |
{ month: 'short', day: '2-digit' } | 1月01日 | Jan 01 |
{ month: 'narrow', day: 'numeric' } | 1月1日 | J 1 |
{ month: 'narrow', day: '2-digit' } | 1月01日 | J 01 |
{ day: 'numeric', weekday: 'long' } | 1日水曜日 | 1 Wednesday |
{ day: 'numeric', weekday: 'short' } | 1日(水) | 1 Wed |
{ day: 'numeric', weekday: 'narrow' } | 1日(水) | 1 W |
{ day: '2-digit', weekday: 'long' } | 01日水曜日 | 01 Wednesday |
{ day: '2-digit', weekday: 'short' } | 01日(水) | 01 Wed |
{ day: '2-digit', weekday: 'narrow' } | 01日(水) | 01 W |
{ year: 'numeric', month: 'numeric', day: 'numeric' } | 2020/1/1 | 1/1/2020 |
{ year: 'numeric', month: 'numeric', day: '2-digit' } | 2020/1/01 | 1/01/2020 |
{ year: 'numeric', month: '2-digit', day: 'numeric' } | 2020/01/1 | 01/1/2020 |
{ year: 'numeric', month: '2-digit', day: '2-digit' } | 2020/01/01 | 01/01/2020 |
{ year: 'numeric', month: 'long', day: 'numeric' } | 2020年1月1日 | January 1, 2020 |
{ year: 'numeric', month: 'long', day: '2-digit' } | 2020年1月01日 | January 01, 2020 |
{ year: 'numeric', month: 'short', day: 'numeric' } | 2020年1月1日 | Jan 1, 2020 |
{ year: 'numeric', month: 'short', day: '2-digit' } | 2020年1月01日 | Jan 01, 2020 |
{ year: 'numeric', month: 'narrow', day: 'numeric' } | 2020年1月1日 | J 1, 2020 |
{ year: 'numeric', month: 'narrow', day: '2-digit' } | 2020年1月01日 | J 01, 2020 |
{ year: '2-digit', month: 'numeric', day: 'numeric' } | 20/1/1 | 1/1/20 |
{ year: '2-digit', month: 'numeric', day: '2-digit' } | 20/1/01 | 1/01/20 |
{ year: '2-digit', month: '2-digit', day: 'numeric' } | 20/01/1 | 01/1/20 |
{ year: '2-digit', month: '2-digit', day: '2-digit' } | 20/01/01 | 01/01/20 |
{ year: '2-digit', month: 'long', day: 'numeric' } | 20年1月1日 | January 1, 20 |
{ year: '2-digit', month: 'long', day: '2-digit' } | 20年1月01日 | January 01, 20 |
{ year: '2-digit', month: 'short', day: 'numeric' } | 20年1月1日 | Jan 1, 20 |
{ year: '2-digit', month: 'short', day: '2-digit' } | 20年1月01日 | Jan 01, 20 |
{ year: '2-digit', month: 'narrow', day: 'numeric' } | 20年1月1日 | J 1, 20 |
{ year: '2-digit', month: 'narrow', day: '2-digit' } | 20年1月01日 | J 01, 20 |
{ month: 'numeric', day: 'numeric', weekday: 'long' } | 1/1水曜日 | Wednesday, 1/1 |
{ month: 'numeric', day: 'numeric', weekday: 'short' } | 1/1(水) | Wed, 1/1 |
{ month: 'numeric', day: 'numeric', weekday: 'narrow' } | 1/1(水) | W, 1/1 |
{ month: 'numeric', day: '2-digit', weekday: 'long' } | 1/01水曜日 | Wednesday, 1/01 |
{ month: 'numeric', day: '2-digit', weekday: 'short' } | 1/01(水) | Wed, 1/01 |
{ month: 'numeric', day: '2-digit', weekday: 'narrow' } | 1/01(水) | W, 1/01 |
{ month: '2-digit', day: 'numeric', weekday: 'long' } | 01/1水曜日 | Wednesday, 01/1 |
{ month: '2-digit', day: 'numeric', weekday: 'short' } | 01/1(水) | Wed, 01/1 |
{ month: '2-digit', day: 'numeric', weekday: 'narrow' } | 01/1(水) | W, 01/1 |
{ month: '2-digit', day: '2-digit', weekday: 'long' } | 01/01水曜日 | Wednesday, 01/01 |
{ month: '2-digit', day: '2-digit', weekday: 'short' } | 01/01(水) | Wed, 01/01 |
{ month: '2-digit', day: '2-digit', weekday: 'narrow' } | 01/01(水) | W, 01/01 |
{ month: 'long', day: 'numeric', weekday: 'long' } | 1月1日水曜日 | Wednesday, January 1 |
{ month: 'long', day: 'numeric', weekday: 'short' } | 1月1日(水) | Wed, January 1 |
{ month: 'long', day: 'numeric', weekday: 'narrow' } | 1月1日(水) | W, January 1 |
{ month: 'long', day: '2-digit', weekday: 'long' } | 1月01日水曜日 | Wednesday, January 01 |
{ month: 'long', day: '2-digit', weekday: 'short' } | 1月01日(水) | Wed, January 01 |
{ month: 'long', day: '2-digit', weekday: 'narrow' } | 1月01日(水) | W, January 01 |
{ month: 'short', day: 'numeric', weekday: 'long' } | 1月1日水曜日 | Wednesday, Jan 1 |
{ month: 'short', day: 'numeric', weekday: 'short' } | 1月1日(水) | Wed, Jan 1 |
{ month: 'short', day: 'numeric', weekday: 'narrow' } | 1月1日(水) | W, Jan 1 |
{ month: 'short', day: '2-digit', weekday: 'long' } | 1月01日水曜日 | Wednesday, Jan 01 |
{ month: 'short', day: '2-digit', weekday: 'short' } | 1月01日(水) | Wed, Jan 01 |
{ month: 'short', day: '2-digit', weekday: 'narrow' } | 1月01日(水) | W, Jan 01 |
{ month: 'narrow', day: 'numeric', weekday: 'long' } | 1月1日水曜日 | Wednesday, J 1 |
{ month: 'narrow', day: 'numeric', weekday: 'short' } | 1月1日(水) | Wed, J 1 |
{ month: 'narrow', day: 'numeric', weekday: 'narrow' } | 1月1日(水) | W, J 1 |
{ month: 'narrow', day: '2-digit', weekday: 'long' } | 1月01日水曜日 | Wednesday, J 01 |
{ month: 'narrow', day: '2-digit', weekday: 'short' } | 1月01日(水) | Wed, J 01 |
{ month: 'narrow', day: '2-digit', weekday: 'narrow' } | 1月01日(水) | W, J 01 |
{ year: 'numeric', month: 'numeric', day: 'numeric', weekday: 'long' } | 2020/1/1水曜日 | Wednesday, 1/1/2020 |
{ year: 'numeric', month: 'numeric', day: 'numeric', weekday: 'short' } | 2020/1/1(水) | Wed, 1/1/2020 |
{ year: 'numeric', month: 'numeric', day: 'numeric', weekday: 'narrow' } | 2020/1/1(水) | W, 1/1/2020 |
{ year: 'numeric', month: 'numeric', day: '2-digit', weekday: 'long' } | 2020/1/01水曜日 | Wednesday, 1/01/2020 |
{ year: 'numeric', month: 'numeric', day: '2-digit', weekday: 'short' } | 2020/1/01(水) | Wed, 1/01/2020 |
{ year: 'numeric', month: 'numeric', day: '2-digit', weekday: 'narrow' } | 2020/1/01(水) | W, 1/01/2020 |
{ year: 'numeric', month: '2-digit', day: 'numeric', weekday: 'long' } | 2020/01/1水曜日 | Wednesday, 01/1/2020 |
{ year: 'numeric', month: '2-digit', day: 'numeric', weekday: 'short' } | 2020/01/1(水) | Wed, 01/1/2020 |
{ year: 'numeric', month: '2-digit', day: 'numeric', weekday: 'narrow' } | 2020/01/1(水) | W, 01/1/2020 |
{ year: 'numeric', month: '2-digit', day: '2-digit', weekday: 'long' } | 2020/01/01水曜日 | Wednesday, 01/01/2020 |
{ year: 'numeric', month: '2-digit', day: '2-digit', weekday: 'short' } | 2020/01/01(水) | Wed, 01/01/2020 |
{ year: 'numeric', month: '2-digit', day: '2-digit', weekday: 'narrow' } | 2020/01/01(水) | W, 01/01/2020 |
{ year: 'numeric', month: 'long', day: 'numeric', weekday: 'long' } | 2020年1月1日水曜日 | Wednesday, January 1, 2020 |
{ year: 'numeric', month: 'long', day: 'numeric', weekday: 'short' } | 2020年1月1日(水) | Wed, January 1, 2020 |
{ year: 'numeric', month: 'long', day: 'numeric', weekday: 'narrow' } | 2020年1月1日(水) | W, January 1, 2020 |
{ year: 'numeric', month: 'long', day: '2-digit', weekday: 'long' } | 2020年1月01日水曜日 | Wednesday, January 01, 2020 |
{ year: 'numeric', month: 'long', day: '2-digit', weekday: 'short' } | 2020年1月01日(水) | Wed, January 01, 2020 |
{ year: 'numeric', month: 'long', day: '2-digit', weekday: 'narrow' } | 2020年1月01日(水) | W, January 01, 2020 |
{ year: 'numeric', month: 'short', day: 'numeric', weekday: 'long' } | 2020年1月1日水曜日 | Wednesday, Jan 1, 2020 |
{ year: 'numeric', month: 'short', day: 'numeric', weekday: 'short' } | 2020年1月1日(水) | Wed, Jan 1, 2020 |
{ year: 'numeric', month: 'short', day: 'numeric', weekday: 'narrow' } | 2020年1月1日(水) | W, Jan 1, 2020 |
{ year: 'numeric', month: 'short', day: '2-digit', weekday: 'long' } | 2020年1月01日水曜日 | Wednesday, Jan 01, 2020 |
{ year: 'numeric', month: 'short', day: '2-digit', weekday: 'short' } | 2020年1月01日(水) | Wed, Jan 01, 2020 |
{ year: 'numeric', month: 'short', day: '2-digit', weekday: 'narrow' } | 2020年1月01日(水) | W, Jan 01, 2020 |
{ year: 'numeric', month: 'narrow', day: 'numeric', weekday: 'long' } | 2020年1月1日水曜日 | Wednesday, J 1, 2020 |
{ year: 'numeric', month: 'narrow', day: 'numeric', weekday: 'short' } | 2020年1月1日(水) | Wed, J 1, 2020 |
{ year: 'numeric', month: 'narrow', day: 'numeric', weekday: 'narrow' } | 2020年1月1日(水) | W, J 1, 2020 |
{ year: 'numeric', month: 'narrow', day: '2-digit', weekday: 'long' } | 2020年1月01日水曜日 | Wednesday, J 01, 2020 |
{ year: 'numeric', month: 'narrow', day: '2-digit', weekday: 'short' } | 2020年1月01日(水) | Wed, J 01, 2020 |
{ year: 'numeric', month: 'narrow', day: '2-digit', weekday: 'narrow' } | 2020年1月01日(水) | W, J 01, 2020 |
{ year: '2-digit', month: 'numeric', day: 'numeric', weekday: 'long' } | 20/1/1水曜日 | Wednesday, 1/1/20 |
{ year: '2-digit', month: 'numeric', day: 'numeric', weekday: 'short' } | 20/1/1(水) | Wed, 1/1/20 |
{ year: '2-digit', month: 'numeric', day: 'numeric', weekday: 'narrow' } | 20/1/1(水) | W, 1/1/20 |
{ year: '2-digit', month: 'numeric', day: '2-digit', weekday: 'long' } | 20/1/01水曜日 | Wednesday, 1/01/20 |
{ year: '2-digit', month: 'numeric', day: '2-digit', weekday: 'short' } | 20/1/01(水) | Wed, 1/01/20 |
{ year: '2-digit', month: 'numeric', day: '2-digit', weekday: 'narrow' } | 20/1/01(水) | W, 1/01/20 |
{ year: '2-digit', month: '2-digit', day: 'numeric', weekday: 'long' } | 20/01/1水曜日 | Wednesday, 01/1/20 |
{ year: '2-digit', month: '2-digit', day: 'numeric', weekday: 'short' } | 20/01/1(水) | Wed, 01/1/20 |
{ year: '2-digit', month: '2-digit', day: 'numeric', weekday: 'narrow' } | 20/01/1(水) | W, 01/1/20 |
{ year: '2-digit', month: '2-digit', day: '2-digit', weekday: 'long' } | 20/01/01水曜日 | Wednesday, 01/01/20 |
{ year: '2-digit', month: '2-digit', day: '2-digit', weekday: 'short' } | 20/01/01(水) | Wed, 01/01/20 |
{ year: '2-digit', month: '2-digit', day: '2-digit', weekday: 'narrow' } | 20/01/01(水) | W, 01/01/20 |
{ year: '2-digit', month: 'long', day: 'numeric', weekday: 'long' } | 20年1月1日水曜日 | Wednesday, January 1, 20 |
{ year: '2-digit', month: 'long', day: 'numeric', weekday: 'short' } | 20年1月1日(水) | Wed, January 1, 20 |
{ year: '2-digit', month: 'long', day: 'numeric', weekday: 'narrow' } | 20年1月1日(水) | W, January 1, 20 |
{ year: '2-digit', month: 'long', day: '2-digit', weekday: 'long' } | 20年1月01日水曜日 | Wednesday, January 01, 20 |
{ year: '2-digit', month: 'long', day: '2-digit', weekday: 'short' } | 20年1月01日(水) | Wed, January 01, 20 |
{ year: '2-digit', month: 'long', day: '2-digit', weekday: 'narrow' } | 20年1月01日(水) | W, January 01, 20 |
{ year: '2-digit', month: 'short', day: 'numeric', weekday: 'long' } | 20年1月1日水曜日 | Wednesday, Jan 1, 20 |
{ year: '2-digit', month: 'short', day: 'numeric', weekday: 'short' } | 20年1月1日(水) | Wed, Jan 1, 20 |
{ year: '2-digit', month: 'short', day: 'numeric', weekday: 'narrow' } | 20年1月1日(水) | W, Jan 1, 20 |
{ year: '2-digit', month: 'short', day: '2-digit', weekday: 'long' } | 20年1月01日水曜日 | Wednesday, Jan 01, 20 |
{ year: '2-digit', month: 'short', day: '2-digit', weekday: 'short' } | 20年1月01日(水) | Wed, Jan 01, 20 |
{ year: '2-digit', month: 'short', day: '2-digit', weekday: 'narrow' } | 20年1月01日(水) | W, Jan 01, 20 |
{ year: '2-digit', month: 'narrow', day: 'numeric', weekday: 'long' } | 20年1月1日水曜日 | Wednesday, J 1, 20 |
{ year: '2-digit', month: 'narrow', day: 'numeric', weekday: 'short' } | 20年1月1日(水) | Wed, J 1, 20 |
{ year: '2-digit', month: 'narrow', day: 'numeric', weekday: 'narrow' } | 20年1月1日(水) | W, J 1, 20 |
{ year: '2-digit', month: 'narrow', day: '2-digit', weekday: 'long' } | 20年1月01日水曜日 | Wednesday, J 01, 20 |
{ year: '2-digit', month: 'narrow', day: '2-digit', weekday: 'short' } | 20年1月01日(水) | Wed, J 01, 20 |
{ year: '2-digit', month: 'narrow', day: '2-digit', weekday: 'narrow' } | 20年1月01日(水) | W, J 01, 20 |
ブラウザによる差異
各ブラウザごとの実装に差異があり、指定したoptionによっては表記が異なる場合があります。
const options = {
month: 'long',
day: 'numeric',
weekday: 'long',
};
new Intl.DateTimeFormat('ja-JP', options).format(new Date('2020-01-01'));
// Chrome, Firefox > "1月1日水曜日"
// Safari > "1月1日 水曜日"
まとめ
自由な書式を定義したい場合はmoment.js
などのライブラリを利用した方が良いかもしれませんが、標準的な書式で十分なのであればIntl.DateTimeFormat
を利用するのもありかと思います。
書式の細かい指定ができないため出力してみないと分からない、ブラウザにより表記が異なるケースがある、という点には注意が必要です。