MENU

GAS×日付操作|日付計算と書式設定の完全ガイド

GAS×日付操作|日付計算と書式設定の完全ガイド

GASで日付を扱おうとして、スプレッドシートから取得した値が意味不明な数字になった経験はないだろうか。あるいは日付の表示形式を変えたい、営業日だけカウントしたい、といった場面に遭遇したことがあるかもしれない。

GASの日付操作はJavaScriptのDateオブジェクトがベースになっている。月が0始まりだったり、タイムゾーンの罠があったりと、独特のクセがある。ただ、基本パターンを押さえれば日付計算もフォーマット変換も難しくない。


目次

GASでの日付の扱い方(Dateオブジェクト)

GASではJavaScriptのDateオブジェクトを使って日付を扱う。

Dateオブジェクトの基本


function dateBasics() {
  // 現在日時を取得
  const now = new Date();
  console.log('現在:', now);  // Mon Feb 02 2026 15:30:00 GMT+0900 (JST)

  // Dateオブジェクトは「日時」を表す
  // → 年、月、日、時、分、秒、ミリ秒を持つ
}

月は0始まり ── 最大の落とし穴


function monthWarning() {
  // ⚠️ 月は 0〜11 で表される(1月=0, 12月=11)
  const date = new Date(2026, 1, 15);  // 2026年2月15日(1ではなく2月!)
  console.log(date);

  // 分かりやすくするコツ
  const year = 2026;
  const month = 2 - 1;  // 2月 → 1 と書く
  const day = 15;
  const date2 = new Date(year, month, day);
}

new Date(2026, 1, 15) は2月15日を指す。1月のつもりで書くと1ヶ月ずれる。この仕様は何年経っても間違えやすいので、2 - 1 のように意図を明示する書き方をおすすめする。


日付の作成・取得方法

日付の作成パターン


function createDates() {
  // パターン1: 現在日時
  const now = new Date();

  // パターン2: 年月日を指定(時刻は00:00:00)
  const date1 = new Date(2026, 1, 15);  // 2026年2月15日

  // パターン3: 年月日時分秒を指定
  const date2 = new Date(2026, 1, 15, 10, 30, 0);  // 2026年2月15日 10:30:00

  // パターン4: 文字列から作成
  const date3 = new Date('2026-02-15');           // ISO形式
  const date4 = new Date('2026/02/15');           // スラッシュ区切り
  const date5 = new Date('February 15, 2026');    // 英語形式

  // パターン5: タイムスタンプ(ミリ秒)から作成
  const timestamp = 1771113600000;
  const date6 = new Date(timestamp);
}

日付の各要素を取得


function getDateParts() {
  const date = new Date(2026, 1, 15, 10, 30, 45);

  console.log('年:', date.getFullYear());    // 2026
  console.log('月:', date.getMonth());       // 1(2月)※0始まり
  console.log('月(実際):', date.getMonth() + 1);  // 2
  console.log('日:', date.getDate());        // 15
  console.log('曜日:', date.getDay());       // 0(日曜)〜6(土曜)
  console.log('時:', date.getHours());       // 10
  console.log('分:', date.getMinutes());     // 30
  console.log('秒:', date.getSeconds());     // 45
  console.log('ミリ秒:', date.getMilliseconds());  // 0
  console.log('タイムスタンプ:', date.getTime());  // ミリ秒
}

曜日の変換


function getDayName() {
  const date = new Date();
  const dayIndex = date.getDay();  // 0〜6

  // 日本語の曜日
  const dayNamesJa = ['日', '月', '火', '水', '木', '金', '土'];
  console.log('曜日:', dayNamesJa[dayIndex]);

  // 英語の曜日
  const dayNamesEn = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
  console.log('Day:', dayNamesEn[dayIndex]);
}

日付の加算・減算

基本: setXxx() メソッドを使う


