3行でまとめると
- Windows10 の日付表示には微妙なカスタマイズが可能です。
- しかしそのカスタマイズによってVBAへの意外な副作用を踏み抜いてハマりました。
- 教訓として、あまり知られていないマイナーなカスタマイズはやめておいた方が無難です。
- とはいえ、その仕様ってどうよ…?
という話になります。4行ですが。
日付表示のカスタマイズ
-
あまり知られていないのですが、Windowsのエクスプローラの日付表示に曜日を表示させることが可能です。
-
何気に date コマンドの出力も変わります。
設定方法
-
このようなダイアログが出ます。ここに表示されている「日付(短い形式)」をカスタマイズします。下の方にある「追加の設定(D)…」を押下します。
-
すると「形式のカスタマイズ」というダイアログが出ます。このダイアログの「日付」タブの真ん中あたりに短い形式(S):という項目があります。デフォルトでは「yyyy/MM/dd」と入っていると思います。
-
しかも実は、「ddd」だと「月」とか「火」となりますが、「dddd」だと「月曜日」とか「火曜日」という風に長い表示になります。細かいです。この機能需要あるんでしょうか。
-
不思議なことに、dateコマンドの出力は「dddd」にしても「水曜日」とはならず、「ddd」の時と同じで「水」のままでした。中途半端です。やるなら最後まで貫いて欲しい。
-
余談ですが、Windows10だとエクスプローラーの詳細表示が変わるだけですが、Windows11で同様の設定をするとタスクバーの日付表示の横に曜日が表示されます。細かいです。需要あるんでしょうか。こちらはあるかな。
話はそれだけでは終わらなかった。
- これだけだったら単なるマイナーなカスタマイズ機能ですほう、で終わりなのですが…そうは問屋が卸しませんでした。
- カスタマイズの話とはまったく関係なく、とあるExcel VBAで作られたマクロがありました。これをとある事情により使っていたのですが、上記日付表示のカスタマイズを行ってからしばらくしてこのExcelマクロを動かした所、まともに動かなくなっていることが判明しました。データも何も変わっていないのに突然動かなくなったのでびっくりして原因を調べたところ、このような処理をしている箇所があることに気づきました。勝手に転載すると怒られるかもなので、下記は問題点を示すための疑似的なコードです。
Dim s as String
s = Cells(x, y).Value 'ここには日付値が入っている
If IsDate(s) = True Then
' 肝心な処理
'...
End If
- この「肝心な処理」の所を通っていないのが原因らしい…
- この文字列 s は、普通なら yyyy/mm/dd の形式となるはずなのですが…まさかと思い、こういうシートを作成し…
以下のようなコードを書いてみました。
Dim w As Worksheet
Set w = ActiveSheet
Dim s As String
s = w.Range("C5").Value
Debug.Print ("s=" & s)
Debug.Print ("IsDate(s)の判定結果=" & IsDate(s))
s=2022/07/19 火
IsDate(s)の判定結果=False
なんですかそれは… Windowsの日付表示設定がExcelの日付値の文字列変換の動作に影響しているのか?
その謎を解明するため、日付表示の設定を元に戻してみて、再度実行してみました。
s=2022/07/19
IsDate(s)の判定結果=True
直りました1。まじですかい…本当に影響してました。それなら、「yyyy/MM/dd dddd」にしたら「2022/07/19 火曜日」になるのかい?
s=2022/07/19 火曜日
IsDate(s)の判定結果=False
見事になっています。
セルの日付値を取り出してStringに変換するのがいけないのか?
- ならば DateとかVariant で受けたらどうなる?ということで、やってみました。
'Stringで受けた場合
Dim s As String
s = w.Range("C5").Value
Debug.Print ("s=" & s)
Debug.Print ("IsDate(s)の判定結果=" & IsDate(s))
'Dateで受けた場合
Dim d As Date
d = w.Range("C5").Value
Debug.Print ("d=" & d)
Debug.Print ("IsDate(d)の判定結果=" & IsDate(d))
'Variantで受けた場合
Dim v As Variant
v = w.Range("C5").Value
Debug.Print ("v=" & v)
Debug.Print ("IsDate(v)の判定結果=" & IsDate(v))
s=2022/07/19 火曜日
IsDate(s)の判定結果=False
d=2022/07/19 火曜日
IsDate(d)の判定結果=True
v=2022/07/19 火曜日
IsDate(v)の判定結果=True
Date型やVariant型であれば表示は「火曜日」だけどIsDate()判定は正しい結果になる。そうなんだ…へぇ……
まとめ
【教訓】Excel VBAで日付値を取り出すときに安易に String で受けてはいけません。
- ということですね… Stringで受けるということは、値を「文字列表現」に変えたということ。単なる表現に過ぎない文字列は、本質的な値ではなく、OS側の設定によって変わってしまうので処理を制御するための判別値に使ってはいかん、と言うわけです。制御に使いたいならDateとかVariantで受けなさいと、いうことらしいです。なるほど勉強になりました。
【根本的教訓】みんながしないようなマイナーなカスタマイズをすると痛い目に合うのでやめておいた方が無難
- ということですよね。だけどそれをやってみたくなるのが人というものなんじゃないですか…
【問題提起】しかしそれなら IsDate(文字列)の存在意義ってなんです?2
-
冷静に考えて見ると、そもそもですが、OSの表示カスタマイズ設定がExcelの動作に影響するってありなの?
-
百歩譲ってありだとして、OS側で日付文字列のフォーマットの設定が変わったときにVBA側の日付→文字列の変換ロジックが変わるのならば、IsDate()の判定ロジックも一緒に合わせて変わってくれてもいいんじゃないでしょうか?仕様の一貫性的な意味で、おかしくないです?
-
などと無駄な一石を投じつつ、今回の記事は以上です。最後までお読みいただきありがとうございました。
【参考情報】今回動作確認した環境
・Windows10 Pro Version. 21H2 OSビルド 19044.1826
・Microsoft Office Personal 2019
・Microsoft® Excel® 2019 MSO (バージョン 2206 ビルド 16.0.15330.20260) 32 ビット