English 中文(简体)
CMD脚本中的日期算术
原标题:
  • 时间:2008-12-10 08:36:43
  •  标签:

我需要编写脚本,将文件名从aDate.txt更改为bDate.txt,其中:

  • aDate is the current system date in yyyymmdd format and
  • bDate is the current system date - 1 in yyyymmdd format.

我目前拥有:

set yy=%date:~6,2%
set mm=%date:~3,2%
set dd=%date:~0,2%
if "%date:~6,1%"==" " set yy=0%yy:~1,1%
if "%date:~3,1%"==" " set mm=0%mm:~1,1%
if "%date:~0,1%"==" " set dd=0%dd:~1,1%
SET sys_date=20%yy%%mm%%dd%
ECHO %sys_date%
REM still have to do this bit properly
SET sys_date_yesterday=%sys_date%a
move %sys_date%.txt %sys_date_yesterday%.txt

但是我不知道如何进行日期-1的操作(除了冗长的减去1天的方法,如果结果是0,那么从月份减去1,设置日期为新月的最后一天,年份也是如此。)

有什么想法吗?

问题回答

你必须用困难的方法去做。我建议使用SteveGTR提供的这个解决方案。我复制下面的文本,因为我不能总是在那个网站上看到解决方案。


这是我开发的一个批处理文件,可以从当前日期减去任意天数。它接受一个命令行参数,表示要减去的天数。默认为1天(昨天):

@echo off

set yyyy=

set $tok=1-3
for /f "tokens=1 delims=.:/-, " %%u in ( date /t ) do set $d1=%%u
if "%$d1:~0,1%" GTR "9" set $tok=2-4
for /f "tokens=%$tok% delims=.:/-, " %%u in ( date /t ) do (
 for /f "skip=1 tokens=2-4 delims=/-,()." %%x in ( echo.^|date ) do (
    set %%x=%%u
    set %%y=%%v
    set %%z=%%w
    set $d1=
    set $tok=))

if "%yyyy%"=="" set yyyy=%yy%
if /I %yyyy% LSS 100 set /A yyyy=2000 + 1%yyyy% - 100

set CurDate=%mm%/%dd%/%yyyy%

set dayCnt=%1

if "%dayCnt%"=="" set dayCnt=1

REM Substract your days here
set /A dd=1%dd% - 100 - %dayCnt%
set /A mm=1%mm% - 100

:CHKDAY

if /I %dd% GTR 0 goto DONE

set /A mm=%mm% - 1

if /I %mm% GTR 0 goto ADJUSTDAY

set /A mm=12
set /A yyyy=%yyyy% - 1

:ADJUSTDAY

if %mm%==1 goto SET31
if %mm%==2 goto LEAPCHK
if %mm%==3 goto SET31
if %mm%==4 goto SET30
if %mm%==5 goto SET31
if %mm%==6 goto SET30
if %mm%==7 goto SET31
if %mm%==8 goto SET31
if %mm%==9 goto SET30
if %mm%==10 goto SET31
if %mm%==11 goto SET30
REM ** Month 12 falls through

:SET31

set /A dd=31 + %dd%

goto CHKDAY

:SET30

set /A dd=30 + %dd%

goto CHKDAY

:LEAPCHK

set /A tt=%yyyy% %% 4

if not %tt%==0 goto SET28

set /A tt=%yyyy% %% 100

if not %tt%==0 goto SET29

set /A tt=%yyyy% %% 400

if %tt%==0 goto SET29

:SET28

set /A dd=28 + %dd%

goto CHKDAY

:SET29

set /A dd=29 + %dd%

goto CHKDAY

:DONE

if /I %mm% LSS 10 set mm=0%mm%
if /I %dd% LSS 10 set dd=0%dd%

echo Date %dayCnt% day(s) before %CurDate% is %mm%/%dd%/%yyyy%

Good Luck, Steve

Easily Add or Subtract Days from a Date with a Windows Batch Script

这是我为使用批处理计算日期(加或减)提出的解决方案。根据您的需求设置变量,然后根据您的需求调整逻辑。这对我的需求非常有效,而且所有内容都包含在同一个批处理脚本中,没有太多的逻辑。

