China DOS Union

-- Unite DOS · Advance DOS · Grow DOS --

Union site: www.cn-dos.net Forum site: www.cn-dos.net/forum
DOS stands for freedom, openness and progress. Let us work hard, learn from the openness and GNU spirit of FreeDOS and Linux, and together build and grow a free GNU GPL world!

中国DOS联盟论坛
The time now is 2026-07-02 16:39
中国DOS联盟论坛 » DOS批处理 & 脚本技术(批处理室) » Batch file for the date N days ago DigestI View 7,067 Replies 4
Original Poster Posted 2007-06-07 21:29 ·  中国 广东 电信
荣誉版主
★★★★
batch fan
Credits 5,226
Posts 1,737
Joined 2006-03-10 00:38
20-year member
UID 51697
From 成都
Status Offline
  People often ask how to calculate the date N days ago. Because this involves the issues of big months and small months, common years and leap years, the code becomes relatively complicated and tends to scare people off.

  Although willsort posted code like this two years ago (please refer to: (Ended) Deleting files older than N days from the DOS command line under WINDOWS), and although the idea is extremely simple—convert the date into a relative number, do the subtraction, then convert the relative number back into a date—the numbers 2472632 and 146097 and the like appear too abruptly, making it hard to figure out what's going on. To be honest, limited by my own level, even now I still find it very confusing.

  Now I'm posting three batch files for getting the date N days ago ( the date may include the weekday, but it must be arranged in year-month-day order, and the year must be four digits, otherwise there will be errors). The key parts all have comments, so they're a bit easier to understand than willsort's:

  Code 1:

@echo off
:: Get the date N days ago
:: Idea:
::   Simulate manual calculation: subtract the number of days from the date number;
::   when the difference is negative, borrow 1 from the higher place value.
:: Features:
::   The code is concise and easy to understand; speed depends on the size of the specified number of days

setlocal enabledelayedexpansion

:Main
cls
:: The date may include the weekday, but it must be arranged in year-month-day order
:: The year must be four digits, otherwise there will be errors
set day=%date%
set days=0
echo.&echo.
echo The specified date is: %day%
echo.
set /p input= Please specify how many days to trace back:

:: Extract the date
for /f "tokens=1-3 delims=-/. " %%i in ("%day%") do (
set /a sy=%%i, sm=100%%j %% 100, sd=100%%k %% 100
)

set /a sd-=input

if %sd% leq 0 call :count

cls
echo.&echo.
echo The specified date is: %day%
echo.
set sm=0%sm%
set sd=0%sd%
echo The date %input% days ago is: %sy%-%sm:~-2%-%sd:~-2%
pause>nul
goto Main

:count
set /a sm-=1
if !sm! equ 0 set /a sm=12, sy-=1
call :days
set /a sd+=days
if %sd% leq 0 goto count
goto :eof

:days
:: Get the total number of days in the specified month
set /a leap="^!(sy %% 4) & ^!(^!(sy %% 100)) | ^!(sy %% 400)"
set /a max=28+leap
set num=0
set str=31 %max% 31 30 31 30 31 31 30 31 30 31
for %%i in (%str%) do (
set /a num+=1
if %sm% equ !num! set days=%%i&goto :eof
)
goto :eof

  Code 2:

@echo off
:: Get the date N days ago
:: Idea:
::   Convert the current date into a day count
::   Subtract N days from the current day count
::   Then convert the result back into a date
:: Specific operation:
::   Calculate the day count year by year
:: Features:
:: The code is concise and easy to understand; relatively slow, but not affected by the size of the specified number of days

setlocal enabledelayedexpansion

:Main
cls
:: The date may include the weekday, but it must be arranged in year-month-day order
:: The year must be four digits, otherwise there will be errors
set day=%date%
set days=0
echo.&echo.
echo The specified date is: %day%
echo.
set /p input= Please specify how many days to trace back:

rem ========Convert the specified date into a day count========
:: Extract the date
for /f "tokens=1-3 delims=-/. " %%i in ("%day%") do (
set /a sy=%%i, sm=100%%j %% 100, sd=100%%k %% 100
)
:: Convert the year into a day count
for /l %%i in (1,1,%sy%) do (
set /a leap="^!(%%i %% 4) & ^!(^!(%%i %% 100)) | ^!(%%i %% 400)"
set /a days=days+365+leap
)
:: Convert the month into a day count
set /a num=0, mday=0, max=28+leap
set str=0 31 %max% 31 30 31 30 31 31 30 31 30
for %%i in (%str%) do (
set /a num+=1
if !num! leq !sm! set /a mday+=%%i
)

