海外予定の時刻ずれを登録前に発見|GASでタイムゾーン入力をdry-run確認

海外予定の時刻ずれを登録前に発見|GASでタイムゾーン入力をdry-run確認

ツールおじ|GoogleアカウントをAIエージェント化

ツールおじ|GoogleアカウントをAIエージェント化

海外との打ち合わせを予定表へ取り込む時、「10:00」が日本時間なのか現地時間なのか分からないまま登録すると、予定そのものは作れても開始時刻がずれることがあります。

この記事では、日時に時差情報が付いているか、変換先のタイムゾーン名が有効かを先に検査し、変換後の時刻だけをログで確認する無料GASを紹介します。Googleカレンダーへの予定作成・更新は行いません。

準備するシート

スプレッドシートに `TimezonePlan` シートを作り、1行目へ次の3列を用意します。

  • A列 `実行`: 確認する行だけ `TRUE`
  • B列 `開始日時ISO`: `2026-09-15T10:00:00+09:00` のように時差を含む日時
  • C列 `変換先タイムゾーン`: `America/New_York` や `Asia/Tokyo`

日時の末尾が `Z` または `+09:00` のようになっていれば、どの時点を指すかを固定できます。`2026/09/15 10:00` のように時差が分からない入力は、このコードでは止めます。

コピーして使える最小コード

const TIMEZONE_AUDIT_CONFIG = Object.freeze({
  DRY_RUN: true,
  SHEET_NAME: 'TimezonePlan',
  MAX_ROWS: 100,
  OUTPUT_FORMAT: 'yyyy-MM-dd HH:mm z'
});

function auditCalendarTimezoneInputFree() {
  validateTimezoneAuditConfig_(TIMEZONE_AUDIT_CONFIG);

  const sheet = SpreadsheetApp.getActiveSpreadsheet()
    .getSheetByName(TIMEZONE_AUDIT_CONFIG.SHEET_NAME);
  if (!sheet) {
    throw new Error('TimezonePlanシートが見つかりません。');
  }

  const lastRow = sheet.getLastRow();
  if (lastRow < 2) {
    throw new Error('確認するデータ行がありません。');
  }

  const rowCount = Math.min(lastRow - 1, TIMEZONE_AUDIT_CONFIG.MAX_ROWS);
  const values = sheet.getRange(2, 1, rowCount, 3).getValues();
  const results = [];

  values.forEach((row, index) => {
    const rowNumber = index + 2;
    const enabled = row[0] === true;
    const startIso = String(row[1] || '').trim();
    const targetTimeZone = String(row[2] || '').trim();

    if (!enabled) {
      results.push({ row: rowNumber, status: 'SKIP', reason: '実行がTRUEではありません' });
      return;
    }

    const errors = [];
    if (!hasExplicitOffset_(startIso)) {
      errors.push('開始日時ISOにZまたは±HH:MMの時差情報が必要です');
    }

    const instant = new Date(startIso);
    if (Number.isNaN(instant.getTime())) {
      errors.push('開始日時ISOを日時として解釈できません');
    }

    if (!isValidTimeZone_(targetTimeZone)) {
      errors.push('変換先タイムゾーン名が無効です');
    }

    if (errors.length > 0) {
      results.push({ row: rowNumber, status: 'HOLD', errors });
      return;
    }

    results.push({
      row: rowNumber,
      status: 'OK',
      converted: Utilities.formatDate(
        instant,
        targetTimeZone,
        TIMEZONE_AUDIT_CONFIG.OUTPUT_FORMAT
      ),
      targetTimeZone,
      action: 'NONE'
    });
  });

  const summary = {
    dryRun: TIMEZONE_AUDIT_CONFIG.DRY_RUN,
    checkedRows: rowCount,
    ok: results.filter((item) => item.status === 'OK').length,
    hold: results.filter((item) => item.status === 'HOLD').length,
    skipped: results.filter((item) => item.status === 'SKIP').length,
    action: 'NONE',
    results
  };

  console.log(JSON.stringify(summary));
  return summary;
}

function hasExplicitOffset_(value) {
  return /T\d{2}:\d{2}(?::\d{2}(?:\.\d{1,3})?)?(?:Z|[+-]\d{2}:\d{2})$/.test(value);
}

function isValidTimeZone_(timeZone) {
  if (!timeZone || !/^[A-Za-z_+-]+\/[A-Za-z0-9_+\/-]+$/.test(timeZone)) {
    return false;
  }
  try {
    Utilities.formatDate(new Date(0), timeZone, 'yyyy-MM-dd HH:mm');
    return true;
  } catch (error) {
    return false;
  }
}

function validateTimezoneAuditConfig_(config) {
  if (config.DRY_RUN !== true) {
    throw new Error('安全のためDRY_RUNはtrue固定です。');
  }
  if (!Number.isInteger(config.MAX_ROWS) || config.MAX_ROWS < 1 || config.MAX_ROWS > 100) {
    throw new Error('MAX_ROWSは1〜100の整数にしてください。');
  }
}

実行前の準備

