【bat】バッチファイルでログを日付別ファイルに自動保存する完全ガイド|%DATE%整形・wmic・フォルダ階層・エラー分離・ローテーション連携まで

【bat】バッチファイルでログを日付別ファイルに自動保存する完全ガイド|%DATE%整形・wmic・フォルダ階層・エラー分離・ローテーション連携まで bat

バッチファイルでログを残す際、すべて1つのファイルに書き続けると肥大化・検索困難になります。日付ごとにログファイルを自動で分けることで、「今日の実行結果だけ確認したい」「先週のエラーを調べたい」という操作が格段に楽になります。

この記事でわかること

  • %DATE% の文字列切り出しで日付付きファイル名を生成する方法
  • ロケール(地域設定)に左右されない wmic / PowerShell による安全な日付取得
  • logs\ 配下にフォルダ階層(年/月)で整理する方法
  • 標準ログとエラーログを別ファイルに分ける方法
  • :log サブルーチンでタイムスタンプ付き行をすっきり書く方法
  • ログローテーション(古いファイルの自動削除)との連携
スポンサーリンク

日付付きログファイルの管理方式比較

方式 ファイル例 メリット デメリット
1ファイルに全追記 app.log シンプル・設定不要 肥大化・日付検索困難
日付別ファイル(推奨) log_20250428.txt 日ごとに分離・ローテーション容易 ファイル数が増える
月別ファイル log_202504.txt ファイル数少ない 1ファイルが大きくなりやすい
年月フォルダ階層 logs\2025\04\28.txt 視認性高・検索容易 フォルダ作成処理が必要

基本:%DATE% で日付付きファイル名を作る

Windows の %DATE% 環境変数は 地域設定によって形式が異なります。日本語Windowsでは 2025/04/28(スラッシュ区切り)が一般的ですが、Mon 04/28/2025(英語ロケール)になる環境もあります。:~0,4% などの文字列切り出しで整形することで対応できます。

基本: 日付付きログファイルへの出力
@echo off
setlocal

REM ===== 日付を YYYYMMDD 形式に整形(日本語Windowsロケール想定)=====
REM %DATE% の形式例: 2025/04/28 (月) → ~0,4=年 ~5,2=月 ~8,2=日
set YYYY=%DATE:~0,4%
set MM=%DATE:~5,2%
set DD=%DATE:~8,2%
set TODAY=%YYYY%%MM%%DD%

REM ログ保存先フォルダ(なければ自動作成)
set LOGDIR=C:\logs
if not exist "%LOGDIR%" mkdir "%LOGDIR%"

set LOGFILE=%LOGDIR%\app_%TODAY%.log

REM ===== ログ出力(追記モード >> )=====
echo ==============================  >> "%LOGFILE%"
echo 実行開始: %DATE% %TIME%         >> "%LOGFILE%"
echo ==============================  >> "%LOGFILE%"

REM ここに実際の処理を記述
echo 処理1を実行中...               >> "%LOGFILE%"
echo 処理1が完了しました。           >> "%LOGFILE%"

echo 実行終了: %DATE% %TIME%         >> "%LOGFILE%"
endlocal
= を使ったリダイレクト先指定の注意点
>> "%LOGFILE%" のようにパスを ダブルクォートで囲むことを推奨します。フォルダ名やファイル名にスペースが含まれる場合にエラーになるのを防ぎます。リダイレクトの詳細はリダイレクト(> >> 2>&1)完全ガイドを参照してください。

ロケールに左右されない日付取得(wmic / PowerShell)

%DATE% の形式はPCの地域設定次第です。複数の環境で動かすバッチでは wmic または PowerShell を使うとロケール非依存で安定して日付を取得できます。

wmic で YYYYMMDD を取得(ロケール非依存)
@echo off
setlocal

REM wmic os get LocalDateTime → 20250428143022.000000+540 形式で取得
for /f "tokens=2 delims==" %%A in ('wmic os get LocalDateTime /value') do (
    set DATETIME=%%A
)

