検証環境: Excel 365 v2509 · Excel 2021 · Excel 2019 · 最終確認 2026-06-10
要点 — CStr・CDate・Val・CLng・CDbl は変換関数です。値の型を変えます — 文字列を本物の数値へ、文字列を本物の日付へ、数値を文字列へ。これは Format の逆です。Format は値の見た目しか変えません。この違いを掴めば、VBA の静かなデータバグの最大の発生源を止められます。
Sub ConvertDemo()
Debug.Print CStr(1234.5) ' "1234.5" 数値 -> 文字列
Debug.Print CDbl("1234.5") * 2 ' 2469 文字列 -> 数値、そして本物の計算
Debug.Print CLng("42") ' 42 文字列 -> Long 整数
Debug.Print CDate("2026-04-01") ' 並べ替え・減算できる本物の日付
Debug.Print Val("12px") ' 12 数字を読み、最初の非数字で止まる
End Sub
考え方の軸:変換は「値が何であるか」を変える
このクラスターを掃除目線でひと回り:Trim はデータをきれいにし、Format は正しく見せ、C… 関数は正しい型にします。これは別々の 3 つの仕事で、最後の 2 つを取り違えるのが大罪です。
2026-04-01 と表示されるセルは、本物の日付(並べ替え・減算・月でのフィルターが可能)かもしれないし、そう見えるだけのテキストかもしれません。Format は後者を、CDate は前者を生みます。日付が並ばない、「数値」が合計されない — そういうとき、ほぼ必ず、本物の型付き値が要る場所にテキストが入っています。直し方は変換であって、追加の書式設定ではありません。テキストを「ふりをしている本来のもの」に変えるなら CDate/CDbl/CLng、意図して逆向きに行くなら CStr です。
唯一のルール:CDate は曖昧な日付をマシンの地域設定で読む
これが、チーム内でデータを静かに壊すルールです。
CDateは日付文字列を、実行される PC の地域設定で解釈します。CDate("01/02/2026")は米国のマシンでは 1 月 2 日、ヨーロッパのマシンでは 2 月 1 日。同じブック、同じコード、違うデータ — しかも何もエラーになりません。
警告は出ません。どちらの読み方も有効な日付だからです。バグは、設定の違う同僚にファイルが渡ったとき、あるいは別地域向けに構成されたサーバーで動いたときに初めて表面化します — そのときには、誤った日付が 1 か月分のレポートに焼き付いています。
' ⚠ 危険 — 結果は誰の PC が実行するかに依存する
d = CDate("01/02/2026") ' 米国では 1 月 2 日、ヨーロッパの多くでは 2 月 1 日
' ✓ 安全 — 部品から日付を組み立てる。地域設定に非依存
d = DateSerial(2026, 2, 1) ' どのマシンでも常に 2 月 1 日
直し方は、そもそも CDate に曖昧な文字列を渡すのをやめることです。ソースを自分で握っているなら、部品に分けて DateSerial(年, 月, 日) で組み立てる — 3 つの数値を取り、読み違えようがありません。"01/02/2026" を受け取らざるを得ないなら、"/" で Split して、順序を地域設定任せにせず自分で決めます。CDate は ISO の "2026-04-01" のような曖昧さのない書式に対してのみ安全とみなしましょう。
第 2 の罠:Val は地域設定に盲目、CDbl はそうでない
どちらも文字列を数値にしますが、小数点の区切りで意見が割れ、その食い違いがコンマ小数のデータを食います。
Valは 常に.を小数点、,を停止文字として扱います。空白を無視し、非数字に当たるまで左から右へ読みます。Val("12px")→12。Val("1,234.5")→1(コンマで止まる)。CDblは 地域設定に従います。コンマが小数点の環境(ヨーロッパの多くなど)ではCDbl("3,14")→3.14。
つまり、まったく同じ文字列が、選んだ関数次第で意味を変えます。
' コンマが小数点の環境のユーザーが「3,14」(= 3.14)と入力する
Debug.Print Val("3,14") ' 3 <- コンマで止まり、",14" は静かに捨てられる
Debug.Print CDbl("3,14") ' 3.14 <- 地域設定を尊重。ユーザーが意図した値
身を守るルール:自分で握る固定の英語形式の文字列には Val("12px" を 12 に削る、. 小数で自分が書き出した CSV を読む)。ユーザー入力や地域化されたソース由来のものには CDbl/CLng。 混ぜると、地域形式の数値の列が、知らぬ間に小数部を失います。
第 3 の罠:CLng は丸める。しかも期待どおりには丸めない
CLng と CInt は切り捨てません — 丸めます。しかも銀行家の丸め(偶数への丸め)です。
Debug.Print CLng(2.5) ' 2 <- 切り上げでなく、偶数へ丸める
Debug.Print CLng(3.5) ' 4
Debug.Print Int(2.7) ' 2 <- Int/Fix は代わりに切り捨てる
「常に切り上げ」や「小数を切り落とす」が欲しいなら、CLng は道具ちがいです — Int・Fix・WorksheetFunction.Round を使いましょう。そして CInt は 32,767 を超えるとオーバーフローします。実務の件数になりうるものには CLng を。
テキスト側でもう 1 つ:CStr(123) は "123" ですが、古い Str(123) は符号用に先頭の空白を予約して " 123" を返し、地域に関係なく常に . を使います。きれいな数値→テキストには、CStr(特定の見た目が欲しいときは Format)が Str に毎回勝ちます。
どれをいつ使うか
| 持っているもの | 使うもの | 理由 |
|---|---|---|
| テキストにしたい数値 | CStr(n) |
きれい、地域対応、先頭空白なし |
| テキスト → 数値(ユーザー/地域化ソース) | CDbl / CLng |
地域の小数点区切りを尊重 |
| テキスト → 数値(自分が握る固定の英語形式) | Val(s) |
常に . 小数、非数字で停止 |
| テキスト → 本物の日付(曖昧さなし、ISO) | CDate("2026-04-01") |
明確な書式を安全に解釈 |
| 曖昧な部品からの日付 | DateSerial(年, 月, 日) |
地域非依存、読み違え不可 |
| 表示用文字列だけ、値は不変 | Format | 化粧のみ — 型は変えない |
意見:データの解釈を地域設定に委ねるな
一線はこれです:暗黙の変換と、曖昧な文字列への CDate は、便利機能ではなく時限爆弾。 someDate = rng.Value や CDate(textCell) をして自分のマシンで「ちゃんと動く」コードは、サーバーで 1 月の代わりに 2 月を静かに生むのと同じコードです。自分の PC で走らせる限り、あらゆるテストを通ります。
だから、意図的に、曖昧さなく変換しましょう。日付は DateSerial で組む。ユーザーの数値は CDbl、固定文字列は Val で解釈し、どちらを握っているか分かっていること。列まるごとが「テキストとして保存された数値」で届いたら、本当の直し方は書式設定のひと回しではなく — 取り込み境界で一度、地域設定を釘付けにした変換です。やけどするチームは暗黙の読みを信じたチーム。そうでないチームは、自分で書式を決めたチームです。
よくある変換のミス(と直し方)
| 症状 | 原因 | 直し方 |
|---|---|---|
| 別の PC で日付が 1 か月ずれる | CDate が曖昧な dd/mm と mm/dd を読んだ |
DateSerial(年, 月, 日) で組む |
| コンマ小数がコンマ以降を全部失う | Val が , を停止文字扱いした |
地域化入力には CDbl を使う |
CDate/CDbl で「型が一致しません」 |
文字列が有効な日付/数値でなかった | 先に IsDate(s) / IsNumeric(s) を判定 |
| 丸めが予想外の値になる | CLng/CInt が銀行家の丸めを使う |
Int/Fix か WorksheetFunction.Round |
大きな件数の変換で オーバーフロー |
CInt は 32,767 で頭打ち |
CLng を使う |
| 数値→テキストに先頭空白がつく | 符号枠を予約する Str() を使った |
CStr() を使う |
変換が積み上がってきたら — 欲しい「データ」を伝える
あなたは CDate 対 DateSerial の見学をしたかったわけではありません。「日付が dd/mm、金額がコンマ区切りのこのエクスポートを読んで、モデルに正しく取り込みたい」だけだった。IsDate でガードし、地域設定を釘付けにし、Val でなく CDbl を選び、曖昧な日付を組み直す頃には、変換の配管がマクロそのものになっています。ExcelMaster Agent なら、代わりにデータを説明できます — 「A 列の日付は日が先、B 列の金額はコンマ小数。本物の日付と数値に変換して」 — するとそれらを曖昧さなく解釈する Python を、ブックを先にバックアップしたうえで書き出します。無料で試す →
関連ガイド
- VBA Trim — 空白が消えない理由と Chr(160) の対処法
- VBA Format — 日付・数値と、書式設定が計算を壊す理由
- VBA InStr — 文字列の中から文字を探す
- VBA Split — 1 つの文字列を配列に変える
- VBA For ループ — 実務の 8 例
よくある質問
VBA で文字列を数値に変換するには?
ユーザー入力や地域化されたソースからの入力には CDbl か CLng を使います。地域の小数点区切りを尊重するからです:コンマ小数の環境では CDbl("3,14") は 3.14。Val は自分が握る固定の英語形式の文字列にだけ使いましょう。Val は常に . を小数点として扱い、最初の非数字で止まるからです。
VBA の CStr と Str の違いは?
CStr は数値をきれいにテキスト化し、地域設定に従います。Str は符号用に先頭空白を予約し(Str(123) は " 123")、地域に関係なく常に . を小数点に使います。数値→テキストには CStr を選びましょう。
VBA の CDate が間違った日付を返すのはなぜ?
CDate が "01/02/2026" のような曖昧な文字列をマシンの地域設定で解釈するからです — 米国では 1 月 2 日、ヨーロッパの多くでは 2 月 1 日。DateSerial(2026, 2, 1) で部品から組んで地域非依存にし、CDate は ISO "2026-04-01" のような曖昧さのない書式に限って使いましょう。
VBA の CLng は丸める? 切り捨てる?
CLng(と CInt)は丸めます。銀行家の丸めで、CLng(2.5) は 2、CLng(3.5) は 4。代わりに小数を切り捨てるなら Int か Fix、切り上げ丸めなら WorksheetFunction.Round。なお CInt は 32,767 を超えるとオーバーフローするので、大きな値には CLng を使います。
VBA の変換で「型が一致しません」を避けるには?
先に入力を判定します:If IsNumeric(s) Then n = CDbl(s)、If IsDate(s) Then d = CDate(s)。このガードが、紛れ込んだ非数値や無効な日付文字列がループの途中で実行時エラーを起こすのを防ぎます。
