批次檔原生只支援十進位整數運算(set /a),卻要處理 60 進位(分/秒)、24 進位(時)、12 進位(月)、不定天數(月/閏年)的時間計算,難度極高。本文系統拆解「去零→十進位運算→進位轉換→補零」四步法,並提供可直接引用的子程式::AddSec、:SubSec、:IsLeapYear、:DaysInMonth。
| 難點 | 對策 |
|---|---|
| 時間元件前導零導致八進位誤判(08、09) | 前綴 1 再取模 100:set /a m=1%%m%%100 |
| 小時可能為空格(單位數) | set "h=%time:~,2%" 後 set "h=%h: =0%" 替換空格為零 |
| 進位制混雜(秒/分 60、時 24、月 12、日 28/29/30/31) | 統一轉為「總秒數」或「總天數」運算,再反推 |
| 閏年判斷(能被 400 整除、或被 4 整除但非 100 倍數) | 子程式 :IsLeapYear 回傳 1/0 |
:: 去零:將 "08" → 8,避免八進位
set /a m=1%m%%%100, s=1%s%%%100
:: 運算後補零:確保兩位數顯示
set "m=0%m%" & set "m=%m:~-2%"
set "s=0%s%" & set "s=%s:~-2%"
@echo off & setlocal enabledelayedexpansion
set "h=%time:~,2%" & set "h=%h: =0%"
set /a "m=1%time:~3,2%%%100, s=1%time:~6,2%%%100"
echo 目前時間 %h%:%m%:%s%
for /l %%a in (1,1,1000) do (
set /a s+=1
if !s! equ 60 set /a s=0, m+=1
if !m! equ 60 set /a m=0, h+=1
if !h! equ 24 set /a h=0
)
set "m=0%m%" & set "m=%m:~-2%"
set "s=0%s%" & set "s=%s:~-2%"
echo 1000秒後 %h%:%m%:%s%
pause > nul
完整程式碼篇幅較長,核心邏輯:
num_d = 秒數/86400、剩餘秒數 num_h = 秒數%%86400。D-=1,若 D==0 呼叫 :PrevMonth 取得上月天數(含閏年 2 月判斷)。:IsLeapYear <-- 年份在 %y%
set /a a=%y%%%4, b=%y%%%100, c=%y%%%400, _2=28
if %b% equ 0 (if %c% equ 0 set /a _2+=1) else (if %a% equ 0 set /a _2+=1)
set _days=%_2% & goto :eof
:DaysInMonth <-- 月份在 %mo%, 年份在 %y%
if %mo%==2 call :IsLeapYear & set _days=%_2% & goto :eof
for %%a in (1 3 5 7 8 10 12) do if %mo%==%%a set _days=31 & goto :eof
for %%a in (4 6 9 11) do if %mo%==%%a set _days=30 & goto :eof
goto :eof
(Get-Date).AddDays(-30) 或 VBScript DateAdd,批次檔維護成本極高且易出錯。lib_datetime.bat,主腳本 call lib_datetime.bat 後直接使用 :AddDays 等標籤。