はじめに

.NETで和暦を使うにはちょっとしたコツがあります。
そんな大げさな内容ではありませんが、.NETがどのように日付型と文字列変換とのやりとりを行っているかを知ることで、また.NETの面白さを再認識出来るかと思います。

和暦(文字列)→ 日付型

これは非常に簡単に行えます。
var dateTime1 = Convert.ToDateTime("H22/12/28");
var dateTime2 = Convert.ToDateTime("平成22/12/28");

var string1 = dateTime1.ToString();
var string2 = dateTime2.ToString();
実行結果は、string1, string2 共に同じ値で、2010/12/28 0:00:00 と和暦から日付型への変換が無事に行われたことがわかります。

日付型 → 和暦(文字列)

こちらは、単純な方法ではうまくいきません。
どんなフォーマットストリングを指定しても、むなしい結果に終わります。
いろいろと調べていくと、System.Globalizationに色々な情報があることに気が付きます。

今回ターゲットにするのは、

Calendar

CultureInfo

この二つになります。
var calendar = new System.Globalization.JapaneseCalendar();
var culture = new System.Globalization.CultureInfo("ja-JP");
culture.DateTimeFormat.Calendar = calendar;
var dateTime = DateTime.Parse("2011/01/07");
MessageBox.Show(dateTime.ToString("gyy/MM/dd", culture));
これを実行すると、「平成23/01/07」とメッセージボックスが表示されます。

日付型 → 和暦(文字列) その2

さて、平成(元号)まで変換できる事がわかったのですが、普段使うシステムででは、もう少し別の元号を使っていると思います。そう、元号記号の(M,T,S,H)ですね。

”平成”って変換ができるし、逆もまた可能(H22/12/28からの変換)なので、「2011/01/07」→「H23/01/07」も簡単にできるのでは?と思うと思います。

が、、、

簡単には変換することができません

今後は変わるかもしれませんが、、、

という事で、ライブラリのソースコードを探検してきました。
内部では、ちゃんと元号記号を管理しています。その部分をちょっとアクセスしてあげれば、元号記号を取り出す事ができます。

今回のターゲットは、

DateTimeFormatInfo

var formatInfo = default(System.Globalization.DateTimeFormatInfo);
var culture = new System.Globalization.CultureInfo("ja-JP");
var calendar = new System.Globalization.JapaneseCalendar();
formatInfo = culture.DateTimeFormat;
formatInfo.Calendar = calendar;
var eraName = "";
int era = formatInfo.Calendar.GetEra(DateTime.Now);
string eraString = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (int index = 0; index < eraString.Length; index++)
{
    if (formatInfo.GetEra(eraString[index].ToString()) == era)
    {
        eraName = eraString[index].ToString();
        break;
    }
}

これを実行すると、eraNameに元号記号が取得できます。
内部では、元号記号を管理していますので、その情報でつき合わせていけば最終的には値を取り出す事ができます。

日付型 → 和暦(文字列) その3

もっとストレートに取得したい場合は、、、内部の情報に直接手を伸ばして値を取得すればいいのです。
ただしこの方法は、ライブラリ内部の非公開のプロパティを直接触っていますので、.NETライブラリのバージョンや、更新により動かなくなる可能性があります。とはいえ、.NET1.1の頃から変わってなかったりします・・・
var formatInfo = default(System.Globalization.DateTimeFormatInfo);
var culture = new System.Globalization.CultureInfo("ja-JP");
var calendar = new System.Globalization.JapaneseCalendar();
formatInfo = culture.DateTimeFormat;
formatInfo.Calendar = calendar;
var type = typeof(System.Globalization.DateTimeFormatInfo);
var propertyInfo = type.GetProperty("AbbreviatedEnglishEraNames",
 System.Reflection.BindingFlags.NonPublic |
 System.Reflection.BindingFlags.Instance);
var abbrevEnglishEraNames = (string[])propertyInfo.GetValue(formatInfo, null);
int era = formatInfo.Calendar.GetEra(DateTime.Now);
var eraName = abbrevEnglishEraNames[era - 1];

型から非公開プロパティを文字列で指定して取り出しています。
どうしてもっていう場合以外は、その2の方法を使った方が良いと思います。

ここまでを押さえておけば、.NETでの和暦の扱いには困らないと思います。

更新日

2011/01/07:内容修正
2011/01/01:アップ