GASで日付や数値の表示形式を変更する方法

GAS

※本記事はプロモーションを含みます

目次

スプレッドシートを業務フローのハブとして使っていると、CSVファイルの取り込みや外部API経由でのデータ同期、フォーム回答の集計など、外部から自動で流し込んだデータの見た目が崩れるケースが頻繁に起きます。特に多いのが、意図した日付表記が崩れて「2025-01-05T00:00:00.000Z」のような長大なタイムスタンプ文字列になっていたり、逆にシリアル値の数値だけが露出して「45662」のように表示されたり、金額のカンマが抜け落ちて桁数が把握しにくくなったりする現象です。なので、こうした画面上の視認性の問題を解決するために、GAS 日付 表示形式 変更の処理をスクリプト側に組み込み、データ投入と同時にセルの書式を正しく定義しておく実装が欠かせません。

外部データ取り込み直後に日付や数値の見た目を揃えたい場面

スプレッドシートで業務データを扱う際、ユーザーが手作業でデータを打ち込んでいる限りは、入力規則やあらかじめ設定された列書式によってある程度フォーマットが保たれます。ただし、GAS(Google Apps Script)を用いて外部サービスからJSONを取得してセルに流し込んだり、Drive上に置かれたCSVファイルをパースして一括で流し込んだりする場面では、シート側にあらかじめ設定していた表示形式が上書きされて消えてしまったり、意図しない型として扱われて書式が無効化されたりすることが珍しくありません。

たとえば基幹システムから夜間に自動出力される売上CSVを取り込み、日次レポート用スプレッドシートに転記するバッチ処理を考えます。このとき、売上日時の列には「YYYYMMDD」形式やISO 8601形式の文字列が入っていることが多く、金額の列にはクオートなしの生数値が入っています。なので、これらをスクリプトでそのままセルに書き込むと、日付列はただのテキスト文字列として左寄せで出力され、金額列は桁区切りカンマのない数値として右寄せで出力されます。ただし、人が目視で確認したり、他の関数で参照したりするシートにおいては、日付は「yyyy/mm/dd」に統一され、金額は「#,##0」のように3桁区切りの通貨表記になっていなければ、業務確認の手間が大幅に増えてしまいます。

また、セルの値自体を変更して整形するアプローチを取ると、後続の計算で問題が生じることがあります。というのは、日付をJavaScript側で「2025/01/05」という文字列に変換してセルに書き込むと、セルのデータ型そのものが「文字列」になってしまい、スプレッドシート上のFILTER関数やQUERY関数、あるいは日付比較演算子(>= など)を使った集計式で正しく日付順として比較できなくなるトラブルを招くからです。数値についても同様で、JavaScriptで「1,234,567」というカンマ付き文字列にして代入してしまうと、SUM関数などの計算対象から外れてしまいます。なので、値そのものは数値や日付オブジェクト(シリアル値)として保持したまま、見た目だけをコントロールする「表示形式の変更」が正解となります。

単一セルと一括範囲でsetNumberFormatを使い分ける書き方

GASでセルの表示形式を変更するときに使う基本メソッドが、Rangeクラスに用意されているsetNumberFormatです。というのは、このメソッドが、指定した単一セルまたはセル範囲全体に対して、スプレッドシートのカスタム数値形式と同じ構文で書式を上書き適用するからです。

まずは単一セルまたは指定範囲全体に同一の表示形式をあてる基本的なコード例を確認しましょう。これは、外部から取り込んだ直後の日付セルに対して、標準的なスラッシュ区切りの日付形式を反映する処理です。

function applyDateFormat() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const targetRange = sheet.getRange("A1");
  
  // A1セルの表示形式を「年/月/日」に指定
  targetRange.setNumberFormat("yyyy/mm/dd");
}

このコードを実行すると、対象のA1セルにシリアル値としての日付や数値が入っていれば、即座に「2025/01/05」のような形式に見た目が変わります。ただし、対象が1つのセルではなく「A2:A100」のような範囲であっても、その全セルを同じ日付フォーマットにしたいのであれば、sheet.getRange("A2:A100").setNumberFormat("yyyy/mm/dd")と記述するだけで一括適用が可能です。というのは、第1引数に渡す文字列が、スプレッドシートの画面上で「表示形式」→「数字」→「カスタム数値形式」に手動入力するパターン文字列と完全に互換性を持っているからです。

日付だけでなく数値の書式指定も同様に行えます。なので、売上金額を表示する列には#,##0を指定して桁区切りカンマを入れたり、パーセンテージを表示する列には0.0%を指定したりしましょう。よく使われるパターンの対応は次の通りです。

日付・日時の場合:
・年月日:yyyy/mm/dd
・年月日時分秒:yyyy/mm/dd hh:mm:ss
・曜日付き:yyyy/mm/dd (ddd)
・月日のみ:mm/dd

数値・通貨の場合:
・整数カンマ区切り:#,##0
・円記号付き整数:"¥"#,##0
・小数第2位までのカンマ区切り:#,##0.00
・パーセント表示(小数第1位):0.0%

ここでずれる点として意識しなければならないのは、setNumberFormatに小文字と大文字のどちらを渡すかという点です。というのは、スプレッドシートの書式構文では、月を表すトークンがmmであり、時間を表す分もmmだからです。前後にhhやssがある文脈で自動的に「分」と認識されますが、混同を避けるために正確なパターンを指定する必要があります。ただし、大文字のYYYYと書いてもシート側で解釈される場合はありますが、公式の仕様に沿って小文字のyyyyを用いるのが安全です。

表示形式が変わらない最大の原因である文字列データの見分け方