set /a days=days+mday+sd

set /a days-=input


rem ========Convert the day count into a date========
:: Get the year
for /l %%i in (1,1,%sy%) do (
set /a leap="^!(%%i %% 4) & ^!(^!(%%i %% 100)) | ^!(%%i %% 400)"
set /a days_tmp=365+leap
if !days! gtr !days_tmp! (
set /a days-=days_tmp
set y=%%i
)
)
:: Get the month and date
set /a m=1, max=28+%leap%
set str=31 %max% 31 30 31 30 31 31 30 31 30
for %%i in (%str%) do (
if !days! gtr %%i (
set /a days-=%%i
set /a m+=1
) else goto next
)
:next
set m=0%m%
set d=0%days%

cls
echo.&echo.
echo The specified date is: %day%
echo.
echo The date %input% days ago is: %y%-%m:~-2%-%d:~-2%
pause>nul
goto Main

  Code 3:

@echo off
:: Get the date N days ago
:: Idea:
::   Convert the current date into a day count
::   Subtract N days from the current day count
::   Then convert the result back into a date
:: Specific operation:
:   First calculate using 365 days per year, then calculate the number of leap years
::   Finally do the conversion
:: Features:
::   The code is complicated and not easy to understand, but very fast
:: There is still a bug in the calculation; you can use 11111 to compare and test against the first two. I don't have time to update it for now

setlocal enabledelayedexpansion

:Main
cls
:: The date may include the weekday, but it must be arranged in year-month-day order
:: The year must be four digits, otherwise there will be errors
set day=2007-01-02
set /a days=0, sum=0
echo.&echo.
echo The specified date is: %day%
echo.
set /p input= Please specify how many days to trace back:

rem =======Convert the date into a day count=======
:: Extract the date
for /f "tokens=1-3 delims=/-. " %%i in ("%day%") do (
set /a sy=%%i, sm=100%%j %% 100, sd=100%%k %% 100, y=%%i
)

:: Convert the year into a day count
set num=0
if %sy% lss 400 goto next1
call :leap_num
:next1
set /a leap_num=sy/4-num

:: Convert the month into a day count
set /a leap="^!(sy %% 4) & ^!(^!(sy %% 100)) | ^!(sy %% 400)"
set /a max=28+leap
set num=0
set str=31 %max% 31 30 31 30 31 31 30 31 30 31
for %%i in (%str%) do (
set /a num+=1
if !num! lss %sm% set /a sum+=%%i
)

set /a days=365*sy+leap_num+sum+sd

set /a days-=input

rem =======Convert the day count into a date=======

:: Get the year
set /a y=days/365
set /a mod1=days %% 365
call :leap_num
set /a mod2=mod1-leap_num
:loop2
if %mod2% lss 0 (
set /a y-=1
set /a mod2=365+mod2
) else goto next2
goto loop2

:: Get the month and date
:next2
set /a m=1, days=mod2+1, max=28+%leap%
set str=31 %max% 31 30 31 30 31 31 30 31 30
for %%i in (%str%) do (
if !days! gtr %%i (
set /a days-=%%i
set /a m+=1
) else goto next3
)
:next3
set m=0%m%
set d=0%days%

cls
echo.&echo.
echo The specified date is: %day%
echo.
echo The date %input% days ago is: %y%-%m:~-2%-%d:~-2%
pause>nul
goto Main

:leap_num
:: Count the years divisible by 100 but not by 400
set /a y_tmp=(%y:~0,1%%y%-%y%)/10
set num=0
:loop1
set /a mod=y_tmp %% 400
if %mod% neq 0 set /a num+=1
set /a y_tmp-=100
if %y_tmp% geq 100 goto loop1
set /a leap_num=y/4-num
goto :eof