To add: You can also use this script to add a number of days to the current date by deleting the minus (-) symbol from the below batch script in the :DynamicVBSScriptBuild routine, so where you see this,-%MinusDay%, you simple remove the minus symbol to get ,%MinusDay%, on each of those lines and now the MinusDay= variable value will equal the number of days you want to add.

重要提示:似乎批处理脚本在使用MinusDays=值进行减法计算时,五个9(99999)是极限。在使用MinusDays=值进行加法计算时,六个9(999999)是极限。

批处理脚本

@ECHO ON

::// Minus days is the number of days to subtract from the CURRENT DAY i.e. 2 for minus 2 days or 99999 for minus 99999 days from when it s run
SET MinusDay=2

:: This calls the temp vbs script routine that will be used to set YYYY-MM-DD values for the subtracted days date you specify
CALL :DynamicVBSScriptBuild

FOR /F "TOKENS=*" %%A IN ( cscript//nologo "%YYYYTmpVBS%" ) DO SET YYYY=%%A
FOR /F "TOKENS=*" %%A IN ( cscript//nologo "%MMTmpVBS%" ) DO SET MM=%%A
FOR /F "TOKENS=*" %%A IN ( cscript//nologo "%DDTmpVBS%" ) DO SET DD=%%A

::// Set your web server log file path in the below variable
SET WebServerLogPath=C:WebServerLogs

::// Set web server log file name where YYYY MM DD variables are set to the values after the day numbers setup above are subtracted
SET YYYY=%YYYY%
SET MM=%MM%
SET DD=%DD%

ECHO %YYYY%%MM%%DD%
PAUSE

GOTO EOF

:DynamicVBSScriptBuild
SET YYYYTmpVBS=%temp%~tmp_yyyy.vbs
SET MMTmpVBS=%temp%~tmp_mm.vbs
SET DDTmpVBS=%temp%~tmp_dd.vbs
IF EXIST "%YYYYTmpVBS%" DEL /Q /F "%YYYYTmpVBS%"
IF EXIST "%MMTmpVBS%" DEL /Q /F "%MMTmpVBS%"
IF EXIST "%DDTmpVBS%" DEL /Q /F "%DDTmpVBS%"
ECHO dt = DateAdd("d",-%MinusDay%,date) >> "%YYYYTmpVBS%"
ECHO yyyy = Year(dt)                    >> "%YYYYTmpVBS%"
ECHO WScript.Echo yyyy                  >> "%YYYYTmpVBS%"
ECHO dt = DateAdd("d",-%MinusDay%,date) >> "%MMTmpVBS%"
ECHO mm = Right("0" ^& Month(dt),2)     >> "%MMTmpVBS%"
ECHO WScript.Echo mm                    >> "%MMTmpVBS%"
ECHO dt = DateAdd("d",-%MinusDay%,date) >> "%DDTmpVBS%"
ECHO dd = Right("0" ^& Day(dt),2)       >> "%DDTmpVBS%"
ECHO WScript.Echo dd                    >> "%DDTmpVBS%"
GOTO EOF

Further Resources

I needed something that would subtract days from the current date while checking leap years, etc. and this worked great.

I just call it from those scripts with the needed parameter (number of days to subtract), and then have it call back the calling script with substitutions and pass a parameter back to the original script for the modified (subtracted) date.

Here are examples:

Script needing date calculation variable set:

IF "%1"=="" goto modifydate

:modifydate
SET subtractdays=5
SET ModDateScript=\serversharepathCalled_ScriptsModDate.cmd
CALL "%ModDateScript%" %subtractdays% "%~fnx0"

Script which will calculate and pass back a %moddate% parameter to the original calling script to be set as a variable for it to process accordingly. You will simply put this at the end of the script you call to modify/subtract days from the current date (ModDate.cmd).

SET moddate=%mm%/%dd%/%yyyy%
Call %2 %moddate%
GOTO EOF

I was able to test and determine that these lines from the original script posted:

set yyyy=
set $tok=1-3
for /f "tokens=1 delims=.:/-, " %%u in ( date /t ) do set $d1=%%u
if "%$d1:~0,1%" GTR "9" set $tok=2-4
for /f "tokens=%$tok% delims=.:/-, " %%u in ( date /t ) do (
for /f "skip=1 tokens=2-4 delims=/-,()." %%x in ( echo.^|date ) do (
    set %%x=%%u
    set %%y=%%v
    set %%z=%%w
    set $d1=
    set $tok=))
if "%yyyy%"=="" set yyyy=%yy%
if /I %yyyy% LSS 100 set /A yyyy=2000 + 1%yyyy% - 100

Can be replaced with just this one single line and it works just as well:

FOR /F "tokens=2-4 delims=/ " %%A IN ("%date%") DO SET "mm=%%A" DO (& SET "dd=%%B") DO (& SET "yyyy=%%C")

Please explain what those lines (the ones I changed to just the one line with and statements) do anyways because I cannot tell the difference quickly testing. I subtracted back to the 19th century and it appeared accurate to me. I thought perhaps it helped handle the calculations where the modified year would be less than 2000 -- but I didn t see that unless I m missing something.

Otherwise this one script can be easily called and pass back the %mm%/%dd%/%yyyy% as a parameter for several scripts which need their own calculations. Great and very efficient batch solution. I can pass the argument as %1, %2, %3, etc. and still use the setlocal in that script for the current date -- just make a variable something like moddate=%1, etc.

Lastly, I challenge any batch script expert to optimize this script even further and post back the results for batch people to test.

Thanks, P

Try with this code in other words. You could use as a script subroutine or use this with the CALL and parameters functions to pass back to the original batch file:

:: Pass 1st parameter as number of days (whole numbers) to subtract from current day in   date
:: This script is able to subtract days to any date of the current date
:: This script will check for leap years, etc. as well
@echo on
::for /f "tokens=2-4 delims=/ " %%A in ("%date%") do set "mm=%%A" do & set "dd=%%B" do & set "yyyy=%%C"
set "mm=%date:~4,2%" & set "dd=%date:~7,2%" & set "yyyy=%date:~10,4%"
set CurDate=%mm%/%dd%/%yyyy%
set dayCnt=%1
if "%dayCnt%"=="" set dayCnt=1
:: Substract your days here
set /A dd=1%dd% - 100 - %dayCnt%
set /A mm=1%mm% - 100
:CHKDAY
if /I %dd% GTR 0 goto DONE
set /A mm=%mm% - 1
if /I %mm% GTR 0 goto ADJUSTDAY
set /A mm=12
set /A yyyy=%yyyy% - 1
:ADJUSTDAY
if %mm%==1 goto SET31
if %mm%==2 goto LEAPCHK
if %mm%==3 goto SET31
if %mm%==4 goto SET30
if %mm%==5 goto SET31
if %mm%==6 goto SET30
if %mm%==7 goto SET31
if %mm%==8 goto SET31
if %mm%==9 goto SET30
if %mm%==10 goto SET31
if %mm%==11 goto SET30
:: ** Month 12 falls through
:SET31
set /A dd=31 + %dd%
goto CHKDAY
:SET30
set /A dd=30 + %dd%
goto CHKDAY
:LEAPCHK
set /A tt=%yyyy% %% 4
if not %tt%==0 goto SET28
set /A tt=%yyyy% %% 100
if not %tt%==0 goto SET29
set /A tt=%yyyy% %% 400
if %tt%==0 goto SET29
:SET28
set /A dd=28 + %dd%
goto CHKDAY
:SET29
set /A dd=29 + %dd%
goto CHKDAY
:DONE
if /I %mm% LSS 10 set mm=0%mm%
if /I %dd% LSS 10 set dd=0%dd%
echo Date %dayCnt% day(s) before %CurDate% is %mm%/%dd%/%yyyy%
SET DirDate=%mm%/%dd%/%yyyy%
:: The %2 parameter is passed from the calling script as the full path and name of the          file to call back
:: %2 equals %~fnx0
:: The dirdate variable is passed as parameter %1 back to the calling script
Call %2 %dirdate%
GOTO EOF

I m going to look for a vb or something more efficient I can still incorporate or call from a batch to dynamically calculate dates.

Found this script on ss64.com: https://ss64.com/nt/syntax-datemath.html (license: https://ss64.com/docs/copyright.html)

You can keep it separate and call it from your batch files without cluttering your code, it will fill some environments variables with the operation result.

For example, this will subtract one day to the current date (on my system date is returned in the "dd/mm/yyyy" format):

set YY=%date:~-4,4%
set MM=%date:~-7,2%
set DD=%date:~-10,2
call datemath.bat %YY% %MM% %DD% - 1
echo year=%_yy_int%, month=%_mm_int%, day=%_dd_int%
echo padded date:%_ymd_str%, padded month:%_mm_str%, padded day:%_dd_str%

The script:

   @ECHO off
   SETLOCAL
   :: DateMath, a general purpose date math routine

   :: If DateMath detects an error, variable _dd_int is set to 999999.
   SET v_dd_int=0
   SET v_mm_int=0 
   SET v_yy_int=0
   SET v_ymd_str=
   SET v_mm_str=
   SET v_dd_str=

   IF "%3"=="" goto s_syntax
   IF "%4"=="+" goto s_validate_year
   IF "%4"=="-" goto s_validate_year
   IF "%4"=="" goto s_validate_year

   :s_syntax
   echo:
   echo DATEMATH SYNTAX:
   echo _______________
   echo:
   echo DateMath will set the variables as listed below
   echo  str  variables include leading zeros e.g. "01"
   echo  int  variables leading zeros are stripped e.g. "1"
   echo:
   echo CALL DateMath YY MM DD - YY2 MM2 DD2 
   echo:
   echo Will set variable _dd_int to the signed difference
   echo between the 2 dates (measured in days)
   echo:
   echo:
   echo CALL DateMath YY MM DD +/- Days 
   echo:
   echo Will set the following variables to the result of 
   echo adding or substracting days from the initial date:
   echo    _ymd_str, _yy_int
   echo    _mm_str, _mm_int,
   echo    _dd_str, _dd_int
   echo:
   echo:
   echo ___________________________________
   pause

   echo:
   echo:
   echo CALL DateMath YY MM DD
   echo:
   echo Will set the following variables:
   echo    _ymd_str, _yy_int
   echo    _mm_str, _mm_int,
   echo    _dd_str, _dd_int
   echo:
   echo ___________________________________
   echo:
   echo _ymd_str is in YYYYMMDD format.
   echo:
   echo _yy_int is in YYYY format, even if YY format was originally supplied.
   echo This conversion is useful for FAT/NTFS file dates which are in YY format.
   echo:

   ENDLOCAL & SET /a _dd_int=999999
   goto :eof

   :s_validate_year
   ::strip leading zeros
    SET v_yy=%1
    if %v_yy:~0,1% EQU 0 set v_yy=%v_yy:~1%

    :: Check for Y2K
    IF %v_yy% LSS 100 IF %v_yy% GEQ 80 SET /A v_yy += 1900
    IF %v_yy% LSS 80 SET /A v_yy += 2000

    :: at this point v_yy contains a 4 digit year

   ::validate month and day
    if %2 GTR 12 goto s_syntax
    if %3 GTR 31 goto s_syntax

    SET v_mm=%2
    SET v_dd=%3

    ::strip leading zeros
    if %v_mm:~0,1% EQU 0 set v_mm=%v_mm:~1%
    if %v_dd:~0,1% EQU 0 set v_dd=%v_dd:~1%

   :: Set the int variables
    SET /a v_dd_int=%v_dd%
    SET /a v_yy_int=%v_yy%
    SET /a v_mm_int=%v_mm%

   :: Determine which function to perform - ADD, SUBTRACT or CONVERT

    If not "%6"=="" goto s_validate_2nd_date 
    if "%4"=="" goto s_convert_only

   :: Add or subtract  days to a date
    SET /a v_number_of_days=%5
    goto s_add_or_subtract_days

   :s_convert_only

    SET /a v_dd_int=%v_dd%
    IF %v_dd% LEQ 9 (SET v_dd_str=0%v_dd%) ELSE (SET v_dd_str=%v_dd%)
    IF %v_mm% LEQ 9 (SET v_mm_str=0%v_mm%) ELSE (SET v_mm_str=%v_mm%)
    SET v_ymd_str=%v_yy%%v_mm_str%%v_dd_str%

   ECHO DATEMATH - Convert date only (no maths)
   goto s_end
   ::::::::::::::::::::::::::::::::::::::::::::::::::

   :s_validate_2nd_date
    If "%4"=="+" goto s_syntax
    :: Subtracting one date from another ::::::
    :: strip leading zero
    SET v_yy2=%5
    if %v_yy2:~0,1% EQU 0 set v_yy2=%v_yy2:~1%

    if %v_yy2% GTR 99 goto s_validate2nd_month
    if %v_yy2% GTR 49 goto s_prefix_2_1950_1999
    if %v_yy2% LSS 10 goto s_prefix_2_2000_2009
    SET v_yy2=20%v_yy2%
    goto s_validate2nd_month

   :s_prefix_2_2000_2009
    SET v_yy2=200%v_yy2%
    goto s_validate2nd_month

   :s_prefix_2_1950_1999
    SET v_yy2=19%v_yy2%

   :s_validate2nd_month
    ::strip leading zeros
    ::SET /a v_yy2=%v_yy2%
    if %v_yy2:~0,1% EQU 0 set v_yy2=%v_yy2:~1%
    ::v_yy2 now contains a 4 digit year

    if %6 GTR 12 goto s_syntax
    SET v_mm2=%6

    if %7 GTR 31 goto s_syntax
    SET v_dd2=%7

    ::strip leading zeros
    ::SET /a v_mm2=%v_mm2%
    if %v_mm2:~0,1% EQU 0 set v_mm2=%v_mm2:~1%
    ::SET /a v_dd2=%v_dd2%
    if %v_dd2:~0,1% EQU 0 set v_dd2=%v_dd2:~1%

   call :s_julian_day %v_yy_int% %v_mm_int% %v_dd_int%
   SET v_sumdays1=%v_JulianDay%

   call :s_julian_day %v_yy2% %v_mm2% %v_dd2%
   SET v_sumdays2=%v_JulianDay%

   SET /a v_dd_int=%v_sumdays1% - %v_sumdays2%

   ECHO DATEMATH - Subtracting one date from another = days difference
   ECHO ~~~~~~
   ECHO %v_dd_int%
   ECHO ~~~~~~
   goto s_end_days
   ::::::::::::::::::::::::::::::::::::::::::::::::::

   :s_add_or_subtract_days
   if /i "%4"=="+" goto s_add_up_days

   :: Subtract all days ::::::
   SET /a v_dd=%v_dd% - %v_number_of_days%

   :s_adjust_month_year
   if %v_dd% GEQ 1 goto s_add_subtract_days_DONE
   SET /a v_mm=%v_mm% - 1
   if %v_mm% GEQ 1 goto s_add_days_%v_mm%
   SET /a v_yy=%v_yy% - 1
   SET /a v_mm=%v_mm% + 12
   goto s_add_days_%v_mm%

   :s_add_days_2
   SET /a v_dd=%v_dd% + 28
   SET /a v_leapyear=%v_yy% / 4
   SET /a v_leapyear=%v_leapyear% * 4
   if %v_leapyear% NEQ %v_yy% goto s_adjust_month_year
   SET /a v_dd=%v_dd% + 1
   goto s_adjust_month_year

   :s_add_days_4
   :s_add_days_6
   :s_add_days_9
   :s_add_days_11
   SET /a v_dd=%v_dd% + 30
   goto s_adjust_month_year

   :s_add_days_1
   :s_add_days_3
   :s_add_days_5
   :s_add_days_7
   :s_add_days_8
   :s_add_days_10
   :s_add_days_12
   SET /a v_dd=%v_dd% + 31
   goto s_adjust_month_year

   :s_add_up_days
   :: add all days ::::::
   SET /a v_dd=%v_dd% + %v_number_of_days%

   :s_subtract_days_
   goto s_subtract_days_%v_mm%

   :s_adjust_mth_yr
   SET /a v_mm=%v_mm% + 1
   if %v_mm% LEQ 12 goto s_subtract_days_%v_mm%
   SET /a v_yy=%v_yy% + 1
   SET /a v_mm=%v_mm% - 12
   goto s_subtract_days_%v_mm%

   :s_subtract_days_2
   SET /a v_leapyear=%v_yy% / 4
   SET /a v_leapyear=%v_leapyear% * 4
   If %v_leapyear% EQU %v_yy% goto s_subtract_leapyear

   if %v_dd% LEQ 28 goto s_add_subtract_days_DONE
   SET /a v_dd=%v_dd% - 28
   goto s_adjust_mth_yr

   :s_subtract_leapyear
   if %v_dd% LEQ 29 goto s_add_subtract_days_DONE
   SET /a v_dd=%v_dd% - 29
   goto s_adjust_mth_yr

   :s_subtract_days_4
   :s_subtract_days_6
   :s_subtract_days_9
   :s_subtract_days_11
   if %v_dd% LEQ 30 goto s_add_subtract_days_DONE
   SET /a v_dd=%v_dd% - 30
   goto s_adjust_mth_yr

   :s_subtract_days_1
   :s_subtract_days_3
   :s_subtract_days_5
   :s_subtract_days_7
   :s_subtract_days_8
   :s_subtract_days_10
   :s_subtract_days_12
   if %v_dd% LEQ 31 goto s_add_subtract_days_DONE
   SET /a v_dd=%v_dd% - 31
   goto s_adjust_mth_yr

   :s_add_subtract_days_DONE
   SET /a v_dd_int=%v_dd%
   SET /a v_mm_int=%v_mm%
   SET /a v_yy_int=%v_yy%
   IF %v_dd% GTR 9 (SET v_dd_str=%v_dd%) ELSE (SET v_dd_str=0%v_dd%)
   IF %v_mm% GTR 9 (SET v_mm_str=%v_mm%) ELSE (SET v_mm_str=0%v_mm%)
   SET v_ymd_str=%v_yy%%v_mm_str%%v_dd_str%

   ECHO DATEMATH - add or subtract days from a date = new date
   goto s_end
   ::::::::::::::::::::::::::::::::::::::::::::::::::

   :s_julian_day
   SET v_year=%1
   SET v_month=%2
   SET v_day=%3

   SET /a v_month=v_month
   SET /a v_day=v_day

   SET /A a = 14 - v_month
   SET /A a /= 12
   SET /A y = v_year + 4800 - a
   SET /A m = v_month + 12 * a - 3
   SET /A m = 153 * m + 2
   SET /A m /= 5
   SET /A v_JulianDay = v_day + m + 365 * y + y / 4 - y / 100 + y / 400 - 32045

   ECHO The Julian Day is [%v_JulianDay%]
   goto :eof
   ::::::::::::::::::::::::::::::::::::::::::::::::::

   :s_end
   ECHO ~~~~~~~~~~~~
   ECHO [%v_ymd_str%] YY=[%v_yy_int%] MM=[%v_mm_str%] DD=[%v_dd_str%]
   ECHO ~~~~~~~~~~~~
   :s_end_days
   ENDLOCAL&SET /a _yy_int=%v_yy_int%&SET /a _mm_int=%v_mm_int%&SET /a _dd_int=%v_dd_int%&SET _ymd_str=%v_ymd_str%&SET _mm_str=%v_mm_str%&SET _dd_str=%v_dd_str%

Can be done with adding jscript code to a batch file. Here s the dayAdder.bat that accepts only one argument - the days you want to add to the current date and prints the result:

  @if (@X) == (@Y) @end /* JScript comment 
    @echo off   
    cscript //E:JScript //nologo "%~f0" %*
    exit /b %errorlevel%       
@if (@X)==(@Y) @end JScript comment */

var days=parseInt(WScript.Arguments.Item(0));


Date.prototype.addDays = function(days) {
    var date = new Date(this.valueOf());
    date.setDate(date.getDate() + days);
    return date;
}

var date = new Date();

WScript.Echo(date.addDays(5));
WScript.Echo("Year: " + date.getFullYear());
WScript.Echo("Month: " + date.getMonth());
WScript.Echo("DayOfTeWEek: " + date.getDay());

examaple and output:

E:scripts>dayAdder.bat 7
Sun Nov 8 16:27:48 UTC+0200 2020
Year: 2020
Month: 10
DayOfTeWEek: 2
DayOfTheMonth: 3

You can modify it in way that will be suitable for you.





相关问题
热门标签