メインコンテンツまでスキップ

【VB.NET】IsDate関数の罠と対策

thumbnail

記事作成日: 2019/03/14
記事更新日: 2019/03/14

IsDate関数の問題について

VB.NETの関数に「IsDate」関数というのがあります。
(VBAの関数にも同様のものがありますが、サンプルコードなどはVB.NETで作成しています。)
この関数は対象の変数が日付になりうるかチェックすることができるもの。
しかしデータによってはエラーにならず、チェック処理をすり抜けるものがいます。

VB.NET実行プログラム

プログラムを用意しました。

Sub Main()

Dim chkDate As String

chkDate = "2018/03/04"
Debug.WriteLine(chkDate & " : " & IsDate(chkDate))

chkDate = "2018/3/4"
Debug.WriteLine(chkDate & " : " & IsDate(chkDate))

chkDate = "18/03/04"
Debug.WriteLine(chkDate & " : " & IsDate(chkDate))

chkDate = "18/3/4"
Debug.WriteLine(chkDate & " : " & IsDate(chkDate))

chkDate = "2018/3/814"
Debug.WriteLine(chkDate & " : " & IsDate(chkDate))

chkDate = "50/3/14"
Debug.WriteLine(chkDate & " : " & IsDate(chkDate))

chkDate = "14/3/50"
Debug.WriteLine(chkDate & " : " & IsDate(chkDate))

chkDate = "3/814"
Debug.WriteLine(chkDate & " : " & IsDate(chkDate))

chkDate = "1/3/814"
Debug.WriteLine(chkDate & " : " & IsDate(chkDate))

chkDate = "昭和99年5月10日"
Debug.WriteLine(chkDate & " : " & IsDate(chkDate))

chkDate = "平成99年5月10日"
Debug.WriteLine(chkDate & " : " & IsDate(chkDate))

chkDate = "平成99年5月"
Debug.WriteLine(chkDate & " : " & IsDate(chkDate))

chkDate = "5月平成99年"
Debug.WriteLine(chkDate & " : " & IsDate(chkDate))

chkDate = "3.1415"
Debug.WriteLine(chkDate & " : " & IsDate(chkDate))

End Sub

いろんなバリエーションの日付、もしくは日付風なデータをIsDate関数で日付かどうかチェックします。

VB.NETの実行結果

日付VB.NET
2018/03/04True
2018/3/4True
18/03/04True
18/3/4True
2018/3/814False
50/3/14True
14/3/50False
3/814True
1/3/814True
昭和99年5月10日True
平成99年5月10日True
平成99年5月True
5月平成99年False
3.1415True

Trueは「日付と認識しました」、Falseは「日付ではありません」という意味です。

ここで気を付けないといけないのが、赤太字にした部分。
「3/814」とか「3.1415」みたいな円周率の冒頭なども日付として扱われています。

この事象が発生する原因は?

事の発端ですが、ユーザーがパソコンのテンキーで
「3/14」という日付を入力しようとしました。 しかし、「3/814」と「/」の下にある8も
同時に打ってしまったがためにこの数字が生まれました。
この入力値は日付として認識され、そのまま後続処理でエラーになったのです。

いろんな日付表記に対応したため

上記の入力値を日付として認識された理由は、
海外に「日月年」という日付表記があり、「814年3月」と解釈されたからでした。
「3.1415」も「1415年3月」と認識されているからだと思います。

昭和や平成が「99年」って異常?

ちなみに、実行結果比較で昭和と平成が99年まで
表示されていることにお気づきでしょうか?

これはMicrosoftが例外エラーにはせず処理を通すようにしているからです。
元号に関しては今回は割愛しますが、
対応をしたい人はレジストリを書き換えてチェックする方法がよさそうです。

アプリケーションの新元号対応

日本語圏で使われている日付のチェックをしたい

話を戻します。

今回発生した「3/814」や「3.1415」は日付としては不適切です。
ですので、正規表現を使って日付のチェックをしたいと思います。

VB.NET実行プログラム(正規表現版)


''' <summary>
''' 日付の正規表現チェック
''' </summary>
''' <param name="inputDate"></param>
''' <returns></returns>
Public Function DateRegularExpression(inputDate As String) As Boolean

Const Regular As String = "^(?<year>[0-9]{4}|[0-9]{2})(?<datesep>\/|-|\.)(?<month>0?[1-9]|1[012])\k<datesep>(?<day>0?[1-9]|[12][0-9]|3[01])$"

If System.Text.RegularExpressions.Regex.IsMatch(inputDate, Regular) Then
Return True
End If

Return False

End Function

正規表現によって「yyyy/MM/dd」や「yy/MM/dd」は許可してそれ以外を拒否します。
これを以下のように呼び出して使います。

Debug.WriteLine(chkDate & " : " & DateRegularExpression(chkDate))

VB.NETの実行結果(正規表現版)

日付VB.NET
2018/03/04True
2018/3/4True
18/03/04True
18/3/4True
2018/3/814False
50/3/14True
14/3/50False
3/814False
1/3/814False
昭和99年5月10日False
平成99年5月10日False
平成99年5月False
5月平成99年False
3.1415False

明らかにデータとしておかしいものはすべてFalseになりました。
西暦表示がメインですので、和暦表示は日付ではないことになります。
お役所系は和暦表示が重要なので、
この辺りが必要な方は別途調整する必要がありますね。

今回はVB.NETで正規表現をしましたが、VBAでも正規表現ができます。
VBAを勉強している方も日付チェックで困っている方も
一度正規表現を試してみてください。

以上