REM YYYYMMDD を切り出す
set TODAY=%DATETIME:~0,8%

REM YYYY-MM-DD 形式に変換したい場合
set YYYY=%DATETIME:~0,4%
set MM=%DATETIME:~4,2%
set DD=%DATETIME:~6,2%
set TODAY_DASH=%YYYY%-%MM%-%DD%

echo 今日の日付: %TODAY_DASH%

set LOGFILE=C:\logs\app_%TODAY%.log
echo 実行: %TODAY_DASH% %DATETIME:~8,2%:%DATETIME:~10,2%:%DATETIME:~12,2% >> "%LOGFILE%"
endlocal
PowerShell で日付を取得(別の方法)
@echo off
setlocal

REM PowerShell で YYYYMMDD を取得
for /f %%D in ('powershell -NoProfile -Command "Get-Date -Format yyyyMMdd"') do (
    set TODAY=%%D
)

set LOGFILE=C:\logs\app_%TODAY%.log
echo 実行開始: %TODAY% >> "%LOGFILE%"
endlocal
wmic vs PowerShell の使い分け
wmic はWindows XP/7以降で動作し、PowerShell不要な環境でも使えます。PowerShell は書式指定(yyyy-MM-dd_HH-mm-ss 等)が直感的で柔軟です。日付のファイル名利用全般は日付と時間をファイル名に挿入する方法も参照してください。

日付+時刻でファイル名をさらに細かく管理する

1日に複数回実行するバッチや、同日の実行ごとにファイルを分けたい場合は日付+時刻(hhmmss)をファイル名に付与します。

日付+時刻付きファイル名(YYYYMMDD_HHMMSS)
@echo off
setlocal

REM wmic でタイムスタンプを取得(YYYYMMDDHHMMSS形式)
for /f "tokens=2 delims==" %%A in ('wmic os get LocalDateTime /value') do (
    set DT=%%A
)

REM 日付部分: YYYYMMDD
set TODAY=%DT:~0,8%
REM 時刻部分: HHMMSS
set HHMMSS=%DT:~8,6%

set LOGFILE=C:\logs\app_%TODAY%_%HHMMSS%.log

echo 開始: %TODAY:~0,4%-%TODAY:~4,2%-%TODAY:~6,2% %HHMMSS:~0,2%:%HHMMSS:~2,2%:%HHMMSS:~4,2% >> "%LOGFILE%"
echo 処理を実行... >> "%LOGFILE%"
echo 終了 >> "%LOGFILE%"
endlocal
%TIME% はスペースに注意
標準の %TIME% は1桁時間のとき 9:05:03(先頭にスペース)になります。ファイル名に使う場合はスペースがエラー原因になるため、wmic の LocalDateTime%TIME: =0%(スペースを0に置換)で対処してください。

年/月フォルダ階層でログを整理する

ログファイルが増えてきたら、logs\2025\04\ のようなフォルダ階層で管理すると視認性が上がります。

年/月フォルダ階層に日別ログを保存
@echo off
setlocal

REM wmic で日付取得
for /f "tokens=2 delims==" %%A in ('wmic os get LocalDateTime /value') do set DT=%%A
set YYYY=%DT:~0,4%
set MM=%DT:~4,2%
set DD=%DT:~6,2%

REM logs‚5\ フォルダを自動作成
set LOGDIR=C:\logs\%YYYY%\%MM%
if not exist "%LOGDIR%" mkdir "%LOGDIR%"

REM ファイル名: 28.log(日のみ)
set LOGFILE=%LOGDIR%\%DD%.log

echo [%YYYY%-%MM%-%DD%] 処理開始 >> "%LOGFILE%"
REM (ここに実際の処理を記述)
echo [%YYYY%-%MM%-%DD%] 処理終了 >> "%LOGFILE%"
endlocal
mkdir はネストした階層を一括作成できる
mkdir "C:\logs\2025\04" のように深い階層を指定すると、中間フォルダ(2025\)も自動的に作成されます(Windows Vista以降)。if not exist で存在確認してから作成することで、既存フォルダへの上書きエラーを防げます。

