請求書の発行日、契約書の締結日、顧客名簿の生年月日、官公庁への提出書類 — 日本の業務アプリを書いていれば、和暦は避けて通れません。「西暦で統一しましょう」と提案して通る現場なら幸運です。多くの場合、画面にも帳票にも「令和8年6月6日」と出すことが、交渉の余地のない要件としてやってきます。
そして多くの実装が、最初の一歩でつまずきます。日付を文字列にしてしまうのです。
本記事では、セルのデータを DateTime のまま保ち、表示だけを和暦にする方法を示します。例には ReoGrid を使います — 和暦カレンダーへの切り替えがデータ書式エンジンに組み込まれているからです。
よくある実装と、その代償
最も自然に見える実装はこうです。和暦のカルチャを作って、文字列化してセルに入れる。
var wareki = new CultureInfo("ja-JP");
wareki.DateTimeFormat.Calendar = new JapaneseCalendar();
sheet["B3"] = date.ToString("ggy年M月d日", wareki); // ← 文字列としてセルに格納
表示は一見正しい。ですが、このセルの中身はもう日付ではなくただの文字列です。代償は後から、まとめて請求されます。
- ソートが壊れる。 文字列比較では「令和10年」が「令和2年」より前に来ます(先頭から 1 文字ずつ比較されるため)。日付列を並べ替えた瞬間に発覚する、和暦文字列の定番バグです。
- 数式が使えない。
=DAYS(B3, TODAY())のような日付計算は、文字列セルに対してはエラーになります。支払期日まであと何日、といった計算が全滅します。 - フィルタが効かない。 「2026年4月以降」のような日付範囲の絞り込みができません。
- 書式変更がデータ変更になる。 「やっぱり西暦も併記で」と言われたら、全セルのデータを作り直しです。
問題の根は 1 つです: 表示の都合をデータに焼き込んでしまったこと。
正解: データは DateTime、表示だけ和暦
ReoGrid では、セルの値と表示書式は分離されています。日付セルに和暦の書式を設定すれば、データは DateTime のまま、画面上の見た目だけが和暦になります。
using unvell.ReoGrid;
using unvell.ReoGrid.DataFormat;
var sheet = grid.CurrentWorksheet;
// B 列を和暦表示の日付セルにする
sheet.SetRangeDataFormat("B3:B100", CellDataFormatFlag.DateTime,
new DateTimeDataFormatter.DateTimeFormatArgs
{
Format = "ggy年M月d日", // gg = 元号、y = 元号での年
CultureName = "ja-JP",
});
sheet["B3"] = new DateTime(2026, 6, 6); // 表示: 令和8年6月6日
これだけです。ポイントは書式パターンの gg(元号指定子)。カルチャが日本語(ja)で、書式に g が含まれていると、ReoGrid は内部でカレンダーを JapaneseCalendar に自動で切り替えます。元号の判定も、元号内での年の計算も .NET の JapaneseCalendar がやってくれるので、改元対応表をコードに持つ必要はありません。
パターンは標準の .NET 日付書式パターンです。よく使う組み合わせ:
| パターン | 表示例 |
|---|---|
ggy年M月d日 | 令和8年6月6日 |
ggy年M月d日(ddd) | 令和8年6月6日(土) |
ggyy/MM/dd | 令和08/06/06 |
yyyy年M月d日(g なし) | 2026年6月6日 — 西暦のまま |
g を外せば同じセルが西暦表示に戻ります。データは一切触っていないので、書式を差し替えるだけで和暦⇔西暦を切り替えられます。「西暦併記で」と言われても、もう怖くありません。
注意: ここで使うのは .NET のパターンです。Excel の表示形式コード(
ggge"年"m"月"d"日"—eが元号年)とは流儀が違います。.NET では元号年はy/yyで表します。
入力は西暦のまま打てる
和暦書式を設定したセルに、ユーザーが 2026/6/6 と打ち込むとどうなるか。
ReoGrid は編集確定時に、DateTime 書式のセルに入力された文字列を DateTime.TryParse で解釈し、本物の DateTime としてセルに格納します。表示は設定した書式 — つまり和暦 — で行われます。
ユーザーの入力: 2026/6/6
セルのデータ: DateTime (2026-06-06)
セルの表示: 令和8年6月6日
「入力は西暦、表示は和暦」という業務アプリの定番要件が、追加コードなしで成立します。データが DateTime なので、入力直後からソートも数式も正しく動きます。
sheet["C3"] = "=DAYS(B3, TODAY())"; // 締結日まであと何日 — 和暦表示のセルにそのまま効く
ReoGrid の数式エンジンは DAYS / TODAY / YEAR / MONTH などの日付関数を内蔵しており、セルの DateTime データに対して直接計算します。
昭和・平成も自動 — 生年月日列にそのまま使える
JapaneseCalendar は改元の境界をすべて知っています。顧客名簿の生年月日のように複数の元号が混在する列でも、書式設定は 1 回だけです。
sheet["B4"] = new DateTime(1980, 4, 2); // 昭和55年4月2日
sheet["B5"] = new DateTime(1989, 1, 7); // 昭和64年1月7日(昭和最後の日)
sheet["B6"] = new DateTime(1989, 1, 8); // 平成1年1月8日
sheet["B7"] = new DateTime(2019, 4, 30); // 平成31年4月30日
sheet["B8"] = new DateTime(2019, 5, 1); // 令和1年5月1日
境界の前後 1 日もきちんと切り替わります。改元判定の if 文を自分で書いた経験のある方なら、このありがたみが分かるはずです。
「元年」問題 — カスタムフォーマッターで仕上げる
1 つだけ、JapaneseCalendar が面倒を見てくれないことがあります。上の例にもある通り、.NET は元号 1 年目を「平成1年」「令和1年」と表示します(Excel の ggge 書式も同じです)。しかし正式な文書では「平成元年」「令和元年」と書くのが慣例です。
ReoGrid のカスタムデータフォーマッターで仕上げます。IDataFormatter を実装して、1 年目だけ「元年」に置き換えます。
using System.Globalization;
using System.Text.RegularExpressions;
using unvell.ReoGrid;
using unvell.ReoGrid.DataFormat;
class WarekiGannenFormatter : IDataFormatter
{
static readonly CultureInfo wareki = new CultureInfo("ja-JP");
static WarekiGannenFormatter()
=> wareki.DateTimeFormat.Calendar = new JapaneseCalendar();
public string FormatCell(Cell cell)
{
if (cell.Data is not DateTime d) return null; // 日付以外はスキップ
var s = d.ToString("ggy年M月d日", wareki);
// 「令和1年」→「令和元年」(明治・大正・昭和・平成にも対応)
return Regex.Replace(s, @"(?<=[治正和成])1年", "元年");
}
public bool PerformTestFormat() => true;
}
正規表現の後読み (?<=[治正和成]) は各元号の末尾 1 文字(明治・大正・昭和/令和・平成)に続く「1年」だけを対象にするので、「平成11年」や「昭和21年」を誤って書き換えることはありません。
適用は、表示を差し替えたいセルにフォーマッターを設定するだけです。
sheet.Cells["B8"].CustomDataFormatter = new WarekiGannenFormatter();
// 表示: 令和元年5月1日
このとき SetRangeDataFormat の DateTime 書式はそのまま残しておいてください。表示はカスタムフォーマッターが優先されますが、編集確定時の「文字列 → DateTime 変換」はセルの DateTime 書式が担っているからです。表示と入力解釈で役割分担させる、という構図です。
印刷と保存はどうなるか
印刷は ReoGrid が画面と同じ描画エンジンで行うため、セルに表示されている和暦がそのまま紙(または PDF)に出ます。和暦の請求書・契約書をそのまま印刷できます — 手順は C# でスプレッドシートを印刷するを参照してください。
.xlsx への保存では、セルの値は文字列ではなく本物の日付として保存されます。これが文字列方式との決定的な違いです: ファイルを受け取った相手が Excel で開いても、日付として計算・ソート・フィルタできます。なお Excel 側の画面で和暦表示にしたい場合は、Excel の表示形式コードの流儀(ggge"年"m"月"d"日")でセル書式を指定してください — 前述の通り、.NET と Excel ではパターンの書き方が異なります。データが日付として生きているので、表示形式はいつでも後から変えられます。
おまけ: 年度(4月始まり)の集計
和暦と並ぶ日本の業務アプリのもう 1 つの定番が年度です。4月1日始まりなので、YEAR() をそのまま使うと 1〜3 月が前年度に紛れ込みます。
ReoGrid の数式エンジンは IF / MONTH / YEAR を内蔵しているので、年度はセル上の数式で出せます。
// B3 の日付が属する年度(西暦)
sheet["D3"] = "=IF(MONTH(B3)>=4, YEAR(B3), YEAR(B3)-1)";
「令和8年度」のような表示が必要なら、年度の開始日(4月1日)を和暦で書式化するヘルパーを 1 つ用意すれば済みます。
static string FiscalYearLabel(DateTime d)
{
var start = d.Month >= 4 ? new DateTime(d.Year, 4, 1)
: new DateTime(d.Year - 1, 4, 1);
return start.ToString("ggy", wareki) + "年度"; // 例: 令和8年度
}
年度もまた「データは DateTime、表示だけ変換」の原則で扱えば、集計・比較が壊れません。
まとめ
和暦対応の要点は、機能の話というより設計の話です。
- 日付を文字列にした瞬間、ソート・数式・フィルタ・書式変更のすべてが壊れる
- ReoGrid では
SetRangeDataFormatにggy年M月d日+ja-JPを渡すだけで、データをDateTimeのまま和暦表示できる —JapaneseCalendarへの切り替えは自動 - 入力された西暦文字列は確定時に
DateTimeへ変換されるので、「入力は西暦・表示は和暦」が自然に成立する - 「元年」表記だけは
IDataFormatterで一手間かける - 印刷は表示どおり、
.xlsx保存は本物の日付として — どちらも文字列方式では得られない性質
次に読むもの
- データ書式 — 数値・通貨・パーセントを含む書式 API の全体像(▲ 三角の負数表記など日本式もあります)
- カスタムデータ書式 —
IDataFormatterの詳細 - 約30行のC#で領収書発行アプリを作る — 和暦の日付欄を持つ帳票をテンプレート方式で
- 数式と計算エンジン —
=セルに書けるもの
