日付項目の和暦・多暦表示
日付項目を和暦(令和 8 年 3 月 6 日など)で表示・入力できるようにする設計メモです。本体の標準機能ではありません。 保存する値(DB・API)は西暦のまま、画面の表示と入力だけを変えます。年月・年だけの入力モードや一覧の表示形式の拡張は 日付項目の入力モードと表示形式の拡張 にあります。調査は 1.5.1.0 で行い、前提にした部分を 1.5.8.1 のソースで確かめています。
前提にした現行実装
date-field の作り
2 世代目のテーマ(UseOldDatepicker が false)では、日付項目は <date-field> カスタム要素で、中の input に flatpickr 4.6.13 を付けています(datefield.ts)。
| 項目 | 1.5.8.1 の実装 |
|---|---|
| Shadow DOM | 使う(mode: 'open')。ただし Shadow DOM の中にあるのは枠と「現在日時」ボタンだけで、input は <slot> に入る通常の子要素(datefield.ts#L18-L26、#L178-L186) |
| flatpickr のインスタンス | flatpickr(this.inputElm, …) で作る。flatpickr の決まりで input._flatpickr から外部のスクリプトでも取れる |
| カレンダーの置き場所 | appendTo でダイアログの中、なければ document.body |
dateFormat | input の data-format(s は S に置き換え)。無ければ Y/m/d H:i(datefield.ts#L44-L46) |
| 「現在日時」ボタン | moment で input.value を書き、setDate(value, false) でピッカーに反映する(datefield.ts#L116-L127) |
| 送信される値 | input の値そのもの |
date-field は Shadow DOM を使いますが、input は Shadow DOM の中ではなく通常の子要素で、this.querySelector('input') で取っています。そのため外部のスクリプトからも input._flatpickr に触れます。既存のレシピでも input._flatpickr を使って flatpickr を付け直しています(入力支援)。
言語ごとの書式
data-format は言語ごとの表示文字列 YmdDatePickerFormat などから決まります(YmdDatePickerFormat.json)。
| 言語 | flatpickr の書式 |
|---|---|
| 既定(英語) | m/d/Y |
| ja・zh・es・vn | Y/m/d |
| de | Y.m.d |
| ko | Y.m.d. |
西暦以外の書式はありません。
暦の変換
Intl.DateTimeFormat(推奨)
ブラウザ標準の Intl.DateTimeFormat は、ロケールに -u-ca-japanese を付けると和暦で書式化します。元号のデータは CLDR に従うので、新しい元号にはブラウザの更新で追従します。
function toWareki(date) {
var parts = new Intl.DateTimeFormat('ja-JP-u-ca-japanese', {
era: 'long', year: 'numeric', month: 'numeric', day: 'numeric'
}).formatToParts(date);
var get = function (type) {
var p = parts.find(function (x) { return x.type === type; });
return p ? p.value : '';
};
return get('era') + get('year') + '年' + get('month') + '月' + get('day') + '日';
// 例: 令和8年3月6日
}同じ方法で、ほかの暦にも書式化できます。
| 暦 | ロケールの例 | 表示の例 |
|---|---|---|
| 和暦 | ja-JP-u-ca-japanese | 令和8年3月6日 |
| 仏暦 | th-TH-u-ca-buddhist | 2569年3月6日 |
| 中華民国暦 | zh-TW-u-ca-roc | 民國115年3月6日 |
| ヒジュラ暦 | ar-SA-u-ca-islamic | 6 Rabiʻ II 1447 AH |
| ペルシャ暦 | fa-IR-u-ca-persian | 1404/12/15 |
| ヘブライ暦 | he-IL-u-ca-hebrew | 6 Adar 5786 |
元号の表を持つ方法
元号の開始日の表を自前で持つ方法もあります。テストはしやすくなりますが、新しい元号ができたら表を直す必要があります。Intl が使えない環境の予備として使います。
和暦から西暦への変換
Intl.DateTimeFormat には逆の変換(文字列 → 日付)がありません。入力を受け付けるなら、正規表現で自前で解析します。
| 入力の形 | 難しさ | 例 |
|---|---|---|
| 完全な形 | 低 | 令和8年3月6日 |
| 略した形 | 中 | R8.3.6 |
| 元年 | 中 | 令和元年5月1日 |
| 時刻付き | 中 | 令和8年3月6日 14:30 |
| 元号の切り替わり | 高 | 平成31年4月30日 |
var ERA_OFFSETS = { 令和: 2018, 平成: 1988, 昭和: 1925, 大正: 1911, 明治: 1867 };
function fromWareki(str) {
var m = str.match(/(令和|平成|昭和|大正|明治)(\d+|元)年(\d+)月(\d+)日/);
if (!m) return null;
var year = ERA_OFFSETS[m[1]] + (m[2] === '元' ? 1 : Number(m[2]));
return new Date(year, Number(m[3]) - 1, Number(m[4]));
}送信する値を西暦のままにする
flatpickr の formatDate を差し替えると、ピッカーが input に書く値そのものが変わります。input の値はそのまま送信されるので、和暦の文字列がサーバーに送られて日付として読めなくなります。表示と送信を分けるには altInput を使います。
| オプション | 役割 |
|---|---|
dateFormat | 元の input(送信される値)の書式。西暦のまま |
altInput: true | 表示用の input を別に作り、元の input を隠す |
altFormat | 表示用の input の書式 |
formatDate(date, format) | 書式化の関数。format が altFormat のときだけ和暦にする |
parseDate(str, format) | 入力の解析。和暦として読めたらその日付、読めなければ flatpickr の既定の解析 |
図を読み込み中…
実装の方法
A. 拡張スクリプトで flatpickr を付け直す
本体を改修せずに、date-field の input._flatpickr を destroy() して、altInput などを付けたオプションで作り直します。年月モードのレシピ(入力支援)と同じやり方です。
- 送信する値は西暦の
dateFormatのままにし、altFormat側だけ和暦にします。 - 「現在日時」ボタンは元の
inputに西暦を書いてsetDateを呼ぶので、altInputを使っていれば表示用の欄にも和暦で反映されます。 date-fieldは後から追加されることがある(ダイアログで開いた編集画面など)ので、MutationObserverで新しいdate-fieldにも適用します。
B. date-field に暦の設定を持たせる(本体改修)
datefield.ts に暦の種類(gregorian・japanese・buddhist・roc など)を持たせ、西暦以外なら上の altInput・formatDate・parseDate を付けます。
private initDatePicker() {
const calendar = this.inputElm.dataset.calendar ?? 'gregorian';
const fpOptions: Options = {
dateFormat: this.dateFormat, // 送信は西暦のまま
...(calendar !== 'gregorian'
? {
altInput: true,
altFormat: 'CAL', // 表示用の目印(formatDate で差し替える)
formatDate: (date: Date, format: string) =>
format === 'CAL'
? this.formatByCalendar(date, calendar)
: flatpickr.formatDate(date, format),
parseDate: (str: string, format: string) =>
this.parseByCalendar(str, calendar) ?? flatpickr.parseDate(str, format)
}
: {}),
// …既存のオプション
};
this.dataPicker = flatpickr(this.inputElm, fpOptions);
}サーバー側は、暦の種類を項目の設定に持たせて data-calendar 属性で出すだけで済みます。
| 対象 | 変更 |
|---|---|
Column.cs | 暦の種類のプロパティを足す |
HtmlControls.cs | date-field の input に data-calendar を出す |
SiteSettings(保存) | 既定値と違うときだけ保存される仕組みに乗せる |
| DB | 変更なし(値は西暦) |
Displays/*.json | 変更なし |
日付ピッカー以外の表示
| 表示箇所 | 現行 | 和暦にするには |
|---|---|---|
| 編集画面の入力欄 | flatpickr の dateFormat | 上の altInput 方式 |
| 一覧画面 | サーバー(C#)で GridFormat の書式で文字列にする | C# で和暦のカレンダーを使って書式化する |
| API の応答 | 西暦 | 変更不要 |
| カレンダー(FullCalendar) | 西暦 | 別に対応が要る |
| CSV エクスポート | サーバーで書式化 | 出力の書式の設定を足す |
C# では JapaneseCalendar を使うと和暦で書式化できます。
using System.Globalization;
var culture = new CultureInfo("ja-JP");
culture.DateTimeFormat.Calendar = new JapaneseCalendar();
var text = date.ToString("ggyy年MM月dd日", culture); // 令和08年03月06日