:log サブルーチンでタイムスタンプ付き行を効率よく書く

echo に毎回 %DATE% %TIME% を書くのは冗長です。:log サブルーチンに切り出すと1行で書けて保守しやすくなります。

:log サブルーチンでタイムスタンプ付き出力
@echo off
setlocal

for /f "tokens=2 delims==" %%A in ('wmic os get LocalDateTime /value') do set DT=%%A
set TODAY=%DT:~0,4%%DT:~4,2%%DT:~6,2%

set LOGFILE=C:\logs\app_%TODAY%.log

REM メイン処理
call :log "処理開始"
call :log "データ取得を実行"
xcopy /E /Y "C:\src" "C:\dst" >> "%LOGFILE%" 2>&1
call :log "コピー完了(ERRORLEVEL=%ERRORLEVEL%)"
call :log "処理終了"
goto :eof

:log
REM タイムスタンプ付きで画面とログファイルの両方に出力
set MSG=%~1
echo [%DATE% %TIME%] %MSG%
echo [%DATE% %TIME%] %MSG% >> "%LOGFILE%"
goto :eof
画面とファイルに同時出力するテクニック
サブルーチン内で echo(画面出力)と echo >> "%LOGFILE%"(ファイル出力)の2行を書くことで、実行中にコンソールでも確認できます。ログ記録の詳細パターンはバッチファイルでログを出力する完全ガイドも参考にしてください。

エラーログを別ファイルに分離する

通常ログとエラーログを分けることで、エラー発生時に専用ファイルだけ確認すれば済みます。監視ツールでエラーファイルのサイズを見るだけで異常検知もできます。

標準ログとエラーログを別ファイルに分ける
@echo off
setlocal

for /f "tokens=2 delims==" %%A in ('wmic os get LocalDateTime /value') do set DT=%%A
set TODAY=%DT:~0,8%

set LOGDIR=C:\logs
if not exist "%LOGDIR%" mkdir "%LOGDIR%"

REM 通常ログとエラーログを別ファイルに
set LOGFILE=%LOGDIR%\app_%TODAY%.log
set ERRFILE=%LOGDIR%\error_%TODAY%.log

echo 開始: %DATE% %TIME% >> "%LOGFILE%"

REM 標準出力はLOGFILE、エラー出力はERRFILEに
xcopy /E /Y "C:\src" "C:\dst" >> "%LOGFILE%" 2>> "%ERRFILE%"

if %ERRORLEVEL% neq 0 (
    echo [ERROR] xcopy 失敗: コード=%ERRORLEVEL% >> "%ERRFILE%"
    echo [ERROR] xcopy 失敗: コード=%ERRORLEVEL% >> "%LOGFILE%"
)

echo 終了: %DATE% %TIME% >> "%LOGFILE%"
endlocal
エラーファイルの存在チェックで異常検知
if exist "%ERRFILE%" でエラーファイルが生成されているか確認し、存在すれば通知やアラート処理を実行できます。ファイルサイズが0より大きい場合のみエラーとみなす場合は for %%F in ("%ERRFILE%") do if %%~zF gtr 0 で判定します。

ログローテーションとの連携(古いファイルを自動削除)

日付別ファイルは長期運用するとファイルが溜まり続けます。forfiles コマンドで古いログを自動削除する処理をバッチに組み込みましょう。

30日以上前のログを自動削除
@echo off
setlocal

for /f "tokens=2 delims==" %%A in ('wmic os get LocalDateTime /value') do set DT=%%A
set TODAY=%DT:~0,8%

set LOGDIR=C:\logs
if not exist "%LOGDIR%" mkdir "%LOGDIR%"
set LOGFILE=%LOGDIR%\app_%TODAY%.log

