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/04 | True |
2018/3/4 | True |
18/03/04 | True |
18/3/4 | True |
2018/3/814 | False |
50/3/14 | True |
14/3/50 | False |
3/814 | True |
1/3/814 | True |
昭和99年5月10日 | True |
平成99年5月10日 | True |
平成99年5月 | True |
5月平成99年 | False |
3.1415 | True |
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/04 | True |
2018/3/4 | True |
18/03/04 | True |
18/3/4 | True |
2018/3/814 | False |
50/3/14 | True |
14/3/50 | False |
3/814 | False |
1/3/814 | False |
昭和99年5月10日 | False |
平成99年5月10日 | False |
平成99年5月 | False |
5月平成99年 | False |
3.1415 | False |
明らかにデータとしておかしいものはすべてFalseになりました。
西暦表示がメインですので、和暦表示は日付ではないことになります。
お役所系は和暦表示が重要なので、
この辺りが必要な方は別途調整する必要がありますね。
今回はVB.NETで正規表現をしましたが、VBAでも正規表現ができます。
VBAを勉強している方も日付チェックで困っている方も
一度正規表現を試してみてください。
以上