🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

Excel VBA の Format — 日付・数値と、書式設定が計算を壊す理由

|

Excel VBA の Format — 日付・数値と、書式設定が計算を壊す理由

検証環境: Excel 365 v2509 · Excel 2021 · Excel 2019 · 最終確認 2026-06-10

要点Format は値と書式コードを受け取り、指定どおりの見た目の文字列を返します。ファイル名・メッセージ・帳票のラベルを組み立てるには最高ですが、その結果をデータセルに書き込んだ瞬間に、静かなバグ工場になります。そのセルが保持するのはテキストで、数値でも日付でもなくなるからです。

Sub FormatDemo()
    Debug.Print Format(1234.5, "#,##0.00")     ' 1,234.50
    Debug.Print Format(0.75, "0.0%")           ' 75.0%
    Debug.Print Format(Now, "yyyy/mm/dd")      ' 2026/06/10
    Debug.Print Format(Now, "m月d日(aaa)")      ' 6月10日(水)
    Debug.Print Format(38740, "¥#,##0")        ' ¥38,740
End Sub

シグネチャ。ほとんどの人が忘れる 2 つの省略可能な引数つき。

Format(expression, [format], [firstDayOfWeek], [firstWeekOfYear])
'       値          コード     曜日計算用、めったに使わない

考え方の軸:Format は化粧であって、手術ではない

Format は値の見た目を変えるだけで、値が何であるかは変えません。日付シリアル値 46183 と コード "yyyy/mm/dd" を渡すと、文字列 "2026/06/10" が返ります。入っていく値は型を変えません — が、出てくるものは常に String です。これが Format について最も大事な 1 文です:出力はテキスト。

これを握れば、道具全体が腑に落ちます。出力先が文字列のときに Format を使う — メッセージ、シート名、"report_" & Format(Date, "yyyymmdd") & ".xlsx" というファイル名、連結しているラベル。出力先が数値や日付のままでいるべきセルのときは使わない。ブックの他の部分が計算しようとしている枠に、テキストを流し込むことになるからです。

唯一のルール:Format は String を返す — だから下流の計算を壊す

これが、最もよくある Format の惨事を説明するルールです。

cell.Value = Format(ある日付, "yyyy/mm/dd") と書いた瞬間、そのセルは日付であることをやめ、日付に見えるテキストになります。時系列で並べ替えられず、月でフィルターできず、「書式化された数値」の列に対する =SUM0 を返します。

罠を丸ごと組み上げると、こうです。

' ⚠ 間違い — 数値に見えるだけのテキストで列を埋める
Range("C2").Value = Format(1234.5, "#,##0.00")   ' セルは今や文字列 "1,234.50" を保持する
' =SUM(C:C) は無視する。並べ替えは "1,234.50" をテキスト扱い。グラフは飛ばす。

本当にやりたいのが「桁区切りで表示しつつ、本物の数値のまま」なら、Format はまったく使いません — セルの表示形式を設定し、値はそのままにします。

' ✓ 正しい — 値は数値のまま、表示だけが変わる
Range("C2").Value = 1234.5
Range("C2").NumberFormat = "#,##0.00"            ' SUM・並べ替え・グラフがすべて機能する

この区別 — Format はテキストを生む、NumberFormat は表示を変える — がすべてです。刻み込みましょう:文字列なら Format、セルなら NumberFormat

第 2 の罠:m は月、ただし時々ちがう

日付コードと時刻コードは文字 m を共有していて、この曖昧さは誰でも一度はやられます。

  • 単独の "mm"Format(Now, "mm")06
  • 同じ "mm""hh:" の直後にあるととして読まれます:Format(Now, "hh:mm")09:05。時との隣接が意味を反転させます。
  • 隣に時のない経過時間では、"mm:ss"月:秒 になります — まず意図と違います。VBA 専用の分トークン n を使いましょう:Format(t, "nn:ss")
Debug.Print Format(Now, "yyyy/mm/dd hh:mm:ss")   ' 2026/06/10 09:05:30  (最初の mm = 月、2 つ目 = 分)
Debug.Print Format(Now, "mm:ss")                 ' 06:30  <- 月:秒、おなじみの不意打ち
Debug.Print Format(Now, "nn:ss")                 ' 05:30  <- 分、これが正解

プレースホルダの桁にも知っておくべき独自ルールがあります。0 は桁を強制(ゼロ埋め)、# は桁があるときだけ表示。Format(5, "00")05Format(5, "##")5。請求番号をゼロ埋めしたり、整数をきれいに保ったりするのはこれです。

名前付き書式と Format* 兄弟

毎回ユーザー定義コードが要るわけではありません。VBA には名前付き書式と、地域設定に従う兄弟関数があります。

Debug.Print Format(1234.5, "Currency")      ' ¥1,235   (PC の地域通貨を使う)
Debug.Print Format(Now, "Short Date")       ' 2026/06/10   (地域の並び)
Debug.Print Format(0.75, "Percent")         ' 75.00%

