0

I have bat script for loop function

@echo off set /p a="Start Date(yyyymmdd):"%=% set /p b="Finish Date (yyyymmdd):"%=%

echo %a% echo %b%

echo start loop

FOR /L %%c IN (%a%,1,%b%) DO ( echo %%c

set inputan=%%c

call test_loopong.bat %inputan%

)

I need to run according to the range of start and end date input. But from the script above, for example the start date is 20221231 and the end date is 20230103 will loop all numbers from 20221231, 20221232, 20221233......20230103

Please someone can help me.

Thanks

1 Answers1

0
@ECHO Off
SETLOCAL
set /p "startdate=Start Date(yyyymmdd):"
set /p "finishdate=Finish Date (yyyymmdd):"

echo %startdate% 
echo %finishdate%

IF %finishdate% lss %startdate% ECHO Invalid DATE range&GOTO :eof

echo start loop

FOR /L %%c IN (%startdate%,1,%finishdate%) DO (
 FOR /F %%y IN ('set /a inputan^=%%c %% 100') DO IF %%y lss 32 IF %%y gtr 0 (
  echo %%c
  set /a inputan=%%c
  call :test_loopong.bat %%c
 )
)
GOTO :EOF

:test_loopong.bat
ECHO IN test_loopong : %%1=%1 inputan=%inputan%
GOTO :eof

I changed the variable names so that they are maintainable, 'though I've no idea what inputan means.

Added invalid date-range check.

Note syntax of set /p

Forget for the moment what for...%%y... does.

I used a set /a since %%c must be numeric.

Use set "var1=value" for setting STRING values - this avoids problems caused by trailing spaces.

I converted test_loopong.bat to an internal subroutine (call :name) for demonstration purposes to avoid having to generate another file.

I'm having that subroutine simply display the value of the variable inputan and the parameter %1. %%c can be delivered as a parameter to the subroutine (be it internal or external) but your syntax would appear to omit the parameter because of the delayed expansion trap - %var% will be replaced by the value of var at the time the outer loop (for...%%c) is encountered.

Now the for...%%y jiggery-pokery.

The command set /a inputan=%%c % 100 would set inputan to %%c mod 100. There's no importance about the variable name - that one's about to be assigned a different value again in a couple of lines.

When used in a for /f, batch will execute the set/a command and echo the result to the metavariable %%y.

However, = and % are special characters and need to be "escaped" (interpreted without their special meaning). Th escape character for most specials is caret (^) but for % is % itself.

The result of the calculation is assigned to %%y and we can then test that %%y is lss 32 - Less than 32, and also it is gtr 0 - Greater than 0. Only then do we call test_loopong.bat. This eliminates most non-dates

If you don't want to skip the non-dates, then remove the for...%%y line and delete one of the ) lines.

--- further thoughts ----

Suppressing the days 32..99 & 00 really only does half the job. Much better if we suppress months 13..99 & 00. The revision then would be (presenting just the main loop, minus the frippery)

FOR /L %%c IN (%startdate%,1,%finishdate%) DO (
 FOR /F %%e IN ('set /a inputan^=%%c %% 10000') DO IF %%e lss 1232 IF %%e gtr 100 (
  FOR /F %%y IN ('set /a inputan^=%%c %% 100') DO IF %%y lss 32 IF %%y gtr 0 (
   echo %%c
   set /a inputan=%%c
   call :test_loopong.bat %%c
  )
 )
)

Same principle, just dealing with months in place of days.

One slight problem with this method is that it's as slow as a wet week.

So - a different approach

SET /a yyyy=%startdate:~0,4%
SET /a mm1=1%startdate:~4,2%
SET /a dd1=1%startdate:~-2%

:loop2
SET /a inputan=%yyyy%0000+%mm1%00+dd1-10100
IF %inputan% gtr %finishdate% GOTO :eof
CALL :test_loopong.bat %inputan%
SET /a dd1+=1
IF %dd1% leq 131 GOTO loop2
SET /a dd1=101&SET /a mm1+=1
IF %mm1% leq 112 GOTO loop2
SET /a mm1=101
SET /a yyyy+=1
GOTO loop2

This sets yyyy to the year and mm1/dd1 to 100+(month/day). 100+ needs to be done since batch regards a numeric string that starts 0 as octal hence August and September cause problems.

So - calculate inputan by tringing 4 0s to yyyy, adding 100*mm1 and dd1, then subtracting 10100 since mm1 is mm+100 and dd1 is dd+100.

If the resultant inputan is greater than the finish date, end the routine.

Test using inputan.

Next day - add 1 to dd1.

If the result is less than or equal to 131, we're fine. Otherwise set dd1 to 101 and increment the month Same recipe for mm1, limit is 112 and bump the year if required.

---- Further revision to deal with non-dates 31st Apr, Jun, Sep, Nov and Feb (include leap years) ---

@ECHO Off
SETLOCAL
set /p "startdate=Start Date(yyyymmdd):"
set /p "finishdate=Finish Date (yyyymmdd):"

echo %startdate% 
echo %finishdate%

IF %finishdate% lss %startdate% ECHO Invalid DATE range&GOTO :eof

echo start loop

GOTO ver2

FOR /L %%c IN (%startdate%,1,%finishdate%) DO (
 FOR /F %%e IN ('set /a inputan^=%%c %% 10000') DO IF %%e lss 1232 IF %%e gtr 100 (
  FOR /F %%y IN ('set /a inputan^=%%c %% 100') DO IF %%y lss 32 IF %%y gtr 0 (
   echo %%c
   set /a inputan=%%c
   call :test_loopong.bat %%c
  )
 )
)
GOTO :EOF

:ver2
SET /a yyyy=%startdate:~0,4%
SET /a mm1=1%startdate:~4,2%
SET /a dd1=1%startdate:~-2%

:loop2
SET /a inputan=%yyyy%0000+%mm1%00+dd1-10100
IF %inputan% gtr %finishdate% GOTO :eof
CALL :test_loopong.bat %inputan%
SET /a dd1+=1
SET /a inputan=yyyy %% 4
IF %mm1%==102 IF %dd1% gtr 129 (GOTO nextmonth) ELSE IF %inputan% neq 0 IF %dd1%==129 GOTO nextmonth
FOR %%e IN (104 106 109 111) DO IF %%e131==%mm1%%dd1% GOTO nextmonth
IF %dd1% leq 131 GOTO loop2
:nextmonth
SET /a dd1=101&SET /a mm1+=1
IF %mm1% leq 112 GOTO loop2
SET /a mm1=101
SET /a yyyy+=1
GOTO loop2


GOTO :eof

:test_loopong.bat
ECHO IN test_loopong : %%1=%1 inputan=%inputan%
GOTO :eof
Magoo
  • 77,302
  • 8
  • 62
  • 84
  • inputan is other variable on test_loopong.bat, or you can means input. in test_loopong.bat file, I will use input from the date range generated earlier. – Noval Juniardi Dec 23 '22 at 06:52
  • This method create _all months_ with 31 days so it fails by 1 day in April, June, September and Novemeber, and it fails by 3 days in February in normal years, but fails by 2 days in leap years... – Aacini Dec 23 '22 at 23:44
  • @Aacini : OP's original proposition was to process all "dates" in the range, including days numbered 32..99 & 00. I assumed that the process being `called` was performing date-validation. – Magoo Dec 24 '22 at 04:33
  • Hmm... I understood it differently: the question specifies "Loop a date range", but the example script will "loop all numbers from 20221231, 20221232, 20221233......20230103". The OP asks for help removing those non-date numbers from the loop... However, only the OP could clarify this point. – Aacini Dec 26 '22 at 06:18