Need assistance padding numerical month and day with leading 0 - date

I am working within a batch file and need to pad a single digit with a leading 0 if under 10. I have the values in environmental variables. They are month and day, I need to pad to match file structure I am working against. I am using vbscript to return a date that comes back in the following format "7/16/2009". Need it to look like "07/16/2009" and most inportantly need each item in separate EVs.
VBscript:
WScript.Echo DateAdd("d", Date, -36)
Batch:
for /F "tokens=1-3 delims=/" %%x in ('cscript //nologo get36thday.vbs') do (
SET YYYY=%%z
SET MM=%%x
SET DD=%%y)

VBScript:
dteOldDate = Now()
strNewDate = Right("00" & Month(dteOldDate), 2) & "/" & Right("00" & Day(dteOldDate), 2) & "/" & Year(dteOldDate)

For the batch script, I don't know the exact syntax but a batch script can return a specified number of characters from the right side of a string.
So, append the month after a "0" character and take the 2 right-most digits. It would probably look something similar to this:
SET MM=0%%x
SET MM=%MM:~-2%
1 become 01
5 becomes 05
10 stays 10

Here is my method of padding strings.
In this example, MYVAR will be padded to five zeroes.
SET MYVAR=00000%MYVAR%
SET MYVAR=%MYVAR:~-5%

Athough the other answers are useful if you don't know the length of the string you want to pad with zeros up front, for dates and times a simple string replacement will do.
set hour=!TIME:~0,2!
set hour=!hour: =0!
In short, if there is a space it will be replaced by a 0.

Related

How to make this powershell command work inside a loop in batch?

