はじめに
System.DateTime
をR1.11.23
のように表示したい場面があり,少し苦戦したため備忘録を兼ねて方法をまとめておきます。
和暦表示
漢字
和暦を表示するだけであれば比較的簡単に行うことができます。
using System.Globalization;
var cultureJp = new CultureInfo("ja-jp", false);
cultureJp.DateTimeFormat.Calendar = new JapaneseCalendar();
var dt = new DateTime(2019, 11, 23);
Console.WriteLine(dt.ToString("ggy年M月d日", cultureJp)); // 令和元年11月23日
このようにg
またはgg
という書式指定子で元号を取得できます。
(この記事を書くときに知ったのですが1年ではなく元年になるのですね…1)
アルファベット
ところが,RやHのようにアルファベットの略号で元号を表したい場合にはめんどくさいことになります。
アルファベット1文字の元号を表す書式指定子がないのです。
ところが,Microsoftが手を抜いて元号の略称を見なかったことにしたのかと言うとそうではなく,DateTime.Parse
は元号の略称に対応しています。
例えば
var dt = DateTime.Parse("R1.11.23"); // [2019/11/23 0:00:00]
と言った感じの文字列を認識してくれます。
この非対称性は気持ち悪いのですが文句を言っていても仕方がないので受け入れるしかありません。
辞書による置換
極めて単純な解決策として,文字列の置換で強引に対応するというものがあります。
しかし,対応をハードコードしてしまうと改元の度に修正が必要になってしまうため,ベストプラクティスではないでしょう。
時代 (年号) を表す整数
.NET Frameworkでは元号を表す整数というものがあるそうです。
これが何かというと明治が1,大正が2,昭和が3……といった感じです。
アルファベット表記を実装するために,この整数を利用します。
この整数は,Calendar.GetEra
メソッドにより取得できます。
var index = cultureJp.DateTimeFormat.GetEra(dt); // 5 など
この整数を利用してアルファベットの略号を取得するのですが,その対応をハードコードしてしまっては意味がありません。
この整数は,DateTimeFormatInfo.GetEra
なるメソッドでも取得することができます。
これは先ほどのDateTime.Parse
と同様に略号を認識してくれるため,"R"
を食わせると5
を返してくれます。
このメソッドを利用して,整数と略号の対応を作っておきます。
var eras = new Dictionary<int, string>();
for (var e = 'A'; e <= 'Z'; e++)
{
var E = e.ToString();
var index = cultureJp.DateTimeFormat.GetEra(E);
if (index > 0)
eras.Add(index, E);
}
このメソッドはinvalidな元号(の略号)に対しては-1を返すため,整数と略号の対応を作ることができます。
このようにして対応を作っておけば,あとはこれを参照するだけです。
var e = cultureJp.DateTimeFormat.Calendar.GetEra(dt);
eras[e] + dt.ToString("y.M.d", cultureJp); // R.1.11.23
さいごに
元号周りは元々ややこしい話ではあるのですがもう少し使い勝手のいいライブラリが欲しいものです。
JapaneseCalendarの実装を見てみるとすごいなぁという気持ちになります。
参考文献
-
"y.M.d"
のようにすると1.11.23
になりました。どうなってるんだ…… ↩