TL;DR —
Range.NumberFormatは 表示層 です。格納された数値がどう読めるかを変える だけで、数値そのものには決して触れません。Range("A1").Value = 5.4999にRange("A1").NumberFormat = "0"を組み合わせると画面には 5 が表示されます — でもA1.Valueは依然として5.4999で、A1 + A1は10.9998です。NumberFormat は丸め ではありません。 「見た目と値」が実際にお金を失わせるのがこの層です。日付とは衣装をまとっただけのシリアル値で あり、NumberFormatはその衣装 — 数値ではないからです。
Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets("Report")
ws.Range("A1").Value = 5.4999
ws.Range("A1").NumberFormat = "0" ' 5 と表示される...
Debug.Print ws.Range("A1").Value ' ...でも値は依然として 5.4999
3 つの書式設定の層 — テキストの Font、塗りの Interior、
そして表示の NumberFormat — のうち、人を欺くのはこれです。変装が真に迫っているからです。赤い
フォントを見て、値が変わったと思う人はいません。5 を表示するセルは、間違いなくそう思わせます。
本記事は、たった 1 つの事実を軸に組み立てられています。NumberFormat は目に見えるものを変える
だけで、格納されているものは決して変えない。そこを握れば、日付、通貨、パーセンテージ、そして
定番の「合計が合わない」バグのすべてが腑に落ちます。
この記事で学べること
- 考え方の軸 —
NumberFormatは表示層であり、表示は値ではない - 最も大事なルール — これは丸めではなく、格納された数値は変わらない
- 日付が衣装をまとったシリアル値である理由
NumberFormat(セルのプロパティ)対Format関数(文字列)- 書式コードの言語 —
#、0、4 つのセクション、通貨と色 - ロケールの罠 —
NumberFormat対NumberFormatLocal
考え方の軸:NumberFormat は表示層
どのセルも、値と、それとは別に、その値をどう描くかのルールを格納しています。NumberFormat が
そのルールです。それを "0.00"、"$#,##0"、"yyyy-mm-dd"、"0%" に設定すると、見せ方 — Excel
が描くグリフ — が変わり、その一方で下にある数値は Range.Value の中で手つかずのままです。セルは
数値を持っていて、NumberFormat はその前に置くレンズだと考えましょう。レンズを変えれば見え方は
変わります。でも、その奥の数値は動きません。
この分離こそがトピックのすべてです。だからこそ、同じ 0.5 を 50%、0.50、1/2 として、数式が
使う値をまったく変えずに見せられます — そして、表示のために小数を隠しても、それが 消える わけ
ではない理由でもあります。
最も大事なルール:これは丸めではない
一度言って、二度と忘れないでください。**NumberFormat は格納された値を丸めません。**丸めるのは
絵です。
ws.Range("A1").Value = 5.4999
ws.Range("A2").Value = 5.4999
ws.Range("A1:A2").NumberFormat = "0" ' 両方とも 5 と表示される
ws.Range("A3").Formula = "=A1+A2" ' 11 と表示される? いいえ - 表示用に丸めた 10.9998 が出る...
' 本当の合計は 10.9998。書式設定は小数を隠しただけで、消してはいない。
これが最もよくある NumberFormat のバグです。列を "0" に書式設定して「きれいにした」つもりが、
どのセルも目に見えない小数を持ち続けているせいで、合計が 1 ずれて出てくるのを見ることになります。
値そのものを本当に 5 にしたいなら、書式ではなく値を変えなければなりません。
ws.Range("A1").Value = WorksheetFunction.Round(ws.Range("A1").Value, 0) ' これで本当に 5 になる
目安はこうです。**見た目さえ正しければいいときは書式設定、数値が正しくなければならないときは
Round。**1 円単位まで合わなければならない帳票は値を丸めます。きれいに読めればいいダッシュボードは
表示を書式設定します。この 2 つを混同すること — それがスプレッドシートが「丸め誤差でずれる」に
行き着く道筋です。
日付は衣装をまとったシリアル値
日付は、見た目と値の分離を鮮やかにします。Excel は日付をシリアル値として — 1899-12-30 からの日数と
して — 格納し、日付が日付「である」のは、ひとえにその NumberFormat のおかげです。
ws.Range("B1").Value = 45900 ' ただの数値
ws.Range("B1").NumberFormat = "yyyy-mm-dd" ' これで日付として読める - 数値は依然として 45900
ここから 2 つの帰結がまっすぐ導かれます。1 つ目、本物の、計算できる日付を得るには、本物の日付の値を
セルに入れ(ws.Range("B1").Value = DateSerial(2025, 9, 15))、それから書式設定しなければなりません
— 間違った値に書式設定を当てるだけでは、間違った日付が表示されます。2 つ目、"2025-09-15" のような
テキスト 文字列に "yyyy-mm-dd" を当てても、役に立つことは何も起きません。テキストの背後には
シリアル値がないので、着飾らせる数値がないのです。日付がテキストで届くなら、書式設定の前に変換
しましょう(CDate、あるいは逆の問題は VBA CStr を参照)。衣装は、本物の数値の
上でしか働きません。
NumberFormat 対 Format 関数
VBA には名前に「format」が付くものが 2 つあり、これらを取り違えるのは本物のバグの源です。両者は、 ある重要な意味で正反対です。
Range.NumberFormatは セルのプロパティ です。永続的な表示ルールを設定し、下にある数値を 完全に手つかずで編集可能なまま残します。ワークシート上で欲しいのはこれです。Format(value, "pattern")は String を返す関数 です。VBA Format で 扱っており、テキストを組み立てるためのもの — メッセージボックス、ファイル名、連結したラベル — であって、セルを書式設定するためのものではありません。
罠は、Format を使って「書式化された数値」をセルに入れることです。
ws.Range("C1").Value = Format(1234.5, "$#,##0.00") ' 文字列 "$1,234.50" を書き込む
' C1 は今やテキスト。SUM も、数値としての並べ替えも、グラフ化もできない。
そのセルは書式設定されて見えますが、今やテキストを保持しており、数値は消えています。正しい版は、 数値を保ったまま表示ルールを設定します。
ws.Range("C1").Value = 1234.5
ws.Range("C1").NumberFormat = "$#,##0.00" ' $1,234.50 と表示、依然として本物の数値
ルールはこうです。**セルには NumberFormat、文字列には Format。**結果が数値のままであるべきなら、
決して Format を経由させないこと。
書式コードの言語
書式コードは小さな言語で、4 つのルールでそのほとんどが読めます。
0は強制の桁、#は省略可能な桁。"0.00"は常に小数 2 桁を表示し(5は5.00になる)、"#.##"は最大 2 桁を表示して末尾のゼロを落とします(5は5のまま)。,は 3 桁ごとに区切ります。"#,##0"は1234567を1,234,567にします。- リテラルの記号はそのまま通ります。
$、%、スペース、引用符で囲んだテキストは書いたとおりに 現れます —"$#,##0.00"、"0%"(これは表示のために 100 倍もします)、"0.0 kg"。 - セミコロンはセクションに分けます。
positive;negative;zero;textです。これが強力なものです。
' 正は黒、負は括弧付きの赤、ゼロはダッシュ、引用符内のテキストはそのまま表示。
ws.Range("D2:D100").NumberFormat = "#,##0.00;[Red](#,##0.00);\-;@"
[Red](およびその他の角括弧付きの色名)はセクションごとの表示色を設定し、@ はテキストの
プレースホルダーです。4 つのセクションすべてが必要になることはめったにありませんが、それらが存在
すると知っていれば、見かけるどんな書式文字列も読めます。日付ではトークンは d/m/y と
h/m/s — "yyyy-mm-dd hh:mm" — で、m は y や d の後では月を、h の後では分を意味
するという癖があります。
ロケールの罠:NumberFormat 対 NumberFormatLocal
最後の罠は、共有ブックで牙をむきます。NumberFormat は常に US-English の書式コードを使います —
3 桁区切りは ,、小数点は .、日付は m/d/y — ユーザーの地域設定が何であろうと関係なくです。
NumberFormatLocal は ユーザーのローカルの記号 を使います(ドイツ語では . が 3 桁を区切り、
, が小数点です)。
ws.Range("E1").NumberFormat = "#,##0.00" ' ポータブル - どのマシンでも同じ結果
ws.Range("E2").NumberFormatLocal = "#.##0,00" ' ドイツ式のコード - ドイツのロケールでだけ正しい
マクロは US コードで NumberFormat に対して書けば、どこでも同じように振る舞います。
NumberFormatLocal に手を伸ばすのは、ユーザーが自分のロケールで打ち込んだものを意図的に読んだり
合わせたりするときだけにしましょう。ローカル式のコードを NumberFormat に(あるいはその逆に)
与えるのは、自分のマシンでは動いて同僚のマシンでは壊れる、見えにくいバグです。
ExcelMaster の活用
NumberFormat は、ほかのどの書式設定の層よりも多くの判断を隠しています。値を丸める必要があるのか
表示だけでいいのか、日付のセルが本物のシリアル値を持つのかテキスト文字列を持つのか、「書式設定
された」セルが実は Format によるテキストなのか、そして NumberFormat と NumberFormatLocal の
どちらがコードをポータブルに保つのか。どの選択を間違えても、もっともらしく見えるセルの裏に壊れた
数値がある、という結果が返ってきます。
ExcelMaster なら、数値がどう
見えるべきかを言うだけで済みます。「D 列を通貨で、マイナスは赤で表示して」「日付を 2025-09-15 と
読めるようにして」と頼めば、セルに NumberFormat を設定し — 値を本物の、計算できる数値に保った
まま — 合計が実際に変わらなければならないときは Round で丸め、ポータブルな US の書式コードを
使います。ブックもコードもあなたの手元に残り、小数が消えたのではなくただ隠れていただけのせいで
合計が狂った、あの帳票を飛ばせます。
よくある質問
VBA で NumberFormat はセルの実際の値を変えますか?
いいえ。Range.NumberFormat は、格納された数値がどう表示されるかだけを変えます。5.4999 を保持
するセルを "0" で書式設定すると 5 と表示されますが、依然として 5.4999 を含んでおり、数式は
完全な値を使います — なので合計が「1 ずれて」見えることがあります。値そのものを変えるには、
WorksheetFunction.Round(value, digits) を使って結果を代入し直しましょう。書式設定だけでは、格納
された数値は決して丸まりません。
VBA でセルを通貨や日付として書式設定するには?
まず値を、それから書式を設定します。通貨なら Range("A1").Value = 1234.5 の後に
Range("A1").NumberFormat = "$#,##0.00"。日付なら Range("B1").Value = DateSerial(2025, 9, 15) の
後に Range("B1").NumberFormat = "yyyy-mm-dd"。テキスト文字列に書式だけを設定しても何も起きません。
表示すべき下地の数値がないからです。
NumberFormat と Format 関数の違いは?
Range.NumberFormat は、表示ルールを設定しつつ値を本物の数値に保つセルのプロパティです。
Format(value, "pattern") は String を返す関数です。ワークシートのセルには NumberFormat を、
メッセージ・ファイル名・ラベル用のテキストを組み立てるには Format を使いましょう。Format(...) を
セルに書き込むと、もう合計もグラフ化もできないテキストになってしまいます。
数値を書式設定した後に合計が狂うのはなぜ?
NumberFormat が小数を消さずに隠すからです。列を "0" に書式設定すると整数が表示されますが、各
セルは依然として小数を格納しているので、本当の合計はそれを含み、表示された数字の合計と食い違う
ことがあります。合計が表示と一致しなければならないなら、書式設定だけで済ませず、
WorksheetFunction.Round で値を丸めましょう。
NumberFormat と NumberFormatLocal の違いは?
NumberFormat は、どのマシンでも US-English の書式コード(3 桁区切りはカンマ、小数点はピリオド)を
使うのでポータブルです。NumberFormatLocal はユーザーの地域の記号を使い、これはロケールによって
異なります。どこでも一貫した振る舞いにするにはマクロを NumberFormat に対して書き、
NumberFormatLocal は、ユーザーが自分の設定で見るものを意図的に合わせるときだけ使いましょう。
検証環境
動作確認: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-08-11。
関連ガイド: VBA Font · VBA Cell Color · VBA Format · VBA CStr · VBA Range