Trying to find the difference. But when this powershell command is inside in the findstr, it fails. On its own, it returns the correct value. Also, without the loop, it returns the correct value.
echo:!newvalue!| findstr /R "^[0123456789][0123456789]\.[0123456789]$" >nul
if errorlevel 1 (
set newvalue=
) else (
FOR /F "usebackq delims=" %%i IN (`powershell -nop -c "'{0:n1}' -f (%newvalue% - 12.0)"`) DO (SET difference=%%i)
echo %difference%
)
Can anyone figure out what I'm missing/did wrong?
Thanks in advance.
I recommend reading How does the Windows Command Interpreter (CMD.EXE) parse scripts?
Windows command processor replaces all environment variable references using syntax %variable% inside a command block starting with ( and ending with matching ) already on parsing the command line using this command block. This means the command line echo %difference% inside ELSE branch command block of the IF command is modified by cmd.exe before command IF is executed at all. %difference% is replaced by current value of environment variable difference or an empty string in case of environment variable difference is not defined somewhere above the IF condition. In latter case echo  is the command line remaining after parsing the command block and therefore shows status of command echoing instead of the string value assigned to environment variable difference in the command line above. The solution with already enabled delayed environment variable expansion is using echo !difference! in ELSE command block.
A solution for this floating point subtraction without usage of PowerShell can be seen below:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
if defined NewValue goto Validate
:UserPrompt
set /P "NewValue=Enter value between 00.0 and 99.9: "
:Validate
echo:!NewValue!| %SystemRoot%\System32\findstr.exe /R "^[0123456789][0123456789]\.[0123456789]$" >nul
if errorlevel 1 set "NewValue=" & goto UserPrompt
for /F "tokens=1,2 delims=." %%I in ("%NewValue%") do set "PreComma=%%I" & set "PostComma=%%J"
set /A Difference=1%PreComma% - 112
set "Difference=%Difference%.%PostComma%"
echo Difference is: %Difference%
endlocal
After validating that the string assigned to environment variable NewValue indeed consists of two digits, a point and one more digit as requested and expected and described at How can I do a negative regex match in batch?, the floating point number string is split up on . into pre-comma and post-comma number strings.
The pre-comma number is subtracted by 12 using an arithmetic expression. But it must be taken into account that an integer number with a leading 0 is interpreted by cmd.exe on evaluation of the arithmetic expression as octal number. That is no problem for 00 to 07. But 08 and 09 would be invalid octal numbers and so Windows command processor would use value 0 resulting in a wrong subtraction result if simply set /A Difference=PreComma - 12 would have been used in batch file. The workaround is concatenating the string 1 with the pre-comma string to a number string in range 100 to 199 and subtract 112 to get the correct result.
The post-comma value does not need to be modified and so the Difference value is determined finally with concatenating the result of the arithmetic expression with the unmodified post-comma number string.
It is possible to get the Difference value also always with two digits by inserting following additional command lines above echo Difference is: %Difference%:
if %Difference:~0,1% == - (
if %Difference:~2,1% == . set "Difference=-0%Difference:~1%"
) else (
if %Difference:~1,1% == . set "Difference=0%Difference%"
)
This solution avoids also the problem that floating point result of PowerShell is formatted according to region and language settings. For example in Germany and Austria the decimal symbol is , and not . which means the subtraction result output by PowerShell for 15.3 - 12.0 is 3,3 and not 3.3.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
echo /?
endlocal /?
findstr /?
for /?
goto /?
if /?
set /?
setlocal /?
See also single line with multiple commands using Windows batch file.
This is not technically an answer, as you've already received and accepted one a perfectly good one.
It is just to allow you to visualise a method of taking the string from your file, splitting it at the decimal point and subtracting 12, from a whole number greater or equal to 12, (see the accepted answer for whole numbers less than 12), all without 'loops' or PowerShell
#Echo Off
Rem Create a variable from the first line of your file
Set /P "newvalue="<"file.tmp"
Echo [%newvalue%]
Rem Exit if the string 'value' does not exist in '%newvalue%'
If "%newvalue%"=="%newvalue:*value=%" Exit /B
Rem ReSet the variable to everything after the string 'value'
Set "newvalue=%newvalue:*value=%"
Echo [%newvalue%]
Rem ReSet the variable to everything up to the first 'space' character
Set "newvalue=%newvalue: ="&:"%"
Echo [%newvalue%]
Rem ReSet the variable, removing the unneeded leading '=' character
Set "newvalue=%newvalue:~1%"
Echo [%newvalue%]
Rem Set a new variable to the whole number, i.e. everything up to the first '.' character
Set "whole=%newvalue:.="&:"%"
Echo [%whole%]
Rem Set a new variable to the decimal, i.e. everything after the '.' character
Set "decimal=%newvalue:*.=%"
Echo [%decimal%]
Rem Subtract 12 from the whole number
Set /A remainder=100+whole-112
Echo [%remainder%]
Rem ReJoin the variables to show the difference
Echo [%remainder%.%decimal%]
Pause
Obviously in your script proper, you'd only need:
#Echo Off
Set /P "newvalue="<"file.tmp"
If "%newvalue%"=="%newvalue:*value=%" Exit /B
Set "newvalue=%newvalue:*value=%"
Set "newvalue=%newvalue: ="&:"%"
Set "newvalue=%newvalue:~1%"
Set "whole=%newvalue:.="&:"%"
Set "decimal=%newvalue:*.=%"
Set /A remainder=100+whole-112
Echo %remainder%.%decimal%
Pause

Find multiple values in different lines using command-line | CMD

