はもちくわ

コードについて自分なりの解釈を書いてます。

【Excel VBA】文字列で自由入力された日付をデータにした話

とてもバカらしい話なのですが、Excelつかっているのに、入力データが揃ってない事って多いですよね?
特に1つのセルへ日付や時間の入力が文字列でされている場合、人によって癖があり、バリエーションが広い。

例えば

  • 2021年4月1日 9:00
  • 4月1日 9時
  • 4月1日 AM9:00
  • 4/1(月)
  • 4月1日(月曜日)
  • 4月1日(月曜)9時

せっかくExcel使っているのに、人が目で見ないと区別できない紙ベースと同じとは・・・・。
これが自社、担当部所内なら入力ルール作るとか、セルを分けるとか方法がありますが、これが取引先だと(笑)

お手上げですよね。

 

このような状態で、ほぼ毎営業日にくるExcelファイルをVBAで自動化してCSVファイルに格納しなければならなくなり、一つ一つ癖をキャンセルしながら、なんとか解決できた時、バカバカしい・・・と虚しく思ったのでコード紹介しながら愚痴ってみます。

とはいえ、入力者のクセによって対応は変わるので、誰に対しても完全に対応できるものではありません。
もし、同じような事でお困りの方はヒントになるかと思います(笑)



VBAの使い方などは全部すっとばして、いきなりコード書きます。

「B2」セルに入力されているものとし、日付と時間が一緒に書いてあるものとします。

結果を「B3」にでも表示しましょうかね。


    Dim buf As Variant, pm As Integer
    Dim buf_day As Variant, buf_hour As Variant
    Dim jikan As Integer
    Dim re_hour As Variant, re_day As Variant
    
    buf = StrConv(Range("B2"),vbNarrow) 'すべて半角にする
    
    If IsDate(buf) Then
      ’もし日付データとしてそのまま使えるならそのまま入れる
        Range("B3")=buf
    else
       'PMとか午後とか書いてあったら時間に12をプラスする準備
        pm = 0
        If Instr(buf,"PM")>0 or Instr(buf,"午後")>0 Then
            pm = 12
        End If
    
        buf = Replace(buf," ","")'半角スペースを消す
        buf = Replace(buf,"AM","")'AMを消す
        buf = Replace(buf,"午前","")'午前を消す
        buf = Replace(buf,"PM","")'PMを消す
        buf = Replace(buf,"午後","")'午後を消す
        buf = Replace(buf,"曜日","")'曜日を消す
        buf = Replace(buf,"曜","")'曜を消す
        buf = Replace(buf,"(月)","()")'(月)の月だけ消す 下の月に干渉するため
        buf = Replace(buf,"(日)","()")'(日)の日だけ消す 下の日に干渉するため
        buf = Replace(buf,"年","/")'年を/にする
        buf = Replace(buf,"月","/")'月を/にする
        buf = Replace(buf,"日","")'日を消す
        buf = Replace(buf,"時",":")'時を:にする
    
        buf_hour = Split(buf,")")'曜日の後ろカッコで2分割
        '後半が空白なら時間は0:00にしておく
        If buf_hour(1)<>"" Then 
           jikan = 0
        else
           re_hour = Split(buf_hour(1),":")’2分割の後半を:でさらに2分割 
           jikan = val(re_hour(0)) + pm
        end if
        
        buf_day = Split(buf,"/")'/で分割する
        Select Case UBound(buf_day)
             Case 1 '月日だけ表示の場合
                re_day = Split(buf_day(1),"(")’/で分割した後半を曜日の(で分割
                Range("B3") = buf_day(0) & "/" & re_day(0) & " " & jikan & ":00"
             Case 2 '年月日表示の場合
                re_day = Split(buf_day(2),"(")’/で分割した最後を曜日の(で分割
                Range("B3") = buf_day(0) & "/" & buf_day(1) & "/" & re_day(0) & " " & jikan & ":00"             
             Case Else '想定外
                Range("B3")="わかりません"
        End Select
    End If

こんなことに時間使ってしまった。

実際は年の記入がなければファイル作成日の年を使うようにしました。

今回関わったのは、曜日と曜、AMと午前、PMと午後が混在しながら、必ず曜日はカッコでくくってあるデータでした(笑)

救いだったのが西暦が必ず4桁で和暦無しだったことですね。ただ年そのものの表記が無いのがスタンダードでしたが・・・・

 

これで曜日カッコなしがきた場合、曜日の月と12ヶ月の月をどう区別するのか(笑)
怖い怖い・・・・・

表示形式という便利な機能があるので使ってほしいですね〜。

ただ、このままのコードですと、外に出すと考えるとちょっとカッコ悪いですかね(笑)
私は処理結果がよければそれでいいじゃんって思ってしまうダメな人なので(笑)
もし、きれいにコード書きたければ配列に処理順で文字列入れて、ループ使ってReplace使ってください。そうやって書き直したことを思い出しました(笑)

今回はこれでおしまいです。