CMD.EXE だけで昨日の日付けを求める

質問掲示板を見ていると良く見かける質問で、今日の日付けをファイル名につける等の日付け関係のものがある。今日の日付けだと、date/t%DATE% を加工するだけなので簡単。たまに、昨日の日付けを求めると言うのがある。簡単に行うのは、VBScriptJavaScriptを使う方法だが、使わない範囲で出来るだけコンパクトに作ってみた。

@echo off
REM 日付の前日を求める。結果は ANS にセット。
REM 引数(YYYYMMDD or YYYY-MM-DD or YYYY/MM/DD)がないときは本日とする。
if "%1"=="" (for /F %%A in ('date /t') do set ANS=%%A) else set ANS=%1
if not "%ANS:~8%"=="" set/a ANS=%ANS:~0,4%%ANS:~5,2%%ANS:~8,2%
set/a ANS-=1
if not %ANS:~-2%==00 goto ans
if %ANS:~4,2%==01 set/a ANS+=-10000+1131&goto ans
for %%M in (02 04 06 08 09 11) do if %ANS:~4,2%==%%M set/a ANS+=-100+31&goto ans
if not %ANS:~4,2%==03 set/a ANS+=-100+30&goto ans
set/a ANS+=-100+28+(!(%ANS:~0,4%%%4)^^!(%ANS:~0,4%%%100)^^!(%ANS:~0,4%%%400))
:ans

一応、サブルーチン形式で作ってみた。引数はyyyymmddでも、区切り文字入りでも可能。ただし日付けの正当性まではチェックしてない。
ワーク用の環境変数を使っていないため、サブルーチンでなく、スクリプト中に埋め込んで使うことも出来るだろう(それを考慮して goto :eof を使ってない)。
ポイントは、年・月・日を分けずに8桁の数字として扱うことと、閏年の算出の工夫(排他的論理和を使用)。
また、ANSの値は、最初に8桁の数字をセットして1引いた後は set/a で最後に一度しか変更しないので、goto を使わないで、if ( ) else ( ) でも書けるかも知れない。

何日前、何日後をバッチだけでやるのだと、ジュリアンデイトに直してから計算するんだろうけど、VBS, JS に頼ってしまいそう。これはまた別途書くことにする。