I am trying to use For Loops that will start and end based on values entered by user in batch. However, when using the user input variables, the loop fail to work. May I know what have I done wrong and how do I correct it? Thanks in advance!
P.S. I have tried both ! and %
Here's the my source code which shows the for loop which is having problem:
setlocal EnableDelayedExpansion
set /p sy="Enter start year (e.g. 2020): "
set /p sm="Enter start month (e.g. 08): "
set /p ey="Enter end year (e.g. 2020): "
set /p em="Enter end month (e.g. 08): "
echo ***LIST OF MISSING FILES FROM %sm% %sy% to %em% %ey%*** > checkFile_%SUBFILENAME%.txt
for /L %%y in (%sy%,1,%ey%) do (
for /L %%m in (1,1,%maxMonth%) do (
if %%m leq 9 set month=0%%m
if %%m gtr 9 set month=%%m
if %%y equ %sy% if !month! leq %sm% (
goto :continue
)
if %%y equ %ey% if !month! equ %em% (
goto :breakloop
) else (
call :DaysOfMonth %%y !month!
set maxDay=!errorlevel!
echo Days Of Month !month!: !maxDay!
Here's the full script:
setlocal EnableDelayedExpansion
set maxHour=23
set maxMonth=12
set missing=0
set /p sy="Enter start year (e.g. 2020): "
set /p sm="Enter start month (e.g. 08): "
set /p ey="Enter end year (e.g. 2020): "
set /p em="Enter end month (e.g. 08): "
set CUR_YYYY=%date:~10,4%
set CUR_MM=%date:~4,2%
set CUR_DD=%date:~7,2%
set CUR_HH=%time:~0,2%
if %CUR_HH% lss 10 (set CUR_HH=0%time:~1,1%)
set CUR_NN=%time:~3,2%
set CUR_SS=%time:~6,2%
set CUR_MS=%time:~9,2%
set SUBFILENAME=%CUR_YYYY%%CUR_MM%%CUR_DD%-%CUR_HH%%CUR_NN%%CUR_SS%
echo ***LIST OF MISSING FILES FROM %sm% %sy% to %em% %ey%*** > checkFile_%SUBFILENAME%.txt
for /L %%y in (%sy%,1,%ey%) do (
for /L %%m in (1,1,%maxMonth%) do (
if %%m leq 9 set month=0%%m
if %%m gtr 9 set month=%%m
if %%y equ %sy% if !month! leq %sm% (
goto :continue
)
if %%y equ %ey% if !month! equ %em% (
goto :breakloop
) else (
call :DaysOfMonth %%y !month!
set maxDay=!errorlevel!
echo Days Of Month !month!: !maxDay!
set missingMonth=0
for /L %%d in (1,1,!maxDay!) do (
if %%d leq 9 set day=0%%d
if %%d gtr 9 set day=%%d
for /f "tokens=1*" %%i in ('PowerShell -Command "& {Get-Date "!day!/!month!/%%y" -format "ddd_MMM_dd"}"') do (
for /L %%f in (0,1,!maxHour!) do (
if %%f leq 9 set hour=0%%f
if %%f gtr 9 set hour=%%f
if not exist "%%i_!hour!_00_00_%%y.enf" (
echo Missing: %%i_!hour!_00_00_%%y.enf
echo Missing: %%i_!hour!_00_00_%%y.enf >> checkFile_%SUBFILENAME%.txt
set /A missing = missing+1
set /A missingMonth = missingMonth+1
)
)
)
)
)
echo NUMBER OF FILES MISSING FOR !month!: !missingMonth!
echo ***NUMBER OF FILES MISSING FOR !month!: !missingMonth!*** >> checkFile_%SUBFILENAME%.txt
echo. >> checkFile_%SUBFILENAME%.txt
:continue
)
)
:breakloop
echo TOTAL NUMBER OF FILES MISSING FROM %sm% %sy% to %em% %ey%: %missing%
echo. >> checkFile_%SUBFILENAME%.txt
echo ***TOTAL NUMBER OF FILES MISSING FROM %sm% %sy% to %em% %ey%*** >> checkFile_%SUBFILENAME%.txt
pause
:DaysOfMonth Year Month
setlocal DisableDelayedExpansion
set /a "yy = %~1, mm = 100%~2 %% 100"
set /a "n = 30 + !(((mm & 9) + 6) %% 7) + !(mm ^ 2) * (!(yy %% 4) - !(yy %% 100) + !(yy %% 400) - 2)"
endlocal &exit /b %n%
I'm getting the error "1JDa:~1JDa:~1 was unexpected at this time." when trying to run the following .cmd through the command line:
Call :GetDateTime Year Month Day
Call :SubtractDate %Year% %Month% %Day% -1 Ret
SET mes=%Ret:~0,2%
SET dia=%Ret:~3,2%
SET ano=%Ret:~6,4%
:SubtractDate Year Month Day <+/-Days> Ret
::Adapted from DosTips Functions::
setlocal & set a=%4
set "yy=%~1"&set "mm=%~2"&set "dd=%~3"
set /a "yy=10000%yy% %%10000,mm=100%mm% %% 100,dd=100%dd% %% 100"
if %yy% LSS 100 set /a yy+=2000 &rem Adds 2000 to two digit years
set /a JD=dd-32075+1461*(yy+4800+(mm-14)/12)/4+367*(mm-2-(mm-14)/12*12)/12-3*((yy+4900+(mm-14)/12)/100)/4
if %a:~0,1% equ + (set /a JD=%JD%+%a:~1%) else set /a JD=%JD%-%a:~1%
set /a L= %JD%+68569, N= 4*L/146097, L= L-(146097*N+3)/4, I= 4000*(L+1)/1461001
set /a L= L-1461*I/4+31, J= 80*L/2447, K= L-2447*J/80, L= J/11
set /a J= J+2-12*L, I= 100*(N-49)+I+L
set /a YYYY= I, MM=100+J, DD=100+K
set MM=%MM:~-2% & set DD=%DD:~-2%
set ret=%MM: =%/%DD: =%/%YYYY: =%
endlocal & set %~5=%ret%
:GetDateTime Year Month Day Hour Minute Second
#echo off & setlocal
for /f "tokens=2 delims==" %%a in ('wmic OS Get localdatetime /value') do set "dt=%%a"
set "YY=%dt:~2,2%" & set "YYYY=%dt:~0,4%" & set "MM=%dt:~4,2%" & set "DD=%dt:~6,2%"
set "HH=%dt:~8,2%" & set "Min=%dt:~10,2%" & set "Sec=%dt:~12,2%"
( ENDLOCAL
IF "%~1" NEQ "" set "%~1=%YYYY%"
IF "%~2" NEQ "" set "%~2=%MM%"
IF "%~3" NEQ "" set "%~3=%DD%"
IF "%~4" NEQ "" set "%~4=%HH%"
IF "%~5" NEQ "" set "%~5=%Min%"
IF "%~6" NEQ "" set "%~6=%Sec%"
)
exit /b
I don't have experience with these scripts, so maybe I've got a basic error? Thank you.
You are simply missing some exit after you call your subroutines and get the result. Add exit /b after the SET ano=%Ret:~6,4% line and you will be fine.
I am new to command scripting.
I need to check if multiple files are available in a directory.
I am able to check the files with the exact names using below script but need direction when the files are with date in the name as shown. the date is as of yesterday, yyyymmdd.
example: metric_cal_enc.20120415.txt, reg_nyc_enc.20120415.txt, ferm_det_enc.20120415.txt
#echo off
echo Check if files are existent in inbound directory
for /f "tokens=*" %%a in (test.txt) do (
echo Checking path %%a
if EXIST %%a (
echo Exists!
) else (
echo Does Not Exist %%a >> log.txt
)
)
Assuming, for lack of an example, that your test.txt file contains
metric_cal_enc.txt
reg_nyc_enc.txt
ferm_det_enc.txt
and you have %yesterday% set up to yesterday's date (don't use a variable %date%)
if EXIST %%~na.%yesterday%%%~xa (
is the only change you'd need.
And here is how you can get Yesterdays date:
#echo off
setlocal
Call :GetDateTime Year Month Day
Echo %Year% %Month% %Day%
Call :SubtractDate %Year% %Month% %Day% -1 Ret
echo %Ret%
exit /b
:SubtractDate Year Month Day <+/-Days> Ret
::Adapted from DosTips Functions::
setlocal & set a=%4
set "yy=%~1"&set "mm=%~2"&set "dd=%~3"
set /a "yy=10000%yy% %%10000,mm=100%mm% %% 100,dd=100%dd% %% 100"
if %yy% LSS 100 set /a yy+=2000 &rem Adds 2000 to two digit years
set /a JD=dd-32075+1461*(yy+4800+(mm-14)/12)/4+367*(mm-2-(mm-14)/12*12)/12-3*((yy+4900+(mm-14)/12)/100)/4
if %a:~0,1% equ + (set /a JD=%JD%+%a:~1%) else set /a JD=%JD%-%a:~1%
set /a L= %JD%+68569, N= 4*L/146097, L= L-(146097*N+3)/4, I= 4000*(L+1)/1461001
set /a L= L-1461*I/4+31, J= 80*L/2447, K= L-2447*J/80, L= J/11
set /a J= J+2-12*L, I= 100*(N-49)+I+L
set /a YYYY= I, MM=100+J, DD=100+K
set MM=%MM:~-2% & set DD=%DD:~-2%
set ret=%YYYY: =%%MM: =%%DD: =%
endlocal & set %~5=%ret%
exit /b
:GetDateTime Year Month Day Hour Minute Second
#echo off & setlocal
for /f "tokens=2 delims==" %%a in ('wmic OS Get localdatetime /value') do set "dt=%%a"
set "YY=%dt:~2,2%" & set "YYYY=%dt:~0,4%" & set "MM=%dt:~4,2%" & set "DD=%dt:~6,2%"
set "HH=%dt:~8,2%" & set "Min=%dt:~10,2%" & set "Sec=%dt:~12,2%"
( ENDLOCAL
IF "%~1" NEQ "" set "%~1=%YYYY%"
IF "%~2" NEQ "" set "%~2=%MM%"
IF "%~3" NEQ "" set "%~3=%DD%"
IF "%~4" NEQ "" set "%~4=%HH%"
IF "%~5" NEQ "" set "%~5=%Min%"
IF "%~6" NEQ "" set "%~6=%Sec%"
)
exit /b
I am making a program and it has a change log. The programs change log must say the version and then show how many days ago it was. So it should say:
[2013/03/19, 2 days ago]
I used this code:
set versionreleasedate1=2013/03/17
set /a verionday=%versionreleasedate1%-%date%
echo Version: 1.0 BETA [2013/03/19, %verionday% days ago]
but I know that the date it is dividing because cmd thinks that the \ symbol is devide buy I want that a little sepricator for the date.
So it would work like this
set /a var1=2013/03/17-%date% (todays date)
and echo how many days ago. Any help would be awesome thanks.
This works for my machine, and hopefully for yours:
#echo off &setlocal
set "versionreleasedate1=2013/03/17"
set "versionreleasetime1=00:00:00,00"
call :GetInternational
call :GetSecs "%versionreleasedate1%" "%versionreleasetime1%" startsec
call :GetSecs "%date%" "%time%" stopsec
set /a versionday=(%stopsec%-%startsec%)/86400
echo Version: 1.0 BETA [%versionreleasedate1%, %versionday% days ago]
goto :eof
:GetInternational
:: Sets a bundle of variables by reading the registry settings
for /f "tokens=1,2*" %%a in (' reg query "HKCU\Control Panel\International"^|find "REG_SZ" ') do set "%%a=%%c"
goto :eof
:GetSecs "dateIn" "timeIn" secondsOut
:: Output: Seconds elapsed since 1th Jan. 1970 00:00:00
:: http://www.dostips.com/forum/viewtopic.php?p=6450#p6450
setlocal
set "dateIn=%~1"
for /f "tokens=2" %%i in ("%dateIn%") do set "dateIn=%%i"
for /f "tokens=1-3 delims=%sDate%" %%a in ("%dateIn%") do (
if %iDate%==0 set /a mm=100%%a%%100,dd=100%%b%%100,yy=10000%%c%%10000
if %iDate%==1 set /a dd=100%%a%%100,mm=100%%b%%100,yy=10000%%c%%10000
if %iDate%==2 set /a yy=10000%%a%%10000,mm=100%%b%%100,dd=100%%c%%100
)
for /f "tokens=1-3 delims=%sTime%%sDecimal% " %%a in ("%~2") do (
set "hh=%%a"
set "nn=%%b"
set "ss=%%c"
)
if 1%hh% lss 20 set hh=0%hh%
if "%nn:~2,1%" equ "p" if "%hh%" neq "12" (set "hh=1%hh%" &set /a hh-=88)
if "%nn:~2,1%" equ "a" if "%hh%" equ "12" set "hh=00"
if "%nn:~2,1%" geq "a" set "nn=%nn:~0,2%"
set /a hh=100%hh%%%100,nn=100%nn%%%100,ss=100%ss%%%100
set /a z=14-mm,z/=12,y=yy+4800-z,m=mm+12*z-3,j=153*m+2,j=j/5+dd+y*365+y/4-y/100+y/400-2472633,j=j*86400+hh*3600+nn*60+ss
endlocal &set "%~3=%j%"
goto :eof
endlocal
%versionreleasedate1% & %versionreleasetime1% must be in the same format like %date% & %time% on your machine!
Is there a way to split the %date% in a batch file (say, in 3 environment variables), but regardless of Regional Settings? Today's date would be 3/13/2013 for US, but with my Regional Settings it is 13.3.2013 - the delimiter is changed and the order as well.
Four years have passed, but this question doesn't get old, and I think now there's a slightly better answer than using wmic (on win7 onwards).
for /F "tokens=1,2,3 delims=_" %%i in ('PowerShell -Command "& {Get-Date -format "MM_dd_yyyy"}"') do (
set MONTH=%%i
set DAY=%%j
set YEAR=%%k
)
echo %MONTH% %DAY% %YEAR%
With powershell Get-Date you can fine-tune the format you want (short,long, numbers,names,etc..). In this example "MM_dd_yyyy" will get you a numeric date with leading zeros in case of single digit months or days
You can do it using wmic (but WMIC isn't included with XP Home):
#ECHO OFF
:: Check WMIC is available
WMIC.EXE Alias /? >NUL 2>&1 || GOTO s_error
:: Use WMIC to retrieve date and time
FOR /F "skip=1 tokens=1-6" %%G IN ('WMIC Path Win32_LocalTime Get Day^,Hour^,Minute^,Month^,Second^,Year /Format:table') DO (
IF "%%~L"=="" goto s_done
Set _yyyy=%%L
Set _mm=00%%J
Set _dd=00%%G
Set _hour=00%%H
SET _minute=00%%I
)
:s_done
:: Pad digits with leading zeros
Set _mm=%_mm:~-2%
Set _dd=%_dd:~-2%
Set _hour=%_hour:~-2%
Set _minute=%_minute:~-2%
:: Display the date/time in ISO 8601 format:
Set _isodate=%_yyyy%-%_mm%-%_dd% %_hour%:%_minute%
Echo %_isodate%
GOTO:EOF
:s_error
Echo GetDate.cmd
Echo Displays date and time independent of OS Locale, Language or date format.
Echo Requires Windows XP Professional, Vista or Windows 7
Echo.
Echo Returns 6 environment variables containing isodate,Year,Month,Day,hour and minute.
And you can do it by parsing the date command to lookup what the current date format is required to be.
The first link indicates you might need to edit the code in the second, on Win7, to handle a few extra wrinkles around short date/long date form.
I've reworked sashoalm's version to take care of the suppressed-leading-zero situation:
#Echo OFF
SETLOCAL
If "%Date%A" LSS "A" (Set _NumTok=1-3) Else (Set _NumTok=2-4)
:: Default Delimiter of TAB and Space are used
For /F "TOKENS=2*" %%A In ('REG QUERY "HKCU\Control Panel\International" /v iDate') Do Set _iDate=%%B
For /F "TOKENS=2*" %%A In ('REG QUERY "HKCU\Control Panel\International" /v sDate') Do Set _sDate=%%B
IF %_iDate%==0 For /F "TOKENS=%_NumTok% DELIMS=%_sdate% " %%F In ("%Date%") Do CALL :procdate %%H %%F %%G
IF %_iDate%==1 For /F "TOKENS=%_NumTok% DELIMS=%_sdate% " %%F In ("%Date%") Do CALL :procdate %%H %%G %%F
IF %_iDate%==2 For /F "TOKENS=%_NumTok% DELIMS=%_sdate% " %%F In ("%Date%") Do CALL :procdate %%F %%G %%H
endlocal&SET YYYYMMDD=%YYYYMMDD%
GOTO :eof
::
:: Date elements are supplied in Y,M,D order but may have a leading zero
::
:procdate
:: if single-digit day then 1%3 will be <100 else 2-digit
IF 1%3 LSS 100 (SET YYYYMMDD=0%3) ELSE (SET YYYYMMDD=%3)
:: if single-digit month then 1%2 will be <100 else 2-digit
IF 1%2 LSS 100 (SET YYYYMMDD=0%2%YYYYMMDD%) ELSE (SET YYYYMMDD=%2%YYYYMMDD%)
:: Similarly for the year - I've never seen a single-digit year
IF 1%1 LSS 100 (SET YYYYMMDD=20%YYYYMMDD%) ELSE (SET YYYYMMDD=%1%YYYYMMDD%)
GOTO :eof
returning YYYYMMDD - substring at your will.
Interestingly, inserting after SETLOCAL
IF NOT "%1"=="" set date=%1
will allow any date in the local sequence (without the dayname) to be decoded to YYYYMMDD (but be careful that 19xx dates provided with the yy form will appear as 20xx - easily compensated-for if you find it necessary)
I have an additional suggestion with robocopy:
#echo off &setlocal enabledelayedexpansion
set "day="
for /f "tokens=3,4,8skip=4delims=: " %%i in ('robocopy') do if not defined day (
set "month=%%i"
set "day=0%%j"
set "year=%%k"
)
set /a cnt=0
for %%i in (Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec) do (
set /a cnt+=1
if "%%i"=="%month%" set "month=0!cnt!"
)
set "day=%day:~-2%"
set "month=%month:~-2%"
echo.%day%.%month%.%year%
endlocal
Try this: Set_date.cm
#echo off&goto :start
:Set_Date DateEnv [Date] or [/p="Prompt for Date: "] [/r]
echo.
echo.Usage: Set_Date.cmd DateEnv [Date] or [/p="Prompt for Date: "]
echo.Populates date variables labeled: 'DateEnv_???', see below
echo.Accepted date formats:
echo. m-d-y, m/d/y, yyyymmdd, dd-Mon-yy or 7 digit julian date
echo. If "%%date%%" is passed as the 2nd arg it will be interpreted
echo. according to the current regional date setting ie. day dd/mm/yyyy
echo. If /r is passed then the date contained in the DateEnv variable
echo. and/or the [Date] argument will be interpreted in regional format
echo. The /r option should be placed at the end of the list if used
echo. The /r option should only be used if date input is not included
echo. in one of the default listed formats or unexpected consequences...
echo.
echo.DateEnv, if passed alone may be a valid defined date variable or if
echo.undefined then todays date will be used to populate the variables
echo.Two digit years input 'XX' are interpreted as the year '20XX'
echo.Valid dates must be in the year 1601 or greater for the validity check
echo.Returns 0 in errorlevel if the date is valid, else non-zero
echo.
echo.If DateEnv is valid or if [Date] is passed DateEnv_??? will be set to:
echo.DateEnv_mdy will be set to mm-dd-yyyy
echo.DateEnv_ymd will be set to yyyymmdd
echo.DateEnv_y.m.d will be set to yyyy.mm.dd
echo.DateEnv_dte will be set to the current active regional date format
echo.DateEnv_jul will be set to the 7 digit Julian date
echo.DateEnv_dow will be set to day of week, ie. Monday, Tuesday, etc.
echo.DateEnv_vrb will be set to Verbose Date, ie. Saturday, August 20th, 2011
echo.DateEnv_dd will be set to the 2 digit day
echo.DateEnv_mm will be set to the 2 digit month
echo.DateEnv_yyyy will be set to the 4 digit year
echo.DateEnv_month will be set to the month, ie. February or December
echo.DateEnv_mon will be set to the 3 letter month, ie. Jan or Aug
echo.
echo.DateEnv itself will not be changed regardless if its a valid date or not
echo.Also formats yyyymmdd or 7 digit julian date input to desired output
echo.Example: Set_Date today "%%date%%" or Set_Date newyear99 01-Jan-99
echo.
echo.Finally:
echo.If DateEnv is not defined and there is no second argument then %%date%% in
echo.the current regional format will be used to populate the variables
echo.If /p is passed as 2nd argument then quoted 3rd argument will prompt for date
echo.
echo.Examples:
echo. set "AprilsFools=4/1/1"
echo. set_date AprilFools
echo. echo Aprils fools date for 2001 in Julian format is: %%AprilFools_jul%%
echo. echo Aprils fools date in 2001 was on a %AprilFools_dow% ^(Sunday^)
echo. Set_Date birthday /p="Enter your birth date: "
echo. ECHO You were born on a %%birthday_dow%%
echo. set "today="
echo. Set_Date today
echo. echo today is %%today_dte%% or %%today_jul%% in Julian format
echo.
echo.If the '/p' option is used then the _GetString.cmd routine must be in the PATH
echo. or else set/p routine will ask for date with no validity checking
exit /b 1
:start
set "jul="&set "Format="&set "Sep="&set "reg="
if "%~1"=="" exit /b 255
if /i "%~1" equ "/?" goto :Set_Date Syntax
SetLocal EnableDelayedExpansion
echo %*|find /i "/r">nul
if %errorlevel% equ 0 set/a reg=1&if /i "%~1" equ "/r" shift
if defined %~1 (call set jul=%%%~1%%) else (
if "%~2"=="" set "jul=%date%"
)
if not "%~2"=="" (
if /i "%~2" neq "/r" (
set "jul=%~2"&set "args=%~3"
)
) else (if not defined %~1 set/a reg=1)
call :RegDateFmt Format Separator yy mm dd jul
if %errorlevel% neq 0 goto :BadDate
if /i "%~2" equ "%date%" set/a reg=1
if defined reg (
set "jul=!mm!-!dd!-!yy!"
)
if /i "%jul%" equ "/p" (
call :_GetString.cmd "%args%" jul /d
if !errorlevel! gtr 0 goto :BadDate
) else if /i "%jul:~0,1%" gtr "9" (
if defined args set "jul=%jul% %args%"
set "jul=!jul:* =!"
) else if /i "%jul:~3,1%" gtr "9" (
set "Mon=%jul:~3,3%"
call :month_convert Mon
if !errorlevel! gtr 0 goto :BadDate
set "jul=!Mon!-%jul:~0,2%-%jul:~-2%"
)
set mdy=%jul:/=%
set mdy=%mdy:-=%
if /i %mdy% equ %jul% (
call :strlen %mdy%
if /i !errorlevel! equ 7 (
call :date_cvt mdy /j
) else (call :date_cvt jul /j)
) else (call :date_cvt jul /j)
if /i %errorlevel% equ 0 (
set/a mdy=%jul%
set/a dow=%jul% %% 7&call :set_day dow
) else (goto :BadDate)
call :date_cvt mdy /j
set "vrb=%mdy%"
call :format_verbose vrb dow month
set/a ymd=%errorlevel%
set "mon=%month:~0,3%"
set/a dte=%ymd%
call :setRegDate dte Format Separator dow mon
if /i %errorlevel% gtr 0 goto :BadDate
Endlocal&(
call set "%~1_mdy=%mdy%"&call set "%~1_ymd=%ymd%"&call set "%~1_jul=%jul%"
call set "%~1_vrb=%vrb%"&call set "%~1_dow=%dow%"&call set "%~1_dd=%ymd:~-2%"
call set "%~1_mm=%mdy:~0,2%"&call set "%~1_yyyy=%ymd:~0,4%"
call set "%~1_mon=%mon%"&call set "%~1_yy=%ymd:~2,2%"&call set "%~1_dte=%dte%"
call set "%~1_y.m.d=%ymd:~0,4%.%mdy:~0,2%.%ymd:~-2%"&call set "%~1_month=%month%"
exit /b 0
)
:BadDate
Endlocal&(
call set "%~1_mdy="&call set "%~1_ymd="&call set "%~1_dte="&call set "%~1_jul="
call set "%~1_vrb="&call set "%~1_dow="&call set "%~1_vrb="&call set "%~1_y.m.d="
call set "%~1_month="
)&exit /b %errorlevel%
::**********************************::
::*******|| SUBROUTINES ||*******::
::**********************************::
:set_day
SetLocal&call set/a tkn=%%%~1%%+1
for /f "tokens=%tkn%" %%a in ("Monday Tuesday Wednesday Thursday Friday Saturday Sunday") do (
set "dayofwk=%%a"
)
EndLocal&call set %~1=%dayofwk%&exit /b 1
:Date_Cvt DateEnv [/Julian] Date_env is converted
if "%~1"=="" exit /b 1
SetLocal&call set "mdy=%%%~1%%"
set ech=&set "arg="
if not "%~2"=="" (set arg=%~2&set arg=!arg:~0,2!)
xcopy /d:%mdy% /h /l "%~f0" "%~f0\">nul 2>&1
if /i %errorlevel% equ 0 (
for /f "tokens=1-3 delims=/- " %%a in ("%mdy%") do (
set m=%%a&set d=%%b&set "y=%%c"
if /i 1!m! lss 20 set "m=0!m!"
if /i 1!d! lss 20 set "d=0!d!"
if /i 1!y! lss 20 set "y=0!y!"
if /i !y! lss 80 (set y=20!y!) else (if !y! lss 100 set y=19!y!)
set "mdy=!m!-!d!-!y!"
)
) else (
set /a rc=1
for /f "tokens=1-3 delims=0123456789" %%a in ("%mdy%") do set "rc=%%a"
if /i !rc! neq 1 set /a err=2&goto :end
call :strlen %mdy%
if /i !errorlevel! gtr 8 set /a err=3&goto :end
)
set "mdy=%mdy:/=-%"
set "ymd=%mdy:-=%"
if %ymd%==%mdy% (
call :strlen %ymd%
set /a err=!errorlevel!
if /i !err! equ 7 if /i "%arg%" equ "/j" (
call :gdate %ymd%
set /a ymd=!errorlevel!
set /a err=8&set "arg="
)
if /i !err! neq 8 goto :end
set mdy=!ymd:~4,2!-!ymd:~6,2!-!ymd:~0,4!&set "ech=!mdy!"
) else (
set ymd=%ymd:~4,4%%ymd:~0,4%&set "ech=!ymd!"
)
xcopy /d:%mdy% /h /l "%~f0" "%~f0\">nul 2>&1
set /a err=%errorlevel%
if /i %err% neq 0 (set ech=)
if /i %err% equ 0 if /i "%arg%" equ "/j" (
call :jdate %ymd%
set /a ech=!errorlevel!
)
:end
EndLocal&call set "%~1=%ech%"&exit /b %err%
:Strlen Returns length of string in errorlevel
setlocal&set "#=%*"
if not defined # exit /b 0
set/a len=0
:loop
set/a len+=1
set "#=!#:~1!"&if not defined # endlocal&exit/b %len%
goto :loop
:jdate
SetLocal
set "yyyymmdd=%~1"
set "yyyy=%yyyymmdd:~0,4%"
set "mm=%yyyymmdd:~4,2%"
set "dd=%yyyymmdd:~6,2%"
if %mm:~0,1% equ 0 set "mm=%mm:~1%"
if %dd:~0,1% equ 0 set "dd=%dd:~1%"
set /a Month1=(%mm%-14)/12
set /a Year1=%yyyy%+4800
set /a JDate=1461*(%Year1%+%Month1%)/4+367*(%mm%-2-12*%Month1%)^
/12-(3*((%Year1%+%Month1%+100)/100))/4+%dd%-32075
EndLocal&exit /b %JDate%
:gdate
SetLocal
set /a p = %1 + 68569
set /a q = 4 * %p% / 146097
set /a r = %p% - ( 146097 * %q% +3 ) / 4
set /a s = 4000 * ( %r% + 1 ) / 1461001
set /a t = %r% - 1461 * %s% / 4 + 31
set /a u = 80 * %t% / 2447
set /a v = %u% / 11
set /a GYear = 100 * ( %q% - 49 ) + %s% + %v%
set /a GMonth = %u% + 2 - 12 * %v%
set /a GDay = %t% - 2447 * %u% / 80
if /i 1%GMonth% lss 20 set "GMonth=0%GMonth%"
if /i 1%GDay% lss 20 set "GDay=0%GDay%"
set "GDate=%GYear%%GMonth%%GDay%"
EndLocal&exit /b %GDate%
:Format_Verbose M/D/Y dayofweek to verbose date
SetLocal&call set "dte=%%%~1%%"
set "dow=%%%~2%%"
set "st="
set "day=%dte:~3,2%"
set "mon=%dte:~0,2%"
set "year=%dte:~6,4%"
set "ymd=%year%%mon%%day%"
set "dy=%day:~1%"
if %day:~0,1% equ 0 set "day=%day:~1%"
if %mon:~0,1% equ 0 set "mon=%mon:~1%"
set months=January February March April May June^
July August September October November December
for /f "tokens=%mon%" %%a in ("%months%") do set "month=%%a"
if /i %dy% equ 0 set "st=th"
if /i %dy% gtr 3 set "st=th"
if /i %day% geq 11 if /i %day% leq 13 set "st=th"
if defined st goto :end
set/a rst=%day% %% 10
for /f "tokens=%rst%" %%s in ("st nd rd") do set "st=%%s"
:end
set "dow=%dow%, %month% %day%%st%, %year%"
EndLocal&call set %~1=%dow%&call set %~3=%month%&exit /b %ymd%
:_GetString.cmd
set p0=%0&set "p0=!p0:~1!"
if not exist _GetString.cmd (
call :checkpath %p0%
if !errorlevel! neq 0 (
set/p %~2="%~1"
exit/b 0
)
)
call _GetString.cmd "%~1" %~2 %~3
exit/b %errorlevel%
:checkpath
if exist "%~$PATH:1" exit/b 0
exit/b 1
:RegDateFmt Format Separator y m d dte
if "%~2"=="" exit/b 1
setlocal EnabledelayedExpansion
set "Day="&set "Mon="&set "dte="
if not "%~6"=="" set "dte=!%~6!"
if not defined dte set "dte=%date%"
for /f "tokens=2 delims=:" %%A in ('date^<nul') do set Format=%%A&goto :next
:next
set "Format=%Format: =%"
for %%A in (/ - . ,) do (
echo %Format%|find "%%A">nul&if !errorlevel! equ 0 set "Separator=%%A"
)
if /i %Format:~0,1% gtr 9 set "Day=Day "
for /f "skip=1 tokens=2-4 delims=(-)" %%a in ('date^<nul') do (
set "Format=%Day%%%a%Separator%%%b%Separator%%%c"
for /f "tokens=1-3 delims=.-/ " %%d in ("%dte:* =%") do (
set %%a=%%d&set %%b=%%e&set "%%c=%%f"
echo !yy:~3!|find "ECHO">nul
if /i "!errorlevel!" neq "0" set "Format=!Format:yy=yyyy!"
if /i "!mm:~0,1!" gtr "9" (
set "Format=!Format:mm=Mon!"
call :month_convert mm
if /i "!errorlevel!" neq "0" endlocal&exit/b 1
)
)
)
endlocal&(
call set "%~1=%Format%"
call set "%~2=%Separator%"
if not "%~3"=="" call set "%~3=%yy%"
if not "%~4"=="" call set "%~4=%mm%"
if not "%~5"=="" call set "%~5=%dd%"
)&exit/b 0
:month_convert
set "months=Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"
call set "month=%%%~1%%"
set/a mnum=0
for %%m in (%months%) do set/a mnum+=1&if /i %month% equ %%m call set "%~1=!mnum!"&exit /b 0
exit/b 1
:setRegDate dte format sep dow mon
setlocal EnableDelayedExpansion
if /i "%~5"=="" exit/b 1
set mon=!%~5!&set dow=!%~4!&set "dow=!dow:~0,3! "
set sep=!%~3!&set "format=!%~2!"&set "dte=!%~1!"
set yyyy=%dte:~0,4%&set yy=%dte:~2,2%&set mm=%dte:~4,2%&set "dd=%dte:~-2%"
set "toks=2-4"
echo %format%|find " ">nul
if %errorlevel% equ 1 set "dow="& set "toks=1-3"
for /f "tokens=%toks% delims=%sep% " %%a in ("%format%") do (
set "dte=%dow%!%%a!%sep%!%%b!%sep%!%%c!"
)
endlocal&call set "%~1=%dte%"&exit/b 0
I found this in http://forums.techguy.org/dos-other/837046-solved-date-format-bat-file.html
I've reworked it a bit to actually split it in 3 environment variables.
The downside is it needs to query the registry, probably to find out the order day, month and year.
#Echo Off
Set _Date=%date%
If "%_Date%A" LSS "A" (Set _NumTok=1-3) Else (Set _NumTok=2-4)
:: Default Delimiter of TAB and Space are used
For /F "TOKENS=2*" %%A In ('REG QUERY "HKCU\Control Panel\International" /v iDate') Do Set _iDate=%%B
For /F "TOKENS=2*" %%A In ('REG QUERY "HKCU\Control Panel\International" /v sDate') Do Set _sDate=%%B
IF %_iDate%==0 For /F "TOKENS=%_NumTok% DELIMS=%_sDate% " %%B In ("%_Date%") Do Set _fdate=%%D%%B%%C
IF %_iDate%==1 For /F "TOKENS=%_NumTok% DELIMS=%_sDate% " %%B In ("%_Date%") Do Set _fdate=%%D%%C%%B
IF %_iDate%==2 For /F "TOKENS=%_NumTok% DELIMS=%_sDate% " %%B In ("%_Date%") Do Set _fdate=%%B%%C%%D
Set _Month=%_fdate:~4,2%
Set _Day=%_fdate:~6,2%
Set _Year=%_fdate:~0,4%
Echo _Year=%_Year%
Echo _Month=%_Month%
Echo _Day=%_Day%
REG QUERY is not sufficient, if sShortDate was set to something like dd yy. Use REG ADD:
#echo off &setlocal
for /f "tokens=2*" %%a in ('reg query "HKCU\Control Panel\International" /v sShortDate^|find "REG_SZ"') do set "ssShortDate=%%b"
reg add "HKCU\Control Panel\International" /f /v sShortDate /d "dd MM yyyy" >nul
set "cdate=%date%"
reg add "HKCU\Control Panel\International" /f /v sShortDate /d "%ssShortDate%" >nul
for /f "tokens=1-3" %%i in ("%cdate%") do set "day=0%%i"&set "month=0%%j"&set "year=%%k"
set "day=%day:~-2%"
set "month=%month:~-2%"
echo.%day%.%month%.%year%
endlocal
This function should work on all regions.
Remarks:
Returns month in text format for MMM regions
#echo off
call :GetDateIntl year month day
echo/Using GetDateIntl you get: %year%-%month%-%day%
goto:eof
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:GetDateIntl yy mm dd [/A]
:: Returns the current date on any machine with regional-independent settings
:: Arguments:
:: yy = variable name for the year output
:: mm = variable name for the month output
:: dd = variable name for the day output
:: /A = OPTIONAL, removes leading 0 on days/months smaller than 10 (example: 01 becomes 1)
:: Remarks:
:: Will return month in text format in regions with MMM month
::
SETLOCAL ENABLEEXTENSIONS
if "%date%A" LSS "A" (set toks=1-3) else (set toks=2-4)
for /f "tokens=2-4 delims=(-)" %%a in ('echo:^|date') do (
for /f "tokens=%toks% delims=.-/ " %%i in ('date/t') do (
set '%%a'=%%i
set '%%b'=%%j
set '%%c'=%%k
)
)
if /I "%'yy'%"=="" set "'yy'=%'aa'%"
if /I "%'yy'%"=="" ( set "'yy'=%'jj'%" & set "'dd'=%'tt'%" )
if %'yy'% LSS 100 set 'yy'=20%'yy'%
endlocal&set %1=%'yy'%&set %4 %2=%'mm'%&set %4 %3=%'dd'%&goto :EOF
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Below there is a pure Batch solution that just use DATE command and %DATE% variable, so it works on any Windows version. To make this program really universal, just add the name of the day and month parts shown by second line of DATE command in other languages, enclosed in slashes. For example, let's suppose that in German the day part is shown as TT, so you just need to modify this value: set DayNames=/dd/tt/ in order to also use this program in German language Windows (besides all the languages that use DD for the day part).
#echo off
setlocal EnableDelayedExpansion
rem GetStdDate.bat: Get date in standard format independently of Regional Settings
rem Antonio Perez Ayala
rem Set Day and Month names shown by second line of DATE command, enclosed in slashes (add any missing language):
set DayNames=/dd/
set MonthNames=/mm/
rem Get date NAMES from second line of date COMMAND, enclosed in parentheses
for /F "skip=1 tokens=2 delims=()" %%n in ('date ^< NUL') do (
rem Separate and store date names
for /F "tokens=1-3 delims=/-.:" %%a in ("%%n") do (
set one=%%a& set two=%%b& set three=%%c
rem Get date VALUES from %date% VARIABLE
for /F "tokens=1-3 delims=/-.:" %%x in ("%date%") do (
rem Assign date values to date names
set %%a=%%x& set %%b=%%y& set %%c=%%z
)
)
)
rem Identify locale date format and assemble StdDate=YYYY/MM/DD
if "!DayNames:/%one%/=!" neq "%DayNames%" (
rem Locale format is DD/MM/YYYY
set StdDate=!%three%!/!%two%!/!%one%!
) else if "!MonthNames:/%one%/=!" neq "%MonthNames%" (
rem Locale format is MM/DD/YYYY
set StdDate=!%three%!/!%one%!/!%two%!
) else (
rem Locale format is YYYY/MM/DD
set StdDate=!%one%!/!%two%!/!%three%!
)
echo Standard date: %StdDate%
Read a locale independent YYYY-MM-DDThh:mm:ss value.
WMIC gives 20220812142505.576000+180 value and using a simple ~substring we can construct a datetime format.
#set dt=
#CALL :GETDATETIME
#echo Step1 %dt%
#timeout /T 4
#CALL :GETDATETIME
#echo Step2 %dt%
#GOTO :END
:GETDATETIME
#for /f "tokens=2 delims==" %%X in ('wmic os get localdatetime /value') do #set dt=%%X
#set dt=%dt:~0,4%-%dt:~4,2%-%dt:~6,2%T%dt:~8,2%:%dt:~10,2%:%dt:~12,2%
#GOTO :EOF
:END
#pause