DOBON.NET DOBON.NETプログラミング掲示板過去ログ

DateTime.TryParse と新元号について

環境/言語:[WinXP C#]
分類:[.NET]

お世話になっております、梅のど飴と申します。

現在 VS2005 C#2.0 で開発を行っているのですが、日付を入力する項目で
"2009/03/03"や"H21.3.3"や"3/3"と言った様々な入力様式をサポートして
日付型に変換すると要件が有ります。

そして以下の様なコーディングを行う事により、9割ほどの要件を満たす
事が出来たのですが、ただ一点…未来元号への対応がどうしても出来ずに
います。

※新元号への対応は Windows Update に任せればいいと言うのは重々承知
 しているのですが、そこは大人の事情と言う事で追及しないで下さい。


どぼん.NETの過去ログにて JapaneseCalendar の内容を変更して未来元号
を表示すると言う記事を見つける事が出来たのですが、それを TryParse
の変換処理とどう組み合わせれば良いのかがわかりません。

DateTime.TryParse を使いつつも、新元号に自力で対応させる方法があり
ましたら教えて頂けないでしょうか。


[参考記事]
http://dobon.net/vb/bbs/log3-5/2481.html

新元号を追加した JapaneseCalendar(?) を一度でも作成すると、下記の
処理その物が正常に動作しなくなります。

"2009/3/3"を指定すると、期待値は"2009/03/03"なのですが(無変換)
"年号の値が有効ではありません。パラメータ名: era"と言うエラーが
発生します。


[現在のソース]

private bool DateTryParse(string text, out DateTime date)
{
// 2バイトの数字は1バイトに置換 ("平成21年3月3日"→"平成21年3月3日"で変換可能)
text = Microsoft.VisualBasic.Strings.StrConv(text, Microsoft.VisualBasic.VbStrConv.Narrow, 0);

System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.CurrentCulture;

bool ret = DateTime.TryParse(text, culture, System.Globalization.DateTimeStyles.None, out date);

if (!ret)
{
// 特殊入力に対応 20090303, 090303, 0303, 033
string[] fmt = new string[4] { "yyyyMMdd", "yyMMdd", "MMdd", "MMd" };
ret = DateTime.TryParseExact(text, fmt, culture, System.Globalization.DateTimeStyles.None, out date);
}

return ret;
}

// 新元号を追加するテストメソッド フォームのOnLoadなどで実行?
private static DateTimeFormatInfo Test()
{
// DateTimeFormatInfo 作成
JapaneseCalendar japaneseCalendar = new JapaneseCalendar();
CultureInfo cultureInfo = new CultureInfo("ja-JP");
DateTimeFormatInfo dateTimeFormatInfo = cultureInfo.DateTimeFormat;
dateTimeFormatInfo.Calendar = japaneseCalendar;

// JapaneseCalendar の Type を取得
Type japaneseCalendarType = typeof(System.Globalization.JapaneseCalendar);

// helper を取得
FieldInfo helperFieldInfo = japaneseCalendarType.GetField("helper",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
object helper = helperFieldInfo.GetValue(dateTimeFormatInfo.Calendar);

// GregorianCalendarHelper の Type を取得
Type helperType = helperFieldInfo.FieldType;

// m_EraInfo を取得
FieldInfo eraInfoFieldInfo = helperType.GetField("m_EraInfo",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
Array eraInfo = (Array)eraInfoFieldInfo.GetValue(helper);

// EraInfo の Type を取得
Type eraInfoType = eraInfo.GetValue(0).GetType();

// m_EraInfo に設定する配列を作成
Array new_EraInfo = Array.CreateInstance(eraInfoType, 5);

// 要素 0 に新しく作成した EraInfo を設定
// 2010/7/30 から新しい元号に
new_EraInfo.SetValue(eraInfoType.Assembly.CreateInstance(
eraInfoType.FullName, false, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static,
null, new object[] { 5, (new DateTime(2010, 7, 30)).Ticks, 2009, 1, 7990 }, cultureInfo, null), 0);

// '平成' の最終年を 22 (= 2010 - 1989 + 1) に変更
FieldInfo maxEraYearFieldInfo = eraInfoType.GetField("maxEraYear",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
maxEraYearFieldInfo.SetValue(eraInfo.GetValue(0), 22);

// 明治〜平成の分をコピーして m_EraInfo (GregorianCalendarHelper) に設定
eraInfo.CopyTo(new_EraInfo, 1);
eraInfo = new_EraInfo;
eraInfoFieldInfo.SetValue(helper, eraInfo);

// m_EraInfo (JapaneseCalendar) に設定
FieldInfo eraInfoFieldInfo2 = japaneseCalendarType.GetField("m_EraInfo",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
eraInfoFieldInfo2.SetValue(japaneseCalendar, eraInfo);

// m_eras
FieldInfo erasFieldInfo = helperType.GetField("m_eras", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
int[] eras = (int[])erasFieldInfo.GetValue(helper); // 取得
eras = new int[] { 5, 4, 3, 2, 1 }; // 編集
erasFieldInfo.SetValue(helper, eras); // 設定

// DateTimeFormatInfo の Type を取得
Type dateTimeFormatInfoType = typeof(System.Globalization.DateTimeFormatInfo);

// m_eraNames を取得 (Porperty Get されるまで Null のようなのでプロパティから読み出し)
PropertyInfo eraNamesPropertyInfo = dateTimeFormatInfoType.GetProperty("EraNames",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);

string[] eraNames = (string[])eraNamesPropertyInfo.GetValue(dateTimeFormatInfo, null);

// 新元号を追加
string[] new_eraNames = new string[5];
new_eraNames[4] = "○○";
eraNames.CopyTo(new_eraNames, 0);

// m_eraNames に設定
FieldInfo eraNamesFieldInfo = dateTimeFormatInfoType.GetField("m_eraNames",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);

eraNamesFieldInfo.SetValue(dateTimeFormatInfo, new_eraNames);

// m_abbrevEraNames を取得 (Porperty Get されるまで Null のようなのでプロパティから読み出し)
PropertyInfo abbrevEraNamesPropertyInfo = dateTimeFormatInfoType.GetProperty("AbbreviatedEraNames",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);

string[] abbrevEraNames = (string[])abbrevEraNamesPropertyInfo.GetValue(dateTimeFormatInfo, null);

// 新元号の略称を追加
string[] new_abbrevEraNames = new string[5];
new_abbrevEraNames[4] = "○";
abbrevEraNames.CopyTo(new_abbrevEraNames, 0);

// m_abbrevEraNames に設定
FieldInfo abbrevEraNamesFieldInfo = dateTimeFormatInfoType.GetField("m_abbrevEraNames",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
abbrevEraNamesFieldInfo.SetValue(dateTimeFormatInfo, new_abbrevEraNames);

// m_abbrevEnglishEraNames を取得 (Porperty Get されるまで Null のようなのでプロパティから読み出し)
PropertyInfo abbreviatedEnglishEraNamesPropertyInfo = dateTimeFormatInfoType.GetProperty("AbbreviatedEnglishEraNames",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);

string[] abbreviatedEnglishEraNames = (string[])abbreviatedEnglishEraNamesPropertyInfo.GetValue(dateTimeFormatInfo, null);

// 新元号の略称(アルファベット)を追加
string[] new_abbreviatedEnglishEraNames = new string[5];
new_abbreviatedEnglishEraNames[4] = "Z";
abbreviatedEnglishEraNames.CopyTo(new_abbreviatedEnglishEraNames, 0);

// m_abbrevEnglishEraNames に設定
FieldInfo abbreviatedEnglishEraNamesFieldInfo = dateTimeFormatInfoType.GetField("m_abbrevEnglishEraNames",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
abbreviatedEnglishEraNamesFieldInfo.SetValue(dateTimeFormatInfo, new_abbreviatedEnglishEraNames);

//// Calendar の Type を取得
//Type calendarType = typeof(System.Globalization.Calendar);

//// m_currentEraValue を設定
//PropertyInfo currentEraValuePropertyInfo = calendarType.GetProperty("CurrentEraValue",
// BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
//int currentEraValue = (int)currentEraValuePropertyInfo.GetValue(japaneseCalendar, null);
//FieldInfo currentEraValueFieldInfo = japaneseCalendarType.GetField("m_currentEraValue",
// BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
//currentEraValueFieldInfo.SetValue(japaneseCalendar, 5);

return dateTimeFormatInfo;
}
お世話になっております、まこと 改め 梅のど飴 です。

特に他意は無いのですが、こちらの掲示板では「まこと」で「C# と VB.NET の質問掲示板」
では「梅のど飴」として名乗らせて頂いております。

件の「DateTime.TryParse と新元号について」は「C# と VB.NET の質問掲示板」の方にのみ
書き込みした内容なのですが、どなたかが私の許可なくマルチポストされた様です(-_-;


マルチポストされた方へ:

私の質問に対して興味を持って頂けた事は有りがたく思うのですが、レスが無いからと言って
このような行動はお止め下さい、内容だけならまだしも、名前まで同じにされると余り気分の
良い物では有りませんので。

もしも私と同様の問題を抱えており、解決方法を知りたいと言う事でしたら「C# と VB.NET の
質問掲示板」の方にその旨を書込んで、あちらの参加者の方々からの協力をお願いするか
ご自分のお名前と書込みを持ってこちらの掲示板に新規スレッドを立てて下さい。

以上です。

DOBON.NET | プログラミング道 | プログラミング掲示板