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

vb.net 日付について

環境/言語:[VB.NET]
分類:[.NET]

2011/05/11(Wed) 13:13:38 編集(投稿者)
2011/05/11(Wed) 13:13:16 編集(投稿者)

DVDの発売日の検索画面を作っています。
テキストボックスに入力された文字列を日付に変更したいのですが、
まず、入力された文字列が日付かどうかをIsDateで判断し、
CdateとToString("yyyy/MM/dd")で日付型に変換しています。

If IsDate(Me.Text_Day.Text) = False Then
MessageBox.Show("日付を入力してください。")
e.Cancel = True
End If

Me.Text_Day.Text = CDate(Me.Text_Day.Text).ToString("yyyy/MM/dd")

しかし、これではテキストボックスに20110511と入力された場合、IsDateでは日付だと判断されないことと、
CDateはOS環境に依存することが多く、あまり使わない方がよいと聞いたことがあります。

テキストボックスに入力された文字列が日付と認識できるものはすべてyyyy/MM/ddの日付型に変換したい
(5/11, 2011年5月11日, 20110511, 2011.5.11, 2011-5-11, 平成23年5月11日などなど -> 2011/05/11)
のですが、
何かいい方法はありませんでしょうか。
  • 題名: Re[1]: vb.net 日付について
  • 著者: 風太郎
  • 日時: 2011/05/11 13:47:22
  • ID: 28558
  • この記事の返信元:
  • この記事への返信:
    • (なし)
  • ツリーを表示
■No28557に返信(むちかさんの記事)
> 2011/05/11(Wed) 13:13:38 編集(投稿者)
> 2011/05/11(Wed) 13:13:16 編集(投稿者)
>
> DVDの発売日の検索画面を作っています。
> テキストボックスに入力された文字列を日付に変更したいのですが、
> まず、入力された文字列が日付かどうかをIsDateで判断し、
> CdateとToString("yyyy/MM/dd")で日付型に変換しています。
>
> If IsDate(Me.Text_Day.Text) = False Then
> MessageBox.Show("日付を入力してください。")
> e.Cancel = True
> End If
>
> Me.Text_Day.Text = CDate(Me.Text_Day.Text).ToString("yyyy/MM/dd")
>
> しかし、これではテキストボックスに20110511と入力された場合、IsDateでは日付だと判断されないことと、
> CDateはOS環境に依存することが多く、あまり使わない方がよいと聞いたことがあります。
>
> テキストボックスに入力された文字列が日付と認識できるものはすべてyyyy/MM/ddの日付型に変換したい
> (5/11, 2011年5月11日, 20110511, 2011.5.11, 2011-5-11, 平成23年5月11日などなど -> 2011/05/11)
> のですが、
> 何かいい方法はありませんでしょうか。

どうしてもTextBoxを使う必要がありますか?
もしそうでなければ、DateTimePickerというコントロールがありますよ。
CustomFormatを"yyyy/MM/dd"
FormatをCustomに指定すればいいかと。

入力された後で、判断/加工という方法もありますが
予め入力させないという方法はいかがでしょうか?
■No28557に返信(むちかさんの記事)

DateTime.TryParseExactで認識させたいすべてのパターンを試すとよいかと
思います。

例)
        For Each src In {"2011/5/4", "2011/05/01", "6/3", "12/3", "2011年5月15日", "20110807", "平成15/5/4", "平成19年10月15日"}
            Dim dtTmp As Date = Nothing
            For Each fmt In {"yyyy/M/d", "M/d", "yyyy年M月d日", "yyyyMMdd"}
                If DateTime.TryParseExact(src, fmt, Nothing, Globalization.DateTimeStyles.None, dtTmp) Then
                    Exit For
                End If
            Next

            If dtTmp = Nothing Then
                '--- 和暦
                Dim jpinfo As New CultureInfo("ja-JP", True)
                jpinfo.DateTimeFormat.Calendar = New JapaneseCalendar()
                For Each fmt In {"ggyy/M/d", "ggyy年M月d日"}
                    If DateTime.TryParseExact(src, fmt, jpinfo, DateTimeStyles.None, dtTmp) Then
                        Exit For
                    End If
                Next
            End If

            Console.Write(src & " => ")
            If dtTmp = Nothing Then
                Console.WriteLine("Nothing")
            Else
                Console.WriteLine(dtTmp)
            End If
        Next
TextBox なら shu さんの方法が適切かなと思います。
あるいは Grapecity さんの GcDate コントロールなら、Fields と DisplayFields をデザイナで設定すればノンコーディングでできますね。

# shu さんの TryParse メソッド系のネタは、これで 3 回目のような気がする... (^-^;
■No28560に返信(じゃんぬねっとさんの記事)

> # shu さんの TryParse メソッド系のネタは、これで 3 回目のような気がする... (^-^;

今回は8桁の数字で明示的に日付に対応できるものだけが対象ではなかったのでTryParseExactを使ってみました。
2011/05/11(Wed) 19:06:59 編集(投稿者)
2011/05/11(Wed) 18:18:02 編集(投稿者)
2011/05/11(Wed) 18:09:23 編集(投稿者)

風太郎さん、どうもありがとうございます。
今回はテキストボックスを使う練習なので、どうにかテキストボックスでの解決法を模索していました。
しかし、この機会にDateTimePickerというコントロールがあることを覚えることができました。