function addSubtractDates() {
  // === 日を加算・減算 ===
  const date = new Date(2026, 1, 15);  // 2026年2月15日

  // 7日後
  date.setDate(date.getDate() + 7);
  console.log('7日後:', date);  // 2026年2月22日

  // 10日前
  date.setDate(date.getDate() - 10);
  console.log('10日前:', date);  // 2026年2月12日

  // === 月を加算・減算 ===
  const date2 = new Date(2026, 1, 15);

  // 3ヶ月後
  date2.setMonth(date2.getMonth() + 3);
  console.log('3ヶ月後:', date2);  // 2026年5月15日

  // === 年を加算・減算 ===
  const date3 = new Date(2026, 1, 15);

  // 1年後
  date3.setFullYear(date3.getFullYear() + 1);
  console.log('1年後:', date3);  // 2027年2月15日
}

注意: 元の日付が変わる


function dateModificationWarning() {
  const original = new Date(2026, 1, 15);

  // ⚠️ setDate() は元のオブジェクトを変更する
  original.setDate(original.getDate() + 7);
  console.log(original);  // 2026年2月22日(元の日付が変わった!)

  // ✅ 元の日付を保持したい場合は、コピーを作る
  const original2 = new Date(2026, 1, 15);
  const newDate = new Date(original2);  // コピーを作成
  newDate.setDate(newDate.getDate() + 7);

  console.log('元の日付:', original2);  // 2026年2月15日(変わらない)
  console.log('新しい日付:', newDate);  // 2026年2月22日
}

setDate() は破壊的メソッドで、呼び出し元のオブジェクトを直接書き換える。元の日付を残したい場合は new Date(original) でコピーしてから操作すること。

便利関数: 日付の加算


/**
 * 日付を加算する(元の日付は変更しない)
 * @param {Date} date - 基準日
 * @param {number} days - 加算する日数(負の値で減算)
 * @return {Date} - 新しい日付
 */
function addDays(date, days) {
  const result = new Date(date);
  result.setDate(result.getDate() + days);
  return result;
}

/**
 * 月を加算する
 */
function addMonths(date, months) {
  const result = new Date(date);
  result.setMonth(result.getMonth() + months);
  return result;
}

/**
 * 年を加算する
 */
function addYears(date, years) {
  const result = new Date(date);
  result.setFullYear(result.getFullYear() + years);
  return result;
}

// 使用例
function testAddFunctions() {
  const today = new Date();

  console.log('今日:', today);
  console.log('7日後:', addDays(today, 7));
  console.log('3日前:', addDays(today, -3));
  console.log('1ヶ月後:', addMonths(today, 1));
  console.log('1年後:', addYears(today, 1));
}

日数の差を計算


/**
 * 2つの日付の差(日数)を計算
 */
function daysBetween(date1, date2) {
  const oneDay = 24 * 60 * 60 * 1000;  // 1日のミリ秒
  const diff = Math.abs(date2 - date1);
  return Math.floor(diff / oneDay);
}

function testDaysBetween() {
  const start = new Date(2026, 1, 1);   // 2026年2月1日
  const end = new Date(2026, 1, 15);    // 2026年2月15日

  console.log('日数差:', daysBetween(start, end), '日');  // 14日
}

日付のフォーマット(Utilities.formatDate)

GASには日付をフォーマットする専用関数 Utilities.formatDate() がある。

基本構文


Utilities.formatDate(date, timeZone, format)
引数 説明
date フォーマットする日付 new Date()
timeZone タイムゾーン 'Asia/Tokyo'
format フォーマット文字列 'yyyy/MM/dd'

フォーマット文字一覧

文字 意味 出力例
yyyy 年(4桁) 2026
yy 年(2桁) 26
MM 月(2桁、ゼロ埋め) 02
M 月(ゼロ埋めなし) 2
dd 日(2桁、ゼロ埋め) 05
d 日(ゼロ埋めなし) 5
HH 時(24時間、2桁) 14
H 時(24時間) 14
hh 時(12時間、2桁) 02
mm 分(2桁) 05
ss 秒(2桁) 09
E 曜日(短縮) Mon
EEEE 曜日(フル) Monday
a 午前/午後 AM / PM