REM ===== メイン処理 =====
call :log "処理開始"
REM (実際の処理をここに記述)
call :log "処理終了"

REM ===== 30日以上前のログを削除 =====
forfiles /p "%LOGDIR%" /m "*.log" /d -30 /c "cmd /c del @file"

goto :eof

:log
echo [%DATE% %TIME%] %~1
echo [%DATE% %TIME%] %~1 >> "%LOGFILE%"
goto :eof
forfiles の /d オプション
/d -30 は「現在から30日以上前に更新されたファイル」を対象にします。/d +0 にすると今日以外のすべてのファイルが対象になります。/m "*.log" でログファイルのみに限定できます。より詳細なローテーション(世代管理・月別アーカイブ)はログローテーション完全ガイドを参照してください。

まとめ

バッチファイルで日付別ログファイルを自動生成するポイントをまとめます。

  • 日付取得: %DATE% は簡単だがロケール依存。wmic LocalDateTime が安全
  • ファイル名: app_YYYYMMDD.log が検索・ソートしやすい
  • 1日複数回: YYYYMMDD_HHMMSS で実行ごとにファイルを分ける
  • フォルダ階層: logs\YYYY\MM\DD.log で月別・日別に整理
  • :log サブルーチン: タイムスタンプ付き行を1行で書ける再利用パターン
  • エラー分離: 2>> error_YYYYMMDD.log でエラー専用ファイルに記録
  • 古いファイル削除: forfiles /d -30 でローテーション自動化

関連記事: バッチファイルでログを出力する完全ガイド / リダイレクト(> >> 2>&1)完全ガイド / ログローテーション完全ガイド

よくある質問(FAQ)

Q%DATE% で切り出した年が2桁になってしまいます。
APCの地域設定が西暦2桁表示(例: 25/04/28)になっている場合に起こります。対処法は2つあります。①%DATE:~0,4% の切り出し位置を地域設定に合わせる、②wmic の LocalDateTime を使う(常に4桁年)です。複数の環境で動かすスクリプトには wmic または PowerShell を推奨します。
Qログファイルを毎回上書きではなく追記にしたいです。
A>(上書き)ではなく >>(追記)を使ってください。日付別ファイルの場合は同じ日の複数回実行が app_20250428.log に追記され、セパレーター(echo ======)や実行開始/終了のタイムスタンプで実行ごとの境目を示すと見やすくなります。
Qタスクスケジューラから実行したときにログファイルが別の場所に作られます。
Aタスクスケジューラはデフォルトの作業ディレクトリが C:\Windows\System32 になるため、相対パス(.\logs\)でログを保存するとシステムフォルダに作られます。ログファイルのパスは必ず 絶対パス(例: C:\myapp\logs\)で指定するか、cd /d "%~dp0" をバッチ先頭に書いて作業ディレクトリをバッチ自身の場所に変更してください。
Qログファイルが文字化けします。
AバッチファイルのデフォルトエンコードはShift-JIS(CP932)です。Windowsのメモ帳やサクラエディタでは問題ありませんが、UTF-8ツールで開くと文字化けします。対処法: ①Shift-JIS対応ツールで確認する、②バッチ先頭に chcp 65001 を追加してUTF-8出力にする(ただし一部コマンドで問題が起きる場合あり)、③PowerShellのリダイレクト(Out-File -Encoding UTF8)を使う。
Qログファイルをネットワーク共有フォルダに保存したいです。
AUNCパス(\\server\share\logs\)をそのまま使えます。set LOGDIR=\\server\share\logs と設定し、if not exist "%LOGDIR%" でフォルダ存在確認してから書き込んでください。ただし実行ユーザーがネットワーク共有への書き込み権限を持っていることが前提です。タスクスケジューラのSYSTEMアカウントはネットワーク共有にアクセスできないことが多いため、専用のサービスアカウントを使用してください。