GAS 日付 表示形式 変更の処理を組んだ開発者が最も頻繁に遭遇する落とし穴が、「setNumberFormatを実行したのにセルの見た目が一切変わらない」という現象です。エラーメッセージが出るわけでもなく、スクリプトの実行ログは正常終了しているにもかかわらず、シート上の日付が意図した形式にならないケースがあります。

この現象が発生する根本原因は、セルに入力されている値そのものが「文字列型(Text)」として格納されている点にあります。というのは、スプレッドシートの表示形式という機能が、セルに「数値」または「日付シリアル値」が入っている場合にのみ機能するからです。なので、文字列型として格納されたセルに対してどれだけ数値フォーマットや日付フォーマットを指定しても、スプレッドシートエンジンは「これは書式を持たない生の文字列である」と解釈するため、フォーマット指定が完全に無視されます。

CSVファイルをインポートした際、各フィールドがダブルクオートで囲まれていると、インポート処理の実装によってはすべての値が文字列としてセルに書き込まれることがあります。また、setValues()で2次元配列を流し込む際、元データの日付が"2025/01/05"というJavaScriptのstring型になっている場合も、シート側には文字列として書き込まれます。ただし、画面上では「2025/01/05」と見えているため日付が入っているように錯覚しますが、セルを選択して左寄せになっていたり、数式バーで先頭にシングルクオート(’)が付いていたりする場合は、文字列として認識されています。

これを回避するためには、セルに値を流し込む段階でJavaScriptのDateオブジェクトに変換してから書き込むか、すでに文字列として入ってしまったセルをシリアル値として再代入する必要があります。以下のコードは、対象セルが文字列になっていないかを確認し、適切なDateオブジェクトを再代入した上でsetNumberFormatを適用する安全な処理パターンです。

function ensureDateAndFormat() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const cell = sheet.getRange("B2");
  const rawValue = cell.getValue();
  
  // 値が文字列として入っている場合はDateオブジェクトに変換して再格納する
  if (typeof rawValue === "string" && rawValue !== "") {
    const parsedDate = new Date(rawValue);
    
    // パースに成功して有効な日付であることを確認
    if (!isNaN(parsedDate.getTime())) {
      cell.setValue(parsedDate);
    }
  }
  
  // シリアル値になったセルに対して表示形式を適用
  cell.setNumberFormat("yyyy/mm/dd");
}

このように、値自体を正規の日付型(または数値型)として確立させてからsetNumberFormatを呼ぶことで、フォーマットが無視されるトラブルを確実に防ぐことができます。なので、外部APIのレスポンスを扱う場合も、JSONから取得した日付文字列をそのままsetValueするのではなく、new Date(item.dateString)を経由してシートに渡す設計を徹底しましょう。

タイムゾーンとシリアル値のズレを避けてフォーマットを適用する運用

日付の表示形式を扱う上で、もうひとつ深く関係してくるのがタイムゾーンの差異による「日付の1日ズレ」問題です。というのは、GASの実行環境(Google Cloud基盤)と、スプレッドシート自体のタイムゾーン設定、さらには取得元データのタイムゾーン定義が食い違っていると、表示形式を変更した瞬間に意図しない日時に化けてしまうことがあるからです。

たとえば、外部システムから「2025-05-01T00:00:00Z」(UTC協定世界時)という文字列を受け取ったとします。これをJavaScriptのnew Date()で解釈すると、日本標準時(JST, UTC+9)の環境下では「2025-05-01 09:00:00」となり、同じ日付として扱われます。ただし、もし外部システムが「日付のみ」を表すつもりで出力した「2025-05-01」という文字列をUTC基準のISO文字列(2025-05-01T00:00:00Z)としてパースし、スプレッドシート側のタイムゾーンが何らかの理由でアメリカ時間(例:PDT, UTC-7)に設定されていた場合、スプレッドシート上では前日の「2025-04-30 17:00:00」としてシリアル値が解釈され、yyyy/mm/ddで表示した結果が「2025/04/30」になってしまうという重大なバグが発生します。

この問題を防ぐためには、2つの確認が必要です。第1に、スプレッドシート自体の設定画面にあるタイムゾーンが「日本(GMT+09:00)」になっているかを確認しましょう。第2に、GASのappsscript.json(マニフェストファイル)内のtimeZoneプロパティが「Asia/Tokyo」に設定されているかを確認しましょう。というのは、ここが不一致だと、スクリプト内で日付を加工してシートに戻した際に、予期せぬオフセットが加算・減算されて日付が前後にズレる原因になるからです。

また、表示形式を整える目的でUtilities.formatDateを使って文字列に変換した上でセルに代入する手法を見かけることがありますが、これは注意が必要です。というのは、前述の通り、Utilities.formatDateで生成された文字列をセルに書き込むと、セルが文字列型になるからです。なので、その場での見た目は整いますが、スプレッドシート上での再計算や並べ替え、日付フィルタリングができなくなる副作用を伴います。集計やフィルタが必要な業務シートでは、値はDateオブジェクトのままセルに渡し、見た目の制御はsetNumberFormatに任せるという明確な役割分担を維持しましょう。

大量行のシートでsetNumberFormatsを使って処理負荷を抑える設計

数千行から数万行に及ぶ大規模なスプレッドシートを扱う場合、セルを1つずつループで回しながらsetNumberFormatを実行すると、実行時間制限(6分)に引っかかったり、APIの呼び出し回数が上限に達してスクリプトが強制停止したりします。なので、実務でGAS 日付 表示形式 変更を組み込む際は、複数行・複数列に対して一括で書式を適用するsetNumberFormats(末尾にsが付く複数形メソッド)を活用しましょう。

タイトルとURLをコピーしました