よく使うフォーマット例


function formatExamples() {
  const date = new Date(2026, 1, 5, 14, 30, 0);  // 2026年2月5日 14:30:00
  const tz = 'Asia/Tokyo';

  // 基本形式
  console.log(Utilities.formatDate(date, tz, 'yyyy/MM/dd'));
  // → 2026/02/05

  console.log(Utilities.formatDate(date, tz, 'yyyy-MM-dd'));
  // → 2026-02-05

  console.log(Utilities.formatDate(date, tz, 'yyyy年MM月dd日'));
  // → 2026年02月05日

  console.log(Utilities.formatDate(date, tz, 'yyyy年M月d日'));
  // → 2026年2月5日(ゼロ埋めなし)

  // 時刻付き
  console.log(Utilities.formatDate(date, tz, 'yyyy/MM/dd HH:mm:ss'));
  // → 2026/02/05 14:30:00

  console.log(Utilities.formatDate(date, tz, 'yyyy/MM/dd HH:mm'));
  // → 2026/02/05 14:30

  // 曜日付き
  console.log(Utilities.formatDate(date, tz, 'yyyy/MM/dd (E)'));
  // → 2026/02/05 (Thu)

  console.log(Utilities.formatDate(date, tz, 'M月d日(E)'));
  // → 2月5日(Thu)

  // 時刻のみ
  console.log(Utilities.formatDate(date, tz, 'HH:mm'));
  // → 14:30

  // ISO 8601形式
  console.log(Utilities.formatDate(date, tz, "yyyy-MM-dd'T'HH:mm:ss"));
  // → 2026-02-05T14:30:00
}

日本語の曜日を表示

Utilities.formatDate() の曜日出力は英語表記になる。日本語で表示するには別のアプローチが必要だ。


/**
 * 日本語の曜日付きでフォーマット
 */
function formatDateJapanese(date) {
  const tz = 'Asia/Tokyo';
  const dayNames = ['日', '月', '火', '水', '木', '金', '土'];
  const dayName = dayNames[date.getDay()];

  const formatted = Utilities.formatDate(date, tz, 'yyyy年M月d日');
  return `${formatted}(${dayName})`;
}

function testJapaneseFormat() {
  const date = new Date(2026, 1, 5);
  console.log(formatDateJapanese(date));  // 2026年2月5日(木)
}

実践例1 営業日計算

土日祝を除いた営業日を計算する。請求書の支払期限や納品日の算出に使える。


/**
 * 営業日を加算する(土日除く)
 * @param {Date} startDate - 開始日
 * @param {number} businessDays - 加算する営業日数
 * @return {Date} - 営業日後の日付
 */
function addBusinessDays(startDate, businessDays) {
  const result = new Date(startDate);
  let count = 0;

  while (count < businessDays) {
    result.setDate(result.getDate() + 1);
    const dayOfWeek = result.getDay();

    // 土曜(6)と日曜(0)をスキップ
    if (dayOfWeek !== 0 && dayOfWeek !== 6) {
      count++;
    }
  }

  return result;
}

/**
 * 営業日を加算する(土日祝除く)
 * @param {Date} startDate - 開始日
 * @param {number} businessDays - 加算する営業日数
 * @param {Date[]} holidays - 祝日の配列(オプション)
 * @return {Date} - 営業日後の日付
 */