1. 元データではなく、少量の確認用スプレッドシートを作ります。

2. `TimezonePlan` シートへサンプルを2〜3行入力します。

3. Apps Scriptエディタへコードを貼り付けて保存します。

4. `auditCalendarTimezoneInputFree` を手動実行します。

5. 実行ログで `dryRun: true` と `action: NONE` を確認します。

最初は、同じ時点を `Asia/Tokyo` と `America/New_York` へ変換し、期待する日付と時刻になるかを見比べてください。

ログの見方

  • `OK`: 時差付き日時とタイムゾーン名を検証できた行
  • `HOLD`: 日時の時差情報がない、日時として読めない、またはタイムゾーン名が無効な行
  • `SKIP`: A列の実行が `TRUE` ではない行
  • `converted`: 指定したタイムゾーンで表示した確認用時刻
  • `action: NONE`: 予定やシートを変更していないことを示す固定値

タイトル、参加者、説明文などは読み込まず、ログにも出しません。実際の予定情報を扱う前に、日時だけのサンプルで確認するためです。

停止条件

  • `HOLD` が1件でもある場合は、カレンダー登録処理へ進まない
  • 変換後の日付が前日または翌日になる場合は、参加者へ基準時刻を確認する
  • 夏時間の切り替わり付近は、対象日そのものを使って再確認する
  • 変換先が `JST` や `EST` のような略称しか分からない場合は、IANA形式の正式名を確認する
  • 100行を超える場合は上限を増やさず、範囲を分けて確認する

制限と安全上の注意

  • このコードはGoogleカレンダーを読み書きしません。予定登録前の入力監査だけを行います
  • タイムゾーンの制度や夏時間は地域によって変更される場合があります。重要な予定は相手が提示した日時・地域名とも照合してください
  • Apps Scriptプロジェクト側のタイムゾーン設定だけで、時差情報のない文字列を自動補完しないでください
  • 自動実行トリガーは設定せず、まず手動実行で確認してください
  • `setValue`、`createEvent`、`deleteEvent` などの変更処理は無料例に含めていません

公開前チェックリスト

  • [ ] 日時に `Z` または `±HH:MM` が付いている
  • [ ] 変換先を `Asia/Tokyo` などのIANA形式で入力した
  • [ ] `DRY_RUN` が `true` のまま
  • [ ] `action` が `NONE`
  • [ ] `HOLD` が0件
  • [ ] 予定名・参加者・説明文などの個人情報をログへ出していない
  • [ ] 変換後の日時を参加者の案内と照合した

まとめ

タイムゾーンのずれは、予定を登録した後より、時差情報と変換先を入力段階で検査する方が安全です。まずは日時だけのdry-runで `HOLD` をなくし、変換後の日時を目視してから、実際の登録工程を別に設計してください。

関連する有料Tips商品を見る

GasおじのTips商品一覧を見る

※このコードは学習・検証用です。実データへ適用する前に少量で確認してください。Google公式・Google公認の商品ではありません。


あなたも記事の投稿・販売を
始めてみませんか?

Tipsなら簡単に記事を販売できます!
登録無料で始められます!

Tipsなら、無料ですぐに記事の販売をはじめることができます Tipsの詳細はこちら
 

この記事のライター

ツールおじ|GoogleアカウントをAIエージェント化

おう、Gasおじだ。 AIツールとSaaSに散々突っ込んで遠回りした結果、最後に強かったのは「今あるGoogleアカウント」だった。 今ではAIエージェントであらゆるタスクを自動化して無双してるぞ。 GAS、スプレッドシート、フォーム、Gmail、AIエージェントを組み合わせれば、個人でも小さな会社でも、手作業だらけの業務はかなり自動化できる。 ここでは机上のAI論じゃなく、現場で動くテンプレ、コード、手順だけを置いていくぞ。 高いツールを増やす前に、まずお前さんのGoogleアカウントを仕事するエージェントに変えようじゃないか。

このライターが書いた他の記事

  • Gmailの定型連絡を「送信せず」まとめて下書き化する|Gmail下書きテンプレGAS Pro

    ¥2,980
    1 %獲得
    (29 円相当)
  • あとで見るURLを二重登録しない|GASで読書・動画ウォッチリストをdry-run監査

  • カレンダーの二重登録を作成前に発見|GASで予定候補をdry-run監査

関連のおすすめ記事

  • Gmailの定型連絡を「送信せず」まとめて下書き化する|Gmail下書きテンプレGAS Pro

    ¥2,980
    1 %獲得
    (29 円相当)
    ツールおじ|GoogleアカウントをAIエージェント化

    ツールおじ|GoogleアカウントをAIエージェント化

  • 【Python】 Con-Que 【データベース接続】

    ¥3,000
    1 %獲得
    (30 円相当)
    GoGorilla

    GoGorilla

  • USBメモリで持ち運べるLinux Mint 22.1と永続的な書き込み領域の作成法【Rufus だけで作成する方法を初心者向けに徹底解説】

    ¥500
    1 %獲得
    (5 円相当)
    SmartSenior

    SmartSenior