shuさん、じゃんぬねっとさんありがとうございます。
今まで2時間ほど格闘しておりました。


'yyyy/M/dのとき
If System.Text.RegularExpressions.Regex.IsMatch(Me.Text_Publication_Day.Text, "\d\d\d\d/\d?\d/\d?\d") Then
If DateTime.TryParseExact(Me.Text_Day.Text, "yyyy/M/d", Nothing, Globalization.DateTimeStyles.None, dtTmp) Then
Me.Text_Day.Text = dtTmp.ToString
Exit Sub
End If
End If

'yyyyMMddのとき
If System.Text.RegularExpressions.Regex.IsMatch(Me.Text_Day.Text, "\d{8}") Then
If DateTime.TryParseExact(Me.Text_Publication_Day.Text, "yyyyMMdd", Nothing, Globalization.DateTimeStyles.None, dtTmp) Then
Me.Text_Day.Text = dtTmp.ToString
Exit Sub
End If
End If
.
.
.
'その他の場合はキャンセル
MessageBox.Show("日付を入力してください。")
e.Cancel = True



というように、1つずつ認識させていく形式で書いてみました。
正規表現を使ってテキストボックスの値を取得しているのですが、
月日のところで、\d\d\d\d/\d?\d/\d?\dと書かず、\d\d\d\d/\d/\dと書いても月日が2桁の場合もエラーが出ずに表示されるのですが、
\dというのは1文字を表す文字ではなかったかなと混乱しております。
また、私の環境では、CultureInfoとJapaneseCalendarが定義されていないとエラーがでるため、和暦がまだ対応できておりません…

※追記
和暦の問題ですが、Imports SystemとImports System.Globalizationが抜けていた為でした。
無事和暦の変換もできるようになりました。
■No28562に返信(むちかさんの記事)

> If System.Text.RegularExpressions.Regex.IsMatch(Me.Text_Publication_Day.Text, "\d\d\d\d/\d?\d/\d?\d") Then

> If System.Text.RegularExpressions.Regex.IsMatch(Me.Text_Day.Text, "\d{8}") Then

この2つの判定はあまり意味がないです。TryParseExactだけでこれらの判定も
おこなわれてしまい、この条件を満たしてもTryParseExactで失敗することも
ある。どちらでTryParseExactするかを事前に判定するならこの場合、IndexOfで"/"を検索する程度で十分かと思います。



> ※追記
> 和暦の問題ですが、Imports SystemとImports System.Globalizationが抜けていた為でした。
> 無事和暦の変換もできるようになりました。
省略してしまい分かりにくかったですね。Globalizationを途中まで記述してたのですが途中でImportsに変えたためこのようになってしまいました。
2011/05/12(Thu) 11:54:43 編集(投稿者)

■No28562に返信(むちかさんの記事)
> 月日のところで、\d\d\d\d/\d?\d/\d?\dと書かず、\d\d\d\d/\d/\dと書いても月日が2桁の場合もエラーが出ずに表示されるのですが、
> \dというのは1文字を表す文字ではなかったかなと混乱しております。

\dは1文字です。以下のコードを書いて
.NET Framework3.5のvbc.exeでコンパイルしたexeで実験して確認しました。

ちなみ「\d\d\d\d/\d?\d/\d?\d」は「\d{4}/\d{1,2}/\d{1,2}」のように書くことができます。参考まで。

-- 以下、実験コード --
' test.vbファイルに以下のコードを記載。test.exeにコンパイル
' コンパイル:vbc /out:test.exe test.vb
' 実行方法:コマンドラインから「test.exe 2010/1/2」のように実行
' ?ありの正規表現なら日付が表示され、?なしの正規表現では何も表示されない(想定される通りの動作)
Module A
    Sub Main(ByVal args As String())
        Dim text As String = args(0)
        Dim dtTmp As Date

        ' "\d\d\d\d/\d\d/\d\d"と"\d\d\d\d/\d?\d/\d?\d"で実験
        If System.Text.RegularExpressions.Regex.IsMatch(text, "\d\d\d\d/\d\d/\d\d") Then 
            If Date.TryParseExact(text, "yyyy/M/d", Nothing, Globalization.DateTimeStyles.None, dtTmp) Then
                Console.WriteLine(dtTmp.ToString)
                Exit Sub
            End If
        End If
    End Sub
End Module
  • 題名: Re[6]: vb.net 日付について
  • 著者: むちか
  • 日時: 2011/05/12 17:04:01
  • ID: 28566
  • この記事の返信元:
  • この記事への返信:
    • (なし)
  • ツリーを表示
shuさん
何度もありがとうございます。
確かに無くとも動きました。

'ggyy年M月d日(和暦)のとき
If System.Text.RegularExpressions.Regex.IsMatch(PDay, "(明治|大正|昭和|平成)元年\d?\d月\d?\d日") Then
PDay = PDay.Replace("元", "1")
End If
If DateTime.TryParseExact(PDay, "ggyy年M月d日", jpinfo, DateTimeStyles.None, dtTmp) Then
PDay = dtTmp.ToString
End If

と元年の部分だけで使用することにしました。

よねKENさん
ありがとうございます。
しっくりこないところがありましたので、助け船を頂き感謝しています。
解決済み!

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