function addBusinessDaysWithHolidays(startDate, businessDays, holidays = []) {
  const result = new Date(startDate);
  let count = 0;

  // 祝日を比較用の文字列に変換
  const holidayStrings = holidays.map(h =>
    Utilities.formatDate(h, 'Asia/Tokyo', 'yyyy-MM-dd')
  );

  while (count < businessDays) {
    result.setDate(result.getDate() + 1);
    const dayOfWeek = result.getDay();
    const dateString = Utilities.formatDate(result, 'Asia/Tokyo', 'yyyy-MM-dd');

    // 土日と祝日をスキップ
    const isWeekend = dayOfWeek === 0 || dayOfWeek === 6;
    const isHoliday = holidayStrings.includes(dateString);

    if (!isWeekend && !isHoliday) {
      count++;
    }
  }

  return result;
}

/**
 * 使用例: 3営業日後を計算
 */
function testBusinessDays() {
  const today = new Date();
  const tz = 'Asia/Tokyo';

  // 土日のみ除外
  const result1 = addBusinessDays(today, 3);
  console.log('3営業日後(土日除く):', Utilities.formatDate(result1, tz, 'yyyy/MM/dd (E)'));

  // 祝日も除外
  const holidays = [
    new Date(2026, 1, 11),  // 建国記念の日
    new Date(2026, 1, 23),  // 天皇誕生日
  ];
  const result2 = addBusinessDaysWithHolidays(today, 3, holidays);
  console.log('3営業日後(祝日含む):', Utilities.formatDate(result2, tz, 'yyyy/MM/dd (E)'));
}

2つの日付間の営業日数を計算


/**
 * 2つの日付間の営業日数を計算
 */
function countBusinessDays(startDate, endDate) {
  let count = 0;
  const current = new Date(startDate);

  while (current <= endDate) {
    const dayOfWeek = current.getDay();
    if (dayOfWeek !== 0 && dayOfWeek !== 6) {
      count++;
    }
    current.setDate(current.getDate() + 1);
  }

  return count;
}

function testCountBusinessDays() {
  const start = new Date(2026, 1, 1);   // 2026年2月1日(日)
  const end = new Date(2026, 1, 28);    // 2026年2月28日(土)

  console.log('営業日数:', countBusinessDays(start, end), '日');
}

実践例2 期限チェック・リマインダー

スプレッドシートに記録されたタスクの期限をチェックし、期限が近いものをメールで通知するスクリプトだ。


/**
 * 期限が近いタスクをチェックしてリマインド
 * スプレッドシート形式: A列=タスク名, B列=期限日, C列=担当者メール
 */
function checkDeadlines() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const data = sheet.getDataRange().getValues();
  const today = new Date();
  const tz = 'Asia/Tokyo';

  // 今日の0時0分に正規化(時刻を無視して日付だけ比較)
  today.setHours(0, 0, 0, 0);

  const alerts = [];

  for (let i = 1; i < data.length; i++) {
    const taskName = data[i][0];
    const deadline = new Date(data[i][1]);
    const email = data[i][2];

    if (!taskName || !deadline) continue;

    // 期限日を0時0分に正規化
    deadline.setHours(0, 0, 0, 0);

    // 日数差を計算
    const diffDays = Math.floor((deadline - today) / (24 * 60 * 60 * 1000));

    // 期限が3日以内または過ぎている場合にアラート
    if (diffDays <= 3) {
      let status;
      if (diffDays < 0) {
        status = `⚠️ ${Math.abs(diffDays)}日超過`;
      } else if (diffDays === 0) {
        status = '🔴 本日期限';
      } else {
        status = `🟡 あと${diffDays}日`;
      }

      alerts.push({
        task: taskName,
        deadline: Utilities.formatDate(deadline, tz, 'M月d日'),
        email: email,
        status: status,
        diffDays: diffDays
      });
    }
  }

  // アラートがあれば通知
  if (alerts.length > 0) {
    sendDeadlineAlert(alerts);
  }

  console.log(`チェック完了: ${alerts.length}件のアラート`);
  return alerts;
}

/**
 * 期限アラートをメール送信
 */
