问题
Please consider the following codes:
@echo off
setlocal enabledelayedexpansion
FOR /L %%G IN (0,1,19) DO (
set /a "Dday=%_day%+%%G"
if %mth% equ sml (
if !Dday! gtr 30 (
set "_day=1"
set /a "_month+=1"
)
if !_month! gtr 12 (
set "_month=1"
set /a "_year+=1"
)
) else (
if %mth% equ big (
if !Dday! gtr 31 (
set "_day=1"
set /a "_month+=1"
)
if !_month! gtr 12 (
set "_month=1"
set /a "_year+=1"
)
)
)
echo !Dday!/!_month!/!_year!.txt
)
Consider the following date: 20/04/2016
_day = 20
; _month = 04
; _year = 2016
; mth=sml
;
and my output is this:
It increases the day from 30 instead of changing it to 1. Can I know what have I done wrong? Please advise. Thanks
回答1:
There are two problems in this script. First as @SomethignDark pointed out, you need to use !_day!
instead of %_day%
.
Second when Dday
is greater than 30, %%G
is 12. So you expression of !_day!+%%G
will be 13 instead of 1.
So you need something like
...
FOR /L %%G IN (0,1,19) DO (
set /a "Dday=!_day!+%%G"
if !_day! equ 1 set /a "Dday=!_day!+%%G-12"
...
回答2:
You know, pure batch is really cumbersome with date math. What will you do for months with 31 days? For February? During leap year? You should consider, if not altogether switching to another language with a proper date object, then at least borrowing from one. Here's a Batch + PowerShell hybrid example:
<# : batch portion
@echo off & setlocal
if "%~1"=="" (
echo usage: %~nx0 startdate
goto :EOF
)
set "startdate=%~1"
set "daysToAdd=19"
rem # evaluate PowerShell hybrid code and capture output as %%I
for /f "delims=" %%I in ('powershell -noprofile "iex (${%~f0} | out-string)"') do (
rem # do something useful with %%I here
echo %%I.txt
)
goto :EOF
: end batch / begin PowerShell hybrid code #>
# cast "startdate" environment variable value as a datetime object
[datetime]$d = $env:startdate
for ($i = 0; $i -le $env:daysToAdd; $i++) {
$d.addDays($i).toString("dd-MM-yyyy")
}
Or if you prefer the speed of VBScript, here's a Batch + VBScript hybrid example. Its allowed date input is perhaps not quite as flexible as that of PowerShell, but it does execute nearly instantly.
<!-- : batch portion
@echo off & setlocal
if "%~1"=="" (
echo usage: %~nx0 startdate
goto :EOF
)
set "startdate=%~1"
set "daysToAdd=19"
rem # evaluate VBScript hybrid code and capture output as %%I
for /f "delims=" %%I in ('cscript /nologo "%~f0?.wsf" "%startdate%" "%daysToAdd%"') do (
rem # do something useful with %%I here
echo %%I.txt
)
goto :EOF
: end batch / begin VBScript -->
<job>
<script language="VBScript">
if not IsDate(WSH.Arguments(0)) then
WSH.StdErr.WriteLine("Not a valid date.")
WSH.Quit(1)
end if
d = CDate(WSH.Arguments(0))
For i = 0 to WSH.Arguments(1)
d2 = DateAdd("d", i, d)
WSH.Echo(Day(d2) & "-" & Month(d2) & "-" & Year(d2))
Next
</script>
</job>
Or if you're more comfortable with JavaScript syntax, you could do a Batch + JScript hybrid solution.
@if (@CodeSection == @Batch) @then
@echo off & setlocal
if "%~1"=="" (
echo usage: %~nx0 startdate
goto :EOF
)
set "startdate=%~1"
set "daysToAdd=19"
rem // evaluate VBScript hybrid code and capture output as %%I
for /f "delims=" %%I in (
'cscript /nologo /e:JScript "%~f0" "%startdate%" "%daysToAdd%"'
) do (
rem // do something useful with %%I here
echo %%I.txt
)
goto :EOF
@end // end batch / begin JScript
Date.prototype.addDays = function(num) {
this.setDate(this.getDate() + num);
return this;
}
for (var i=0; i<WSH.Arguments(1); i++) {
var d = new Date(WSH.Arguments(0)).addDays(i);
WSH.Echo([d.getDate(), (d.getMonth() + 1), d.getFullYear()].join('-'));
}
Either way, VBScript, JScript, and PowerShell will all let you add n days to a date object, and that date object automatically handles calendar quirks without your explicitly needing to script for them.
来源:https://stackoverflow.com/questions/36732545/batch-to-output-a-list-of-dates-from-given-for-l-parameter