VB.NETによる和暦→西暦変換

2019年5月1日から元号が平成から令和へと変わりますが、2019/4/20時点で、Windowsや.NetFrameworkが新元号にまだ対応していません。
5月1日まで残り僅かで、元号を取り扱うアプリでは修正作業が必要な場合があります。

VB.NETでは、[CType(expression, typename)](https://docs.microsoft.com/ja-jp/dotnet/visual-basic/language-reference/functions/ctype-function)を利用してオブジェクトを`Date`型にする変換する際、和暦から西暦に変換する事が出来ます。

### 変換例
頭文字に`平成`、`H`、`h`文字があり尚且つ`/`、`-`などの区切り文字があると和暦から西暦へ変換します。

``` vb
Console.WriteLine(CType("平成31年4月21日", Date).Date.ToString("yyyy/MM/dd"))
' 2019/04/21
Console.WriteLine(CType("H31/4/21", Date).Date.ToString("yyyy/MM/dd"))
' 2019/04/21
Console.WriteLine(CType("H31.4.21", Date).Date.ToString("yyyy/MM/dd"))
' 2019/04/21
Console.WriteLine(CType("H31-4-21", Date).Date.ToString("yyyy/MM/dd"))
' 2019/04/21
Console.WriteLine(CType("H31 4 21", Date).Date.ToString("yyyy/MM/dd"))
' 2019/04/21
Console.WriteLine(CType("h31-4-21", Date).Date.ToString("yyyy/MM/dd"))
' 2019/04/21
```
###問題点
`CType`による変換ですが、殆どのケースで期待する和暦→西暦変換になり大変便利なのですが、新元号の登場により取扱方によっては問題が発生します。
１．Windows Update前に、令和（R01）を入力した場合、変換エラーになる。
２．Windows Update後に、来年以降の平成（H32）を入力した場合、変換エラーになる可能性が高い。

###変換範囲
`CType`による変換では、昭和・平成が混在する年については新旧どちらでも期待する西暦に変換出来ます。
しかし、翌年以降は旧和暦（昭和）を西暦変換出来ません。
また、R（令和）については未対応なので必ず変換エラーになります！※2019/4/20時点　近日中にWindows Updateで改善する筈。。。
入力する和暦を`Ggg/mm/dd`フォーマットと仮定して、変換結果を調べてみました。

| 入力 | 期待する西暦 | 結果 | 備考 |
|:-:|:-:|:-:|:--|
| S64/01/01  | 1989/01/01 | ○  |
| S64/12/31  | 1989/12/31 | ○  | 昭和は1月7日迄ですが年内は変換可能
| S65/01/01  | 1990/01/01 | ×  | 翌年以降は昭和の変換が不可能
| H01/01/01  | 1989/01/01 | ○  | 平成元年は1月8日からですが年内は変換可能
| H01/12/31  | 1989/12/31 | ○  | 年内は平成・昭和どちらでも変換可能
| H02/01/01  | 1990/01/01 | ○  | 翌年からは平成のみ変換可能
| H31/05/01  |  2019/05/01 | ○  | 
| H32/01/01  |  2020/01/01 | ○  | 本来は令和2年ですが、平成でも変換可能 ※
| H99/01/01  |  2087/12/31 | ○  | 本来は令和69年ですが、平成でも変換可能 ※
| R01/05/01  |  2019/05/01 | ×  | 現時点では`R`を元号と認識しません
※令和対応のWindows Update後、変換エラーになる可能性大

###対応策
ファンクションに和暦を投げて、西暦に変換して返します。
変換出来ない場合は、`1900/01/01`になります。
尚、和暦はアルファベットのみ対応なので、`元号gg年mm月dd日`のフォーマットの場合はもう少し修正が必要です。

```vb:ConsoleSample.vb
    Sub Main()
        Dim obj As Object = "H31/5/1"
        Debug.Print(GengoToDate(obj).ToString("yyyy/MM/dd"))
    End Sub

    Function GengoToDate(ByVal obj As Object) As Date

        Dim rslt As Date

        If obj Is DBNull.Value OrElse obj = "" Then
            rslt = CType("1900/01/01", Date)
        Else
            ' 頭文字を取得
            Dim hc As String = CType(obj, String).Substring(0, 1)

            If IsNumeric(hc) Then
                ' 西暦
                If hc = "1" OrElse "2" Then
                    rslt = CType(obj, Date)
                Else
                    rslt = CType("1900/01/01", Date)
                End If

            Else
                ' 和暦
                ' 区切り文字で年・月・日に分割
                Dim arr As String() = {"/", ".", "-", " ", ""}
                Dim ggmmdd As String() = {""}
                For Each a As String In arr
                    If CType(obj, String).Contains(a) Then
                        ggmmdd = Split(CType(obj, String), a)
                        Exit For
                    End If
                Next

                If ggmmdd.Length = 3 And hc.ToUpper = "H" Then
                    ' 平成
                    If CType(ggmmdd(0).Remove(0, 1), Int16) >= 30 Then
                        '来年以降は変換エラーになる可能性があるため、当年も含め手動で変換する
                        rslt = CType(String.Join("/", {ggmmdd(0).Remove(0, 1) + 1988, ggmmdd(1), ggmmdd(2)}), Date)
                    Else
                        ' 昨年以下は、そのまま変換
                        rslt = CType(obj, Date)
                    End If
                ElseIf ggmmdd.Length = 3 And hc.ToUpper = "R" Then
                    ' 令和
                    ' MS側の対応より先回りして対応
                    rslt = CType(String.Join("/", {ggmmdd(0).Remove(0, 1) + 2018, ggmmdd(1), ggmmdd(2)}), Date)
                Else
                    rslt = CType("1900/01/01", Date)
                End If
            End If
        End If

        Return rslt
    End Function

```
###最後に
和暦なんて関係無いと思っても意外なケースでシステムに関係してくるので注意しましょう〜