function sendDeadlineAlert(alerts) {
  const recipient = Session.getActiveUser().getEmail();
  const today = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy年M月d日');

  let body = `【期限アラート】${today}\n\n`;
  body += `${alerts.length}件のタスクが期限間近または超過しています。\n\n`;
  body += '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n';

  alerts.forEach((alert, index) => {
    body += `【${index + 1}】${alert.task}\n`;
    body += ` 期限: ${alert.deadline}\n`;
    body += ` 状態: ${alert.status}\n\n`;
  });

  GmailApp.sendEmail(recipient, `【要対応】期限アラート(${alerts.length}件)`, body);
}

月末・月初の判定


/**
 * 今日が月末かどうか
 */
function isEndOfMonth(date = new Date()) {
  const tomorrow = new Date(date);
  tomorrow.setDate(tomorrow.getDate() + 1);
  return tomorrow.getDate() === 1;
}

/**
 * 今日が月初かどうか
 */
function isStartOfMonth(date = new Date()) {
  return date.getDate() === 1;
}

/**
 * 月末日を取得
 */
function getEndOfMonth(date) {
  const result = new Date(date.getFullYear(), date.getMonth() + 1, 0);
  return result;
}

/**
 * 月初日を取得
 */
function getStartOfMonth(date) {
  return new Date(date.getFullYear(), date.getMonth(), 1);
}

function testMonthBoundaries() {
  const today = new Date();
  const tz = 'Asia/Tokyo';

  console.log('今日は月末?:', isEndOfMonth());
  console.log('今日は月初?:', isStartOfMonth());
  console.log('今月の月末:', Utilities.formatDate(getEndOfMonth(today), tz, 'yyyy/MM/dd'));
  console.log('今月の月初:', Utilities.formatDate(getStartOfMonth(today), tz, 'yyyy/MM/dd'));
}

タイムゾーンの注意点

GASのタイムゾーン問題

GASはデフォルトでUTC(協定世界時)を使う場合があり、日本時間との9時間のズレがバグの原因になりやすい。


function timeZoneIssue() {
  const date = new Date('2026-02-15');  // 文字列から作成

  // ⚠️ UTCとして解釈される可能性
  console.log('そのまま出力:', date);
  console.log('時刻:', date.getHours());  // 9(日本時間で0時のはずが9時に)

  // ✅ タイムゾーンを明示してフォーマット
  console.log('日本時間:', Utilities.formatDate(date, 'Asia/Tokyo', 'yyyy/MM/dd HH:mm'));
}

安全な日付作成方法


/**
 * タイムゾーンを考慮した安全な日付作成
 */
function createDateSafely(year, month, day) {
  // コンストラクタで直接指定(ローカルタイム)
  return new Date(year, month - 1, day);  // 月は-1する
}

/**
 * 文字列から安全に日付を作成
 */
function parseDateString(dateString) {
  // 'yyyy/MM/dd' または 'yyyy-MM-dd' 形式を想定
  const parts = dateString.split(/[\/\-]/);
  const year = parseInt(parts[0]);
  const month = parseInt(parts[1]) - 1;  // 月は-1
  const day = parseInt(parts[2]);

  return new Date(year, month, day);
}

function testSafeDateCreation() {
  const tz = 'Asia/Tokyo';

  const date1 = createDateSafely(2026, 2, 15);  // 2026年2月15日
  console.log('安全に作成:', Utilities.formatDate(date1, tz, 'yyyy/MM/dd HH:mm'));

  const date2 = parseDateString('2026/02/15');
  console.log('文字列から:', Utilities.formatDate(date2, tz, 'yyyy/MM/dd HH:mm'));
}

ISO形式の文字列 '2026-02-15' からDateを生成するとUTCとして解釈される。日本時間で扱いたい場合は new Date(year, month - 1, day) のコンストラクタ形式を使うか、parseDateString() のように文字列を分解してから生成するのが安全だ。

スプレッドシートの日付を正しく取得