[ Last edited by namejm on 2007-6-8 at 11:15 PM ]
尺有所短,寸有所长,学好CMD没商量。
考虑问题复杂化,解决问题简洁化。
Floor 2 Posted 2007-06-07 21:46 ·  中国 甘肃 张掖 电信
金牌会员
★★★★
Credits 4,103
Posts 1,744
Joined 2006-01-20 13:00
20-year member
UID 49241
Gender Male
From 甘肃.临泽
Status Offline
Using ruby is much simpler. I just want to pursue "using the shortest code, in the fastest time, with the most suitable tool, to solve it"—nothing else intended~

puts Data.today-3

[ Last edited by vkill on 2007-6-7 at 10:28 PM ]
Floor 3 Posted 2007-06-07 21:50 ·  中国 上海 联通
版主
★★★★★
Credits 9,023
Posts 5,017
Joined 2007-05-31 19:39
19-year member
UID 89899
Gender Male
Status Offline
Learning
Posting a batch file that uses VBS to calculate the date

@echo off
rem Delete the folder from three days ago
rem The target directory is C:\test
set Target=C:\test
dir /b %Target%>%temp%\FolderList.txt
echo dt=date()-3>%temp%\OldDate.vbs
echo s=right(year(dt),4) ^& right("0" ^& month(dt),2) ^& right("0" ^& day(dt),2)>>%temp%\OldDate.vbs
echo wscript.echo s>>%temp%\OldDate.vbs
for /f %%f in ('cscript /nologo %temp%\OldDate.vbs') do @set DelFlag=%%f
for /f %%i in (%temp%\FolderList.txt) do (
if %%i lss %DelFlag% (
rd /s /q %Target%\%%i
)
)
del %temp%\FolderList.txt
del %temp%\OldDate.vbs
Floor 4 Posted 2008-12-02 09:12 ·  中国 湖北 黄石 电信
初级用户
Credits 27
Posts 27
Joined 2008-11-17 09:28
17-year member
UID 131211
Gender Male
Status Offline
I want to ask: in the OP's third method, is set dat=2007-01-02 the initial time? Last night I came up with a method, but I don't know whether it's the same as the OP's. Please clarify. Also, I don't quite understand the OP's code (method three).

Below is my method:

Assume the initial time coordinate is 1900-01-01, and the input time is date1 (any time). This makes it easier to calculate the difference between the two dates (in days), tmp1. Then also input any number of days tmp2 that you want to query before or after date1. If it is N days before date1, then calculate the result as sum=tmp1+tmp2. (tmp2 can be positive or negative: positive for dates after date1, negative for dates before date1.) Then in the end you get a time difference sum measured from the initial time. Based on 1900-01-01 as the start/end time, calculating the date at a difference of sum days should be relatively simple.

This line of thought can solve the date N days before or after any given date. The start/end time can be set according to how large the calculated difference is, so as to reduce the amount of calculation.

Because my knowledge is limited, I can only provide the idea. I hope the experts can give some guidance. I don't know whether my idea is the same as the third method. To be honest, I still haven't completely understood the third method...
Floor 5 Posted 2008-12-27 11:06 ·  中国 广东 广州 海珠区 电信
初级用户
★★
Credits 131
Posts 119
Joined 2007-06-12 22:50
19-year member
UID 91125
Gender Male
From gz
Status Offline
::Determine the day before the current date
::First directly subtract 1 day from the day count
::If the result is day 0, then subtract 1 from the month, and the day count is the last day of that month.
::If the result is month 0, then subtract 1 from the year, and the month count is the last month of that year.
@echo off&setlocal enabledelayedexpansion
set yyyy=%date:~0,4%
set mm=%date:~5,2%
set dd=%date:~8,2%
set /a nd=!dd!-1
::If it's like subtracting one day from March 1 and getting day 0, then...
if !nd!==0 call :dd0
if !mm!==0 call :mm0
set yyyymmdd=!yyyy!-!mm!-!nd!
echo Today is:%date:~0,10%
echo Yesterday was:!yyyymmdd!
pause

:dd0
set /a mm=!mm!-1
for %%a in (1 3 5 7 8 10 12)do set %%add=31
set /a pddd=!yyyy!*10/4
set pd2d=!pddd:~-1,1!
set 2dd=28
if !pd2d!==0 set 2dd=29
for %%b in (4 6 9 11)do set %%bdd=30
set nd=!%mm%dd!
goto :eof
:mm0
set /a yyyy=!yyyy!-1
set mm=12
set nd=31
goto :eof
Forum Jump: