経理屋とVBAの日記

経理業務で役に立つかもしれないExcel/Access VBAのネタを書きます

【.NET】ParseExact関数に渡す文字列から元号を省略したときの挙動

結論

レジストリに登録されている最新の元号が補完される。

"300110"

この数列が何を表しているか分かりますか?
そう、日付です。平成30年01月10日です。分かりませんね。


 今回諸般の事情でこのような形のデータを処理しなければならなくなり、また改元にも対応しなくてはということでJapaneseCalendarクラスについて色々と調べてみたのですが、標題の疑問が解決しなかったので自分でテストしてみました。

テスト1

さくっと書きます(System.Globalization名前空間を使います)。

Dim ConvertJapaneseDate =
    Function(targetDate As String, targetFormat As String) As Date
        Dim cultureJapan As CultureInfo = New CultureInfo("ja-JP", True)
        cultureJapan.DateTimeFormat.Calendar = New JapaneseCalendar()
        Return DateTime.ParseExact(targetDate, targetFormat, cultureJapan)
    End Function

Debug.Print(ConvertJapaneseDate("30/01/10", "yy/MM/dd"))

結果:
f:id:nicco_mirai:20180125233504p:plain


ちゃんと変換されてる。ちゃんとというか指定してないのに平成扱いされました。

テスト2

さて、JapaneseCalendarクラスが何を元に元号を処理しているかと言えば、レジストリです。
regeditで下記のフォルダを覗いてみましょう。
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras
f:id:nicco_mirai:20180125233506p:plain


ありました。
試しにここに新しい値を追加して…
f:id:nicco_mirai:20180125233509p:plain


先ほどのコードを走らせると…
f:id:nicco_mirai:20180125233511p:plain


結果が変わりました。

最終テスト

ここで冒頭の疑問に立ち返りますが、では一体この中からどんな基準で元号を補完しているのでしょうか。
考えられるのはシステム日付でしょう。つまり「レジストリとシステム日付から現在の元号を取得し補完している」という仮説です。


レジストリに未来日付を登録し…
f:id:nicco_mirai:20180125233632p:plain


Debug.Print(ToDay)を加えて実行します。
今日は2018年の1月25日です。


結果:
f:id:nicco_mirai:20180125233513p:plain


はい。というわけでシステム日付は関係ありませんでした。常に最新の元号が補完されるようです。

補足

これでデフォルトの挙動は掴めましたが、やはり自分で元号を明示的に補完した方が圧倒的に安心です。
よほど楽がしたいでもなければ

Dim regKey As Microsoft.Win32.RegistryKey =
    Microsoft.Win32.Registry.LocalMachine.OpenSubKey("SYSTEM\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras", False)
Dim eraDic As New Dictionary(Of Date, String)
For Each eName In regKey.GetValueNames
    eraDic.Add(CDate(eName.Replace(" ", "/")), regKey.GetValue(eName))
Next

等で元号の一覧を拾って自分で日付に加えてあげるといいんじゃないかと思います。