function getDateFromSpreadsheet() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const cell = sheet.getRange('A1');

  // getValue()で取得するとDateオブジェクトになる
  const dateValue = cell.getValue();

  if (dateValue instanceof Date) {
    // 正しくDateオブジェクトとして取得できた
    const tz = 'Asia/Tokyo';
    console.log('取得した日付:', Utilities.formatDate(dateValue, tz, 'yyyy/MM/dd'));
  } else {
    // 文字列として取得された場合
    console.log('文字列として取得:', dateValue);
    const parsedDate = parseDateString(String(dateValue));
    console.log('パース後:', parsedDate);
  }
}

よくあるエラーと対処法

エラー1: Invalid Date


// ❌ エラー: 無効な日付文字列
const date = new Date('2026/2/30');  // 2月30日は存在しない
console.log(date);  // Invalid Date

// ✅ 対処: 日付の妥当性チェック
function isValidDate(date) {
  return date instanceof Date && !isNaN(date.getTime());
}

const testDate = new Date('2026/2/30');
if (!isValidDate(testDate)) {
  console.error('無効な日付です');
}

エラー2: 月のズレ(0始まり問題)


// ❌ 間違い: 2月のつもりが3月になる
const wrong = new Date(2026, 2, 15);  // 2026年3月15日!

// ✅ 正しい: 月は-1する
const correct = new Date(2026, 2 - 1, 15);  // 2026年2月15日

エラー3: 日付の比較


// ❌ 間違い: 直接比較すると時刻も含まれる
const date1 = new Date(2026, 1, 15, 10, 0, 0);
const date2 = new Date(2026, 1, 15, 14, 0, 0);
console.log(date1 === date2);  // false(同じ日だが時刻が違う)
console.log(date1 == date2);   // false

// ✅ 正しい: 日付部分だけ比較
function isSameDay(d1, d2) {
  return d1.getFullYear() === d2.getFullYear() &&
         d1.getMonth() === d2.getMonth() &&
         d1.getDate() === d2.getDate();
}
console.log(isSameDay(date1, date2));  // true

// または文字列に変換して比較
const tz = 'Asia/Tokyo';
const str1 = Utilities.formatDate(date1, tz, 'yyyy-MM-dd');
const str2 = Utilities.formatDate(date2, tz, 'yyyy-MM-dd');
console.log(str1 === str2);  // true

エラー4: スプレッドシートの日付がシリアル値になる


// スプレッドシートの日付がシリアル値(数値)として取得された場合
function convertSerialToDate(serial) {
  // Excelのシリアル値は1900年1月1日を1とする
  // ただしGoogleスプレッドシートでは1899年12月30日が基準
  const baseDate = new Date(1899, 11, 30);
  const result = new Date(baseDate.getTime() + serial * 24 * 60 * 60 * 1000);
  return result;
}

function testSerialConversion() {
  const serial = 46066;  // 2026年2月15日のシリアル値
  const date = convertSerialToDate(serial);
  console.log('変換結果:', Utilities.formatDate(date, 'Asia/Tokyo', 'yyyy/MM/dd'));
}

まとめ

覚えておくべきポイント

ポイント 説明
月は0始まり 1月=0, 12月=11
setXxx()は元を変更 コピーを作ってから操作
フォーマットはUtilities Utilities.formatDate(date, tz, format)
タイムゾーンを明示 'Asia/Tokyo' を指定

よく使うパターン


// 今日の日付(時刻なし)
const today = new Date();
today.setHours(0, 0, 0, 0);

// 日付のフォーマット
Utilities.formatDate(date, 'Asia/Tokyo', 'yyyy年M月d日');

// N日後
const future = new Date(today);
future.setDate(future.getDate() + 7);

// 日数差
const diff = Math.floor((date2 - date1) / (24 * 60 * 60 * 1000));

次のステップ


日付操作はGASを書くうえで避けて通れない。月の0始まり、タイムゾーン、破壊的メソッド ── この3つの罠さえ意識しておけば、大半のトラブルは防げる。


最終更新: 2026-02-02

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

目次