I have multiple results (Radiology, Labs, Pathology, Transcriptions) for the same patient in a file and I am only interested in getting results for a set of particular values. For example: I want to look for a radiology report on the first line and patient MRN 123456789 on the second line.
Can this be achieved using findstr? Thanks
MSH|^~\&|RADIOLOGY|1|SCM||20150303||ORU|20150303|T|2.3|20150303
PID||1111111|123456789^^^MRN_SB^||TEST^PATIENT^^^||19000101||^^||
PV1|1|E|ER^ER^1^SB||||||||||||||||||||||||||||||||||||||||||||||
ORC|RE|36543654|36543654|3003487889
#ECHO OFF
SETLOCAL
:: remove variables starting $
FOR /F "delims==" %%a In ('set $ 2^>Nul') DO SET "%%a="
SET "found="
SET "mrn=%1"
FOR /f "delims=" %%o IN (q29931949.txt) DO (
FOR /f "tokens=1-4delims=|" %%a IN ("%%o") DO (
IF DEFINED found IF "%%a"=="PID" (
SET "$2=%%o"
CALL :report "%%b" "%%c" "%%d"
)
SET "found="
IF "%%a"=="MSH" IF "%%b"=="RADIOLOGY" SET found=Y
IF "%%a"=="MSH" IF "%%c"=="RADIOLOGY" SET found=Y
IF DEFINED found SET "$1=%%o"
)
)
GOTO :EOF
:report
SET "field=%~1"
IF NOT DEFINED field GOTO :EOF
FOR /f "tokens=1delims=^^" %%r IN ("%~1") DO SET "field=%%r"
IF "%field%"=="%mrn%" FOR /F "tokens=1*delims==" %%r In ('set $') DO ECHO(%%s
shift
GOTO report
I used a file named q29931949.txt containing your data for my testing.
You don't really supply enough information to produce a result. For instance, is "MRN" a required data item?
This procedure will find two consecutive lines, the first one having "MSH" in he first column and "RADIOLOGY" in the second or third and the second line having "PID" in the first column snd either the second, third or fourth column containing the target number.
You'd run the routine using thisbatchaname 123456789
It accepts the parameter 123456789 and assigns that to mrn.
It then reads the file and assigns each line in tun to %%o, and tokenises the line on |, applying tokens 1-4 to %%a..%%d rspectively.
The main loop sets found to empty and then to Y only if the first field is MSH and the second or thid RADIOLOGY. If the found flag is set, the original line in %%o is applied to $1. Only if found is set at the start of the loop (which means that the previous line is MSH/RADIOLOGY) will the routine :report be called after $2 has the original contents of the second line assigned.
The :report routine sets field to the first parameter to see whether there are remaining parameters to process. The for then assigns the part of the field up to the first caret (^) to field. If this matches the mrn input from the command line, then the $ variables are echoed to the console (you don't say what you actually want to do with the data). Regardless, the remaining parameters are checked.
The reson for checking the second/third(/fourth) parameter is to cater for the presence or absence of data in the fields as consecutive | characters are interpreted as a single delimiter.
Find a HL7 parser library for Your programming/scripting language of choice and use it. It is not worth it to write a HL7 parser from scratch. There should be libraries available for all popular languages that You can use.
If You then have specific questions, feel free to ask again.

Comparing creation dates of files in VBScript

This may be very obvious to someone out there but I'm having a lot of trouble trying to solve a bug in VBScript. Within the script, I am running through a bunch of .zip files in a directory and processing ones whose creation date is within a specified range.
For instance, if the user enters two arguments 9/3/2014 and 9/5/2014, I only want to process zip files within that date range.
Here is the if statement I am using:
If Mid(file.NAME,len(file.NAME)-3,4) = ".zip" AND
FormatDateTime(file.DateCreated, 2) >= Wscript.Arguments(1) AND
FormatDateTime(file.DateCreated, 2) <= Wscript.Arguments(2) then
I am using the FormatDateTime function to remove the times from the file creation date. That way I should just be left with a short date (mm/dd/yyyy).
The problem I am having is that I am processing dates outside of the given range. For example if the given range is 9/3/2014 to 9/5/2014 then I also end up processing 9/30/2014 for some reason. Can anyone help solve this?
Both the return value of FormatDateTime() and the items of .Argments are Strings. A string comparison of (stringyfied) numbers will give inconvenient results:
>> WScript.Echo CStr(5 < 30)
>> WScript.Echo CStr("5" < "30")
>>
True
False
Use CDate() to convert the .Arguments to Dates and DateDiff() to compare them against the .DateCreated.
Found the source of my problem. FormatDateTime returns a string. Furthermore, the arguments I was being passed were strings also. This means I was actually doing a string comparison instead of a date comparison. The if statement should be:
If Mid(file.NAME,len(file.NAME)-3,4) = ".zip" AND
CDate(FormatDateTime(file.DateCreated, 2)) >= CDate(Wscript.Arguments(1)) AND
CDate(FormatDateTime(file.DateCreated, 2)) <= CDate(Wscript.Arguments(2)) then

Batch Script For File Date/Time

I know there are similar questions but I have not been able to make any work. I need to check a particular file date and time against the current date and time.
So far I have
Set cdate=%date%
Set filename="c:\myfile"
If Not Exist %filename% GOTO CREATEFILE
For %%f In(%filename%) DoSet filedatetime=%%~tf
If %filedatetime:~0,-9%" == "%cdate% GOTO SHOFILE
My problem is that the cdate returned has the day of the week included in the date but the file date does not. Example cdate= Thur 1/01/2015. How can I get the cdate not to have the day of the week?
Thanks
For %%f In (%filename%) Do Set "filedatetime=%%~tf"
If "%filedatetime:~0,-9%"=="%cdate:~4%" GOTO SHOFILE
Note the required space after in and do
The set "var=value" syntax ensures that any trailing spaces on the batch line are not included in the value assigned to var.
if /i "%var%"=="value" performs a comparison on variables/values containing separators (eg spaces) The '/i' make the comparison case-insensitive if required.
Your cdate can be set like this:
SET cdate=%date:~4%
This has the following output:
echo %cdate%
01/01/2015

CMD/BAT - Help determining date 36 days ago

Each night I need to do work on a folder 36 days old from the current date. I have a system that writes files to a daily structure like below. I need to keep 35days worth on the local disk and so each night I need to archive off the 36th day. Here is the kicker... There are approx 2 million files per day, so I cannot efficiently scan the whole 2009 folder and only move files older than 35 days. What I need to do is though a batch script determine the path of the folder that is 36days old and then apply my archive logic. I have scripts to determine but having trouble doing the determination to 36 days old. In a pinch I can use perl if there is not a batch way to do this. --Shawn
Folder structure is like this:
2009\07\01
2009\07\02
2009\07\03
.
.
.
2009\08\01
2009\08\02
2009\08\03
#EDIT: Helen's great answer has me 99% of the way there. My only problem is that the month and day out of the vbs is not padded with a zero which i have to deal with in the folder structure. Does anyone have an easy way to pad in a leading 0 if the day or month is less than 10?
Here is what I am doing so far:
for /F "tokens=1-3 delims=/" %%x in ('cscript //nologo get36thday.vbs') do (
SET YYYY=%%z
SET MM=%%x
SET DD=%%y)
except %MM% ends up being 7 instead of 07
The batch option is pretty wicked you will need to calculate which month it is then based of of that run a while loop counting down the days. I would high recommend perl as it would be a few lines of code
using the DateTime module from CPAN
http://search.cpan.org/dist/DateTime/lib/DateTime.pm
my $dt = DateTime->now->subtract(days => 36);
The batch way to determine the date would be too compilcated; it's much easier to use a script for that. Sorry, no Perl sample but a VBScript one:
WScript.Echo DateAdd("d", Date, -36)
You can call this script from a batch file and read the calculated date like this:
for /f %%d in ('cscript //nologo datediff.vbs') do set dt=%%d
If you came here with google like me:
To fix the leading zero's in the .vbs I add a zero in front and strip the right 2 characters.
"0" & "7" -> "07" and "0" & "14" -> "14"
OldDateCode.vbs:
OldDate = DateAdd("d", Date, -36)
DateCode = Year(OldDate) & Right("0" & Month(OldDate), 2) & Right("0" & Day(OldDate), 2)
WScript.Echo DateCode
I also wanted to keep the 1st folder of the month so I compare the last 2 digits (day) with "01"
VBS code to check for 1st day:
If Right(DateCode, 2)="01" then
WScript.Echo "The 1st:" & vbCrLf & DateCode
Else
WScript.Echo "Not the 1st:" & vbCrLf & DateCode
End If
CheckDate.bat:
#Echo Off
Set Folder=D:
for /f %%d in ('cscript //nologo OldDateCode.vbs') do set OldDateCode=%%d
If "%OldDateCode:~6,7%"=="01" (
Echo "Old Backup: %OldDateCode% 1st of the month: keeping..."
) ELSE (
Echo "Old Backup: %OldDateCode% not the 1st of the month: removing..."
RD /S /Q "%Folder%\%OldDateCode%"
)
pause
Make a folder in D:\ with the datecode of 36 days ago. Play around with the -36 and the datecodes.