Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to loop through a date range in a batch file

I run a report through a batch file , at the moment I have a message box prompt that allows me to input a date that I want to run the report for , this works fine and sets the variable to the inputted date.

How ever I am trying to further automate this.

For example I would like to run this report from 060114 to 120114 (MMDDYY) I would like to use the loop function so that the script being ran through the batch will run through each date in the range and once it reaches the end date in will go to the next section of the batch file.

for example the first section uses the date inputted and assigns to the variable %b

I have set up two prompts for the date range , the from date will assign to the variable %c and the end date will assign to %d.

The dates assign to the variables correctly , how ever what is the best method to use the loop function

Cheers in advance

Luke..

like image 508
Luke T Avatar asked Jan 10 '23 04:01

Luke T


2 Answers

The best way to deal with dates is not to reinvent the wheel. Batch/CMD has no concept of dates, and so to walk through calendar dates would require implementing it yourself (including month lengths, leap year checking, etc.).

For this task, I suggest using a scripting language, like PowerShell. This script, daterange.ps1, generates a list of dates (inclusive) between the two dates specified.

param(
  [String]
  $DateStart,

  [String]
  $DateFinish
)


Function ParseDateStr {
  param(
    [String]
    $s
  )
  return Get-Date `
           -Month $s.substring(0,2) `
           -Day $s.substring(2,2) `
           -Year ('20'+$s.substring(4,2)) `
           -Hour 0 -Minute 0 -Second 0
}

$start = ( ParseDateStr $DateStart )
$finish = ( ParseDateStr $DateFinish )

$delta = New-TimeSpan -Days 1

for ($d = $start; $d -le $finish; $d +=$delta) {
    Write-Host $d.toString("MMddyy")
}

It could be used within a batch file, like:

@ECHO OFF
SETLOCAL

SET /P STARTDATE=Starting date: 
SET /P ENDDATE=Ending date: 

FOR /F %%d IN ('powershell -NoProfile -ExecutionPolicy Bypass -File daterange.ps1 %STARTDATE% %ENDDATE%') DO (
    @ECHO %%d
)

The loop variable %d will a correctly formatted date for each day in the range.

For example:

C:\temp>sol
Starting date: 022716
Ending date: 030116
022716
022816
022916
030116
like image 96
mojo Avatar answered Jan 16 '23 00:01

mojo


@ECHO OFF
SETLOCAL
:: Get dates
SET /p "startdate=Start date "
SET /p "enddate=End date "
CALL :universal startdateu %startdate%
CALL :universal enddateu %enddate%
:Loop
CALL :nextdate
ECHO Use DATE %selected%
IF "%enddateu%" geq "%startdateu%" GOTO Loop

GOTO :EOF

:nextdate
:: Rebuild "startdateu" in selected format-to-use (MMDDYY programmed)
SET "selected=%startdateu:~2,2%%startdateu:~4,2%%startdateu:~0,2%"
:: bump startdateu
SET /a startdateu=1%startdateu% + 1
IF 1%startdateu:~-2% leq 128 GOTO noteom
IF "%startdateu:~-2%"=="32" GOTO eom
:: short months
IF "%startdateu:~-2%"=="31" FOR %%a IN (04 06 09 11) DO IF "%%a"=="%startdateu:~3,2%" SET /a startdateu+=1&GOTO eom
:: not-Feb
IF "%startdateu:~3,2%" neq "02" GOTO noteom
IF "%startdateu:~-2%"=="30" SET /a startdateu+=2&GOTO eom
:: Only allow Feb 29 if leap year
SET /a startdate=%startdateu:~0,3% %% 4
IF %startdate%==0 GOTO noteom
SET /a startdateu+=3
:eom
SET /a startdateu+=69
IF "%startdateu:~3,2%" equ "13" SET /a startdateu+=8800
:noteom
SET "startdateu=%startdateu:~1%"
GOTO :eof

:: Convert to universal (YYMMDD) format - details depend on desired convention (MMDDYY programmed)
:universal
SET %1=%~2
CALL SET "%1=%%%1:~4,2%%%%%1:~0,2%%%%%1:~2,2%%"
GOTO :eof

Here's a way of producing a list of such dates - you don't apparently specify what format you want to supply to your reporting routine, so I'll leave the tinkering to you.

In essence, each of the input dates is converted to yymmdd format; the selected date is converted back ready for display and the universal-format date in startdateu is incremented. In order to allow the mathematical capabilities to be used with leading-0 years, 1 is strung before the date before and stripped off after the increment.

If the new daynumber is 28 or less, then it's not eom
If the new daynumber becomes 32, then it's eom
If the new daynumber becomes 31, then for short months add an extra 1 making 32 and it's eom
If it's not February, we're not at eom
Otherwise, if new daynumber is 30, add 2 making 32 and it's eom
Else it's not eom if the yearnumber is divisible by 4 Otherwise the new day number must be 29 so add 3 making 32 and it's eom

At eom, add 69 to the new daynumber 69 which will increment the month and set day=1.
If the resultant monthnumber is 13, add 8800 to increment the year and make month =01.

like image 41
Magoo Avatar answered Jan 16 '23 02:01

Magoo