Rob van der Woude's Scripting Pages
Powered by GeSHi

Source code for dateadd.bat

(view source code of dateadd.bat as plain text)

  1. @ECHO OFF
  2. ECHO.
  3.  
  4. :: Reset variables
  5. SET "cDate="
  6. SET "iDate="
  7. SET "sDate="
  8.  
  9. :: Check the Windows version
  10. IF NOT "%OS%"=="Windows_NT" GOTO Syntax
  11.  
  12. SETLOCAL
  13.  
  14. :: Initialize variable
  15. SET "Error=0"
  16.  
  17. :: Check the command line arguments
  18. IF     "%~1"=="" GOTO Syntax
  19. IF NOT "%~3"=="" GOTO Syntax
  20. ECHO.%* | FINDSTR.EXE /R /I /C:"[^-\""adnotwy/0-9 ]" >NUL && GOTO Syntax
  21. FOR %%A IN (%Date%) DO SET "Today=%%~A"
  22. IF "%~2"=="" (
  23. 	SET "cDate=%Today%"
  24. 	SET /A "cDays=%~1" >NUL 2>&1
  25. ) ELSE (
  26. 	SET "cDate=%~1"
  27. 	IF /I "%~1"=="Now"   (SET "cDate=%Today%")
  28. 	IF /I "%~1"=="Today" (SET "cDate=%Today%")
  29. 	SET /A "cDays=%~2" >NUL 2>&1
  30. )
  31. IF "%cDays%"=="0" (
  32. 	ECHO.
  33. 	ECHO Error: %cDays% is not a valid integer
  34. 	GOTO Syntax
  35. )
  36.  
  37. :: Read the Date format from the registry; if this fails, we're probably dealing with an older Windows version
  38. FOR /F "tokens=3" %%A IN ('REG.EXE Query "HKEY_CURRENT_USER\Control Panel\International" /v iDate 2^>NUL') DO SET "iDate=%%~A"
  39. FOR /F "tokens=3" %%A IN ('REG.EXE Query "HKEY_CURRENT_USER\Control Panel\International" /v sDate 2^>NUL') DO SET "sDate=%%~A"
  40. IF "%iDate%"=="" GOTO Syntax
  41.  
  42. :: Check if a valid date in local format was specified
  43. ECHO.%cDate% | FINDSTR.EXE /R /B /C:"[0-9][0-9]*%sDate%[0-9][0-9]*%sDate%[0-9][0-9][0-9][0-9]" >NUL
  44. IF ERRORLEVEL 1 (
  45. 	REM Try testing for ISO 8601 format
  46. 	ECHO.%cDate% | FINDSTR.EXE /R /B /C:"[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]" >NUL
  47. 	IF ERRORLEVEL 1 (
  48. 		ECHO.
  49. 		ECHO Error: %cDate% is not a valid date
  50. 		GOTO Syntax
  51. 	) ELSE (
  52. 		SET "iDate=2"
  53. 		SET "sDate=-"
  54. 	)
  55. )
  56.  
  57. :: Parse the date specified, abort on failure
  58. CALL :ParseDate %cDate%
  59. IF "%Error%"=="1" GOTO Syntax
  60.  
  61. :: Convert the parsed Gregorian date to Julian
  62. CALL :JDate %GYear% %GMonth% %GDay%
  63.  
  64. :: Display original input
  65. ECHO Starting date   : %cDate%
  66.  
  67. :: Add or subtract the specified number of days
  68. IF "%cDays:~0,1%"=="-" (
  69. 	SET /A "NewJDate = %JDate% - %cDays:~1%"
  70. 	ECHO Days subtracted : %cDays:~1%
  71. ) ELSE (
  72. 	SET /A "NewJDate = %JDate% + %cDays%"
  73. 	ECHO Days added      : %cDays%
  74. )
  75.  
  76. :: Convert the new Julian date back to Gregorian again
  77. CALL :GDate %NewJDate%
  78.  
  79. :: Reformat the date to local format
  80. CALL :ReformatDate %GDate%
  81.  
  82. :: Display the result
  83. ECHO Resulting date  : %LDate%
  84.  
  85. :: Return the result in a variable named after this batch file
  86. ENDLOCAL & SET "%~n0=%LDate%"
  87. GOTO:EOF
  88.  
  89.  
  90. ::===================================::
  91. ::                                   ::
  92. ::   -   S u b r o u t i n e s   -   ::
  93. ::                                   ::
  94. ::===================================::
  95.  
  96.  
  97. :GDate
  98. :: Convert Julian date back to "normal" Gregorian date
  99. :: Argument : Julian date
  100. :: Returns  : YYYY MM DD
  101. ::
  102. :: Algorithm based on Fliegel-Van Flandern
  103. :: algorithm from the Astronomical Almanac,
  104. :: provided by Doctor Fenton on the Math Forum
  105. :: (http://mathforum.org/library/drmath/view/51907.html),
  106. :: and converted to batch code by Ron Bakowski.
  107. ::
  108. SET /A "P      = %~1 + 68569"
  109. SET /A "Q      = 4 * %P% / 146097"
  110. SET /A "R      = %P% - ( 146097 * %Q% + 3 ) / 4"
  111. SET /A "S      = 4000 * ( %R% + 1 ) / 1461001"
  112. SET /A "T      = %R% - 1461 * %S% / 4 + 31"
  113. SET /A "U      = 80 * %T% / 2447"
  114. SET /A "V      = %U% / 11"
  115. SET /A "GYear  = 100 * ( %Q% - 49 ) + %S% + %V%"
  116. SET /A "GMonth = %U% + 2 - 12 * %V%"
  117. SET /A "GDay   = %T% - 2447 * %U% / 80"
  118. :: Clean up the mess
  119. FOR %%A IN (P Q R S T U V) DO SET "%%~A="
  120. :: Add leading zeroes
  121. IF 1%GMonth% LSS 20 SET "GMonth=0%GMonth%"
  122. IF 1%GDay%   LSS 20 SET "GDay=0%GDay%"
  123. :: Return value
  124. SET "GDate=%GYear% %GMonth% %GDay%"
  125. GOTO:EOF
  126.  
  127.  
  128. :JDate
  129. :: Convert date to Julian
  130. :: Arguments : YYYY MM DD
  131. :: Returns   : Julian date
  132. ::
  133. :: First strip leading zeroes
  134. SET "MM=%2"
  135. SET "DD=%3"
  136. IF "%MM:~0,1%"=="0" SET "MM=%MM:~1%"
  137. IF "%DD:~0,1%"=="0" SET "DD=%DD:~1%"
  138. ::
  139. :: Algorithm based on Fliegel-Van Flandern
  140. :: algorithm from the Astronomical Almanac,
  141. :: provided by Doctor Fenton on the Math Forum
  142. :: (http://mathforum.org/library/drmath/view/51907.html),
  143. :: and converted to batch code by Ron Bakowski.
  144. SET /A "Month1 = ( %MM% - 14 ) / 12"
  145. SET /A "Year1  = %~1 + 4800"
  146. SET /A "JDate  = 1461 * ( %Year1% + %Month1% ) / 4 + 367 * ( %MM% - 2 -12 * %Month1% ) / 12 - ( 3 * ( ( %Year1% + %Month1% + 100 ) / 100 ) ) / 4 + %DD% - 32075"
  147. FOR %%A IN (Month1 Year1) DO SET "%%~A="
  148. GOTO:EOF 
  149.  
  150.  
  151. :ParseDate
  152. :: Parse (Gregorian) date depending on registry's date format settings
  153. :: Argument : Gregorian date in local date format, or in ISO 8601 format
  154. :: Requires : sDate (local date separator), iDate (local date format number)
  155. :: Returns  : GYear (4-digit year), GMonth (2-digit month), GDay (2-digit day)
  156. ::
  157. IF "%iDate%"=="0" FOR /F "tokens=1-3 delims=%sDate%" %%A IN ('ECHO.%1') DO (
  158. 	SET "GYear=%%~C"
  159. 	SET "GMonth=%%~A"
  160. 	SET "GDay=%%~B"
  161. )
  162. IF "%iDate%"=="1" FOR /F "tokens=1-3 delims=%sDate%" %%A IN ('ECHO.%1') DO (
  163. 	SET "GYear=%%~C"
  164. 	SET "GMonth=%%~B"
  165. 	SET "GDay=%%~A"
  166. )
  167. IF "%iDate%"=="2" FOR /F "TOKENS=1-3 DELIMS=%sDate%" %%A IN ('ECHO.%1') DO (
  168. 	SET "GYear=%%~A"
  169. 	SET "GMonth=%%~B"
  170. 	SET "GDay=%%~C"
  171. )
  172. IF %GDay%   GTR 31 SET "Error=1"
  173. IF %GMonth% GTR 12 SET "Error=1"
  174. GOTO:EOF
  175.  
  176.  
  177. :ReformatDate
  178. :: Reformat the date back to the local format
  179. :: Arguments : YYYY MM DD
  180. :: Returns   : LDate (Gregorian date in local format)
  181. ::
  182. IF "%iDate%"=="0" SET "LDate=%~2%sDate%%~3%sDate%%~1"
  183. IF "%iDate%"=="1" SET "LDate=%~3%sDate%%~2%sDate%%~1"
  184. IF "%iDate%"=="2" SET "LDate=%~1%sDate%%~2%sDate%%~3"
  185. GOTO:EOF
  186.  
  187.  
  188. :Syntax
  189. ECHO.
  190. ECHO DateAdd.bat,  Version 2.01 for Windows XP and later
  191. ECHO Add the specified number of days to the specified date
  192. ECHO.
  193. ECHO Usage:   DATEADD  [ date ]  days
  194. ECHO.
  195. ECHO Where:   date     is a "normal" Gregorian date, either in the local date
  196. ECHO                   format, or in ISO 8601 yyyy-MM-dd format, or "Today"
  197. ECHO                   or "Now" (default if not specified: today's date)
  198. ECHO          days     is the number of days to add (negative to subtract)
  199. ECHO.
  200. ECHO E.g.     DATEADD  2017-01-01   1        will return 2017-01-02
  201. ECHO          DATEADD  2017-01-01  -1        will return 2016-12-31
  202. :: To show the following "advanced" examples, Windows XP or later is required
  203. IF NOT "%OS%"=="Windows_NT" GOTO Skipped2
  204. FOR /F "tokens=3" %%A IN ('REG.EXE Query "HKEY_CURRENT_USER\Control Panel\International" /v iDate 2^>NUL') DO SET "iDate=%%~A"
  205. FOR /F "tokens=3" %%A IN ('REG.EXE Query "HKEY_CURRENT_USER\Control Panel\International" /v sDate 2^>NUL') DO SET "sDate=%%~A"
  206. :: Windows XP or later is required to read iDate, so if iDate isn't set, skip the "advanced" examples
  207. IF "%iDate%"=="" GOTO Skipped2
  208. FOR %%A IN (%Date%) DO SET "Today=%%~A"
  209. CALL :ParseDate %Today%
  210. IF NOT "%Error%"=="0" GOTO Skipped1
  211. CALL :JDate %GYear% %GMonth% %GDay%
  212. SET /A "NewJDate = %JDate% + 1"
  213. CALL :GDate %NewJDate%
  214. CALL :ReformatDate %GDate%
  215. SET "Tomorrow=%LDate%"
  216. CALL :ParseDate %Today%
  217. CALL :JDate %GYear% %GMonth% %GDay%
  218. SET /A "NewJDate = %JDate% - 1"
  219. CALL :GDate %NewJDate%
  220. CALL :ReformatDate %GDate%
  221. SET "Yesterday=%LDate%"
  222. :Skipped1
  223. IF "%Yesterday%"=="" (
  224. 	ECHO          DATEADD  %Today%   1        will return tomorrow's date  ^(as will DATEADD  1^)
  225. 	ECHO          DATEADD  %Today%  -1        will return yesterday's date ^(as will DATEADD -1^)
  226. ) ELSE (
  227. 	ECHO          DATEADD  %Today%   1        will return %Tomorrow%
  228. 	ECHO          DATEADD  1                     will return %Tomorrow% too
  229. 	ECHO          DATEADD  %Today%  -1        will return %Yesterday%
  230. 	ECHO          DATEADD  -1                    will return %Yesterday% too
  231. )
  232. :: End of "advanced" examples section
  233. :Skipped2
  234. ECHO.
  235. ECHO Notes:   By default, the returned date will be presented in the local date
  236. ECHO          format; however, if the date in the command line argument is in the
  237. ECHO          ISO 8601 yyyy-MM-dd format, the result will be in ISO 8601 format too.
  238. ECHO          Unlike its earlier 1.* versions, this batch file does not require
  239. ECHO          elevated privileges.
  240. ECHO.
  241. ECHO Credits: Julian date conversion based on Fliegel-Van Flandern algorithms from
  242. ECHO          the Astronomical Almanac, provided by Doctor Fenton on the Math Forum
  243. ECHO          http://mathforum.org/library/drmath/view/51907.html
  244. ECHO          and converted to batch code by Ron Bakowski.
  245. ECHO.
  246. ECHO Written by Rob van der Woude
  247. ECHO http://www.robvanderwoude.com
  248.  
  249. IF "%OS%"=="Windows_NT" ENDLOCAL
  250. IF "%OS%"=="Windows_NT" EXIT /B 1
  251.  

page last uploaded: 2017-04-06, 13:33