Debug.Print FormatCurrency(1234.5, 0)       ' ¥1,235
Debug.Print FormatNumber(1234.5, 2)         ' 1,234.50
Debug.Print FormatPercent(0.75, 1)          ' 75.0%
Debug.Print FormatDateTime(Now, vbLongDate) ' 2026年6月10日

名前付き書式と Format* 兄弟は PC の地域設定に従います — ユーザー向け表示には利点、行き来させたいデータには危険です。"Short Date" は米国では 6/10/2026、日本では 2026/06/10 になります。固定でマシン非依存の文字列(ファイル名、CSV のキー、ISO タイムスタンプ)が必要なら、コードを明示的に書き下し — "yyyy-mm-dd""Short Date" は決して使わないこと。

どれをいつ使うか

やりたいこと 使うもの 理由
メッセージ・ファイル名・ラベル用の文字列 Format(値, コード) 出力はテキスト — まさに必要なもの
セルを書式付きで表示しつつ数値を保つ Range.NumberFormat = コード 値は数値のまま。SUM/並べ替え/グラフが機能
地域に従う通貨・数値の文字列 FormatCurrency / FormatNumber 地域設定に従う
固定でマシン非依存の日付文字列 Format(d, "yyyy-mm-dd") 明示コードは地域の並びを無視
テキストを実際に数値・日付へ戻す CStr / CDate / Val Format は値 → テキストの一方通行

意見:セルに入るなら Format ではなく NumberFormat

私が譲らない一線はこれです:Format はデータセルにはほぼ絶対に書き込むべきでない。 「SUM がゼロ」「日付が並ばない」案件の 9 割は、NumberFormat を使うべき場面で Format を使った誰かにたどり着きます。コード上ほぼ同じに見える — だからこのバグは多発し、レビューで見えないのです。

だから明確な切り分けを習慣にしましょう。文字列を組み立てる — シートのタブ名、ログの 1 行、ファイル名のスタンプ、MsgBox に連結するテキスト? Formatセルを正しく見せつつ、ブックが計算できる数値や日付に保つ? NumberFormat、値はそのまま。この切り分けを正せば、静かなデータバグの一群がまるごと消えます。そして一方通行を忘れずに:Format は値 → テキストだけ。逆方向 — 本物の数値や日付であるべきテキスト — には CStr・CDate・Val が要り、Format ではありません。

よくある Format のミス(と直し方)

症状 原因 直し方
列に対する =SUM が 0 を返す セルに Format()(テキスト)を書いた + Range.NumberFormat、Format は使わない
日付が時系列で並ばない セルが書式化テキストで、日付ではない 本物の日付を保存し NumberFormat を設定
mm が分でなく月を表示する 単独の mm は月 nn を使う、または mmhh の隣に置く
別の PC で日付の日/月が入れ替わる "Short Date"(地域依存)を使った 明示的な "yyyy-mm-dd" を使う
コードで先頭ゼロが欠ける #(省略可能な桁)を使った 0 で桁を強制:"00"
マクロ後に数値がテキストになる Format の結果を .Value に代入した 数値を代入し、NumberFormat で書式化

書式設定がマクロの半分を占めたら — 代わりに「結果」を伝える

書式設定は目的ではなく、帳票が目的です。あなたが欲しかったのは「金額は円、日付は ISO で表示され、合計はちゃんと合う月次シート」 — なのに、この mm は月か、この列はテキストか数値か、グラフがなぜ 1 行飛ばしたのか、と 3 層下に潜っている。ExcelMaster Agent なら、自然な日本語で結果をそのまま言えます — 「C 列を通貨、A 列を yyyy-mm-dd に書式化して、合計が効くよう数値のままにして」 — するとデータを文字列化せずに表示形式を設定する Python を、ファイルを先にバックアップしたうえで書き出します。無料で試す →

関連ガイド

よくある質問

VBA の Format 関数は何をする? Format は書式コードを使って値を書式化した文字列に変換します — Format(1234.5, "#,##0.00") はテキスト "1,234.50" を返します。値の見た目を変えるだけで、値そのものは変えず、結果は常にテキストです。

VBA で日付を書式化するには? 明示コードを使います:Format(Now, "yyyy/mm/dd")2026/06/10Format(Now, "dd/mm/yyyy") は日付が先。文字列がどの PC でも同じである必要があるなら、地域設定に従う名前付きの "Short Date" は避けましょう。

VBA の Format が分でなく月を表示するのはなぜ? 既定で m が月を意味するからです。単独の "mm" は月で、"hh:" の直後に置いたときだけ分になります。経過時間なら、VBA 専用の分トークンを使います:Format(t, "nn:ss")

VBA で列を書式化したら SUM が 0 になるのはなぜ? ほぼ確実に Format() の結果をセルに書き込み、数値に見えるだけのテキストを保存しています。本物の数値を保存し、見た目は代わりに Range.NumberFormat = "#,##0.00" で設定しましょう — そうすれば SUM・並べ替え・グラフがまた機能します。

VBA の Format と NumberFormat の違いは? Format はテキスト文字列を返します。Range.NumberFormat はセルの表示を変える一方で、保存される値は本物の数値や日付のままです。文字列を組み立てるなら Format、計算を壊さずにセルを正しく見せるなら NumberFormat を使います。