バッチファイルでログを残す際、すべて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 を使うとロケール非依存で安定して日付を取得できます。
@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
@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 はWindows XP/7以降で動作し、PowerShell不要な環境でも使えます。PowerShell は書式指定(
yyyy-MM-dd_HH-mm-ss 等)が直感的で柔軟です。日付のファイル名利用全般は日付と時間をファイル名に挿入する方法も参照してください。日付+時刻でファイル名をさらに細かく管理する
1日に複数回実行するバッチや、同日の実行ごとにファイルを分けたい場合は日付+時刻(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% は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 logs5\ フォルダを自動作成
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 "C:\logs\2025\04" のように深い階層を指定すると、中間フォルダ(2025\)も自動的に作成されます(Windows Vista以降)。if not exist で存在確認してから作成することで、既存フォルダへの上書きエラーを防げます。:log サブルーチンでタイムスタンプ付き行を効率よく書く
各 echo に毎回 %DATE% %TIME% を書くのは冗長です。:log サブルーチンに切り出すと1行で書けて保守しやすくなります。
@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 コマンドで古いログを自動削除する処理をバッチに組み込みましょう。
@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
/d -30 は「現在から30日以上前に更新されたファイル」を対象にします。/d +0 にすると今日以外のすべてのファイルが対象になります。/m "*.log" でログファイルのみに限定できます。より詳細なローテーション(世代管理・月別アーカイブ)はログローテーション完全ガイドを参照してください。まとめ
バッチファイルで日付別ログファイルを自動生成するポイントをまとめます。
- 日付取得:
%DATE%は簡単だがロケール依存。wmicLocalDateTimeが安全 - ファイル名:
app_YYYYMMDD.logが検索・ソートしやすい - 1日複数回:
YYYYMMDD_HHMMSSで実行ごとにファイルを分ける - フォルダ階層:
logs\YYYY\MM\DD.logで月別・日別に整理 - :log サブルーチン: タイムスタンプ付き行を1行で書ける再利用パターン
- エラー分離:
2>> error_YYYYMMDD.logでエラー専用ファイルに記録 - 古いファイル削除:
forfiles /d -30でローテーション自動化
関連記事: バッチファイルでログを出力する完全ガイド / リダイレクト(> >> 2>&1)完全ガイド / ログローテーション完全ガイド
よくある質問(FAQ)
25/04/28)になっている場合に起こります。対処法は2つあります。①%DATE:~0,4% の切り出し位置を地域設定に合わせる、②wmic の LocalDateTime を使う(常に4桁年)です。複数の環境で動かすスクリプトには wmic または PowerShell を推奨します。>(上書き)ではなく >>(追記)を使ってください。日付別ファイルの場合は同じ日の複数回実行が app_20250428.log に追記され、セパレーター(echo ======)や実行開始/終了のタイムスタンプで実行ごとの境目を示すと見やすくなります。C:\Windows\System32 になるため、相対パス(.\logs\)でログを保存するとシステムフォルダに作られます。ログファイルのパスは必ず 絶対パス(例: C:\myapp\logs\)で指定するか、cd /d "%~dp0" をバッチ先頭に書いて作業ディレクトリをバッチ自身の場所に変更してください。chcp 65001 を追加してUTF-8出力にする(ただし一部コマンドで問題が起きる場合あり)、③PowerShellのリダイレクト(Out-File -Encoding UTF8)を使う。\\server\share\logs\)をそのまま使えます。set LOGDIR=\\server\share\logs と設定し、if not exist "%LOGDIR%" でフォルダ存在確認してから書き込んでください。ただし実行ユーザーがネットワーク共有への書き込み権限を持っていることが前提です。タスクスケジューラのSYSTEMアカウントはネットワーク共有にアクセスできないことが多いため、専用のサービスアカウントを使用してください。

