[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[数值计算] 根据给定的两个起止日期按先后/早晚顺序列出指定范围内的所有日期

本帖最后由 pcl_test 于 2017-4-6 08:42 编辑

在其他论坛看到有这样一个需求:
建立以日期为名字的文件夹,从20100406到20101230

  感觉这个需求有很多地方都可能用得到,因此,我想把这个问题扩展一下,使得它更具有通用性,具体要求为:

  1、能在批处理界面中通过手工输入起止日期的方式,自动生成起止日期范围内的所有日期数列(必须考虑平年闰年大月小月),按日期早晚输出到文本中去,一行一条数据,日期格式为8位的纯数字格式,比如20100407;
  2、如果在批处理界面中只输入一个日期,将以系统当前日期为起点,以输入的日期为终点,按照上一条的格式输出数据;
  3、最好不生成临时数据。
=====================================

  再加一条:
  4、最好通过纯批处理来处理,速度不能太慢。

  对第2点做稍许变动:如果只输入一个日期,则和系统当前日期做比较,以较早的日期为起点,较晚的日期为终点,按照第1条的要求输出数据。

  其中,难点在于第1和第3点,把这两点解决了,第2点将迎刃而解。

  难点提示:
  1、年份有平年闰年之分,日期大小月各不相同;
  2、系统的日期格式有很多种,在处理时需要做格式化,统一成形如YYYYMMDD的8位纯数字;
  3、若照搬以前那个批处理版万年历的代码,将难以按照日期早晚的顺序输出数据。


  关于闰年的判断方法(转自百度百科:http://baike.baidu.com/view/29649.htm?fr=ala0_1):
  判定公历闰年遵循的一般规律为: 四年一闰,百年不闰,四百年再闰.
  公历闰年的精确计算方法:(按一回归年365天5小时48分45.5秒)
  ①、普通年能被4整除的为闰年。(如2004年就是闰年,1901年不是闰年) 
  ②、世纪年能被100整除而不能被400整除的不是闰年。(如2000年是闰年,3200年是闰年,1900年不是闰年)
  ③、对于数值很大的年份能整除3200,但同时又能整除172800则又是闰年.(如172800年是闰年,864000年不是闰年)
尺有所短寸有所长,学好批处理没商量;
考虑问题复杂化,解决问题简洁化。

心在天山,身老沧州。

BAT调用VBS或者第三方命令行工具均可实现,不过似乎和第三点有些冲突。
还可以调用现成的日期计算函数,但效率估计不是很高。

TOP

最好通过纯批处理来实现。
尺有所短寸有所长,学好批处理没商量;
考虑问题复杂化,解决问题简洁化。

心在天山,身老沧州。

TOP

  1. @echo off&setlocal enabledelayedexpansion
  2. :han
  3. set a=
  4. set b=
  5. set/p a=起始日期,格式20071221:
  6. set/p b=终止日期,格式20080310,允许为空:
  7. if "%a%"=="" echo.此数值不允许为空,请按任意键重新开始&pause>nul&goto :han
  8. set m=寒夜312831303130313130313031孤星
  9. for /f "tokens=1,2,3 delims=-:/ " %%i in ("%date%") do set i=%%i%%j%%k
  10. if "%b%"=="" (if %i% gtr %a% (set b=%i%) else set a=%i%&set b=%a%)
  11. if "%a:~4,1%"=="0" (set tm=%a:~5,1%) else set tm=%a:~4,2%
  12. if "%a:~6,1%"=="0" (set td=%a:~7,1%) else set td=%a:~6,2%
  13. set ty=%a:~0,4%&echo.%a%
  14. :ye
  15. set/a "n=tm*2","td=td+1","y=(^!(ty%%4)&^!^!(ty%%100))|^!(ty%%400)"
  16. set e=!m:~%n%,2!
  17. if %tm%==2 if %y%==1 set e=29
  18. if %td% gtr %e% set/a "tm=tm+1",td=1
  19. if %tm%==13 set/a "ty=ty+1",tm=1
  20. set em=0%tm%&set ed=0%td%&set em=!em:~-2!&set ed=!ed:~-2!&set d=%ty%!em!!ed!
  21. if %d% gtr %b% echo 完成&pause>nul&goto :eof
  22. echo.%d%&goto :ye
复制代码
改了好几次,问题太多。。。还请大家多多指教

[ 本帖最后由 hanyeguxing 于 2010-4-8 01:05 编辑 ]
寒夜孤星:在没有说明的情况下,本人所有代码均运行在 XP SP3 下 (有问题请发贴,QQ临时会话已关闭)

TOP

稍作修改, 少许提高效率:
  1. @echo off & setlocal enabledelayedexpansion
  2. set /p ymds=请输入起始日期(yyyymmdd):
  3. set /p ymde=请输入截止日期(yyyymmdd):
  4. (set y=!ymds:~0,4!)&(set m=!ymds:~4,2!)&(set d=!ymds:~6,2!)
  5. set /a "y=1!y!-10000, m=1!m!-100, d=1!d!-100"
  6. echo 起始日期为:!y!-!m!-!d!
  7. set /a "leap=(^!(y%%4)&^!^!(y%%100))|^!(y%%400)"
  8. set /a "f=^!(m-2), s=^!(m-4)|^!(m-6)|^!(m-9)|^!(m-11)"
  9. set /a "dmax=f*(28+leap)+s*30+(^!f&^!s)*31"
  10. (set _y=000!y!)&(set _y=!_y:~-4!)&(set _m=0!m!)&(set _m=!_m:~-2!)
  11. :loop
  12. (set _d=0!d!)&(set _d=!_d:~-2!)
  13. if "!_y!!_m!!_d!" leq "!ymde!" (echo !_y!!_m!!_d!) else goto :break
  14. set /a d+=1
  15. if !d! gtr !dmax! (
  16. (set d=1)&(set /a m+=1)
  17. if !m! gtr 12 (
  18. (set m=1)&(set /a y+=1)&(set _y=000!y!)&(set _y=!_y:~-4!)
  19. set /a "leap=(^!(y%%4)&^!^!(y%%100))|^!(y%%400)"
  20. )
  21. set /a "f=^!(m-2), s=^!(m-4)|^!(m-6)|^!(m-9)|^!(m-11)"
  22. set /a "dmax=f*(28+leap)+s*30+(^!f&^!s)*31"
  23. (set _m=0!m!)&(set _m=!_m:~-2!)
  24. )
  25. goto :loop
  26. :break
  27. pause
复制代码

TOP

计算 100 年的日期 耗时 3.7 秒
  1. @echo off&setlocal enabledelayedexpansion
  2. set t=%time%
  3. echo 请输入8位数的起始日期和结束日期用空格分开
  4. echo 或只输入结束(开始)日期,默认当前日期为起始(结束)日期
  5. echo 输入格式 20080205 21080529&echo.
  6. set xx=19100201
  7. for /f "tokens=1,2" %%i in ("%xx%") do (
  8.    if not "%%j"=="" (set qs=%%i&set js=%%j) else (
  9.       for /f "tokens=1-3 delims=.\-/ " %%a in ("!date!") do (
  10.          if %%a%%b%%c gtr %%i (set/a qs=xx,js=%%a%%b%%c) else (
  11.             set/a qs=%%a%%b%%c,js=%%i
  12. ))))
  13. for %%a in (31 28 31 30 31 30 31 31 30 31 30 31) do set/a n+=1&set/a yue!n!=%%a
  14. set /a qsd=100%qs:~4,2%%%100,qsm=100%qs:~6,2%%%100
  15. set /a yuq=qsd,yuh=12,mq=qsm,mh=yue!qsd!
  16. (
  17. echo 起始日期 %qs:~0,4%-%qs:~4,2%-%qs:~6,2%
  18. echo 结束日期 %js:~0,4%-%js:~4,2%-%js:~6,2%
  19. for /l %%i in (%qs:~0,4% 1 %js:~0,4%) do (
  20.     if %%i equ %js:~0,4% set /a yuh=100%js:~4,2%%%100&set flag=a
  21.     for /l %%j in (!yuq! 1 !yuh!) do (
  22.        if %%j equ 2 (
  23.           set /a yue2="^!(%%i%%4)&^!(^!(%%i%%100))|^!(%%i%%400)"+28,mh=yue2
  24.         ) else set /a mh=yue%%j
  25.        if defined flag if %%j equ !yuh! set /a mh=100!js:~-2!%%100
  26.        for /l %%k in (!mq! 1 !mh!) do (
  27.           set numd=0%%j&set "numm=0%%k"
  28.           echo %%i!numd:~-2!!numm:~-2!
  29.         )
  30.        set /a mq=1&echo;
  31.      )
  32.      set yuq=1
  33. )
  34. echo 耗时:
  35. echo %t%
  36. echo !time!
  37. )>c.txt
  38. start c.txt
  39. exit
复制代码

[ 本帖最后由 FOR 于 2010-4-7 23:22 编辑 ]

TOP

  对第2点做稍许变动:如果只输入一个日期,则和系统当前日期做比较,以较早的日期为起点,较晚的日期为终点,按照第1条的要求输出数据。
尺有所短寸有所长,学好批处理没商量;
考虑问题复杂化,解决问题简洁化。

心在天山,身老沧州。

TOP

  hanyeguxing在4楼的代码没有做准确的平年闰年检测;FOR在7楼的代码输出的格式为 2010-4-1 ,由于未做充分测试,其他问题尚未发现。
尺有所短寸有所长,学好批处理没商量;
考虑问题复杂化,解决问题简洁化。

心在天山,身老沧州。

TOP

输出格式已改,但对系统日期作统一处理不会。

TOP

Re FOR:
  运行了你修改后的代码,发现生成350多K的数据竟然只花费了0秒——嘿嘿,貌似 echo %time% 要改成 call echo %%time%% 才对。
尺有所短寸有所长,学好批处理没商量;
考虑问题复杂化,解决问题简洁化。

心在天山,身老沧州。

TOP

改成了 echo !time! 发现把输出格式改了后,多运行了一句set numd=0%%j&set "numm=0%%k" 速度居然到了3秒多

TOP

原帖由 namejm 于 2010-4-7 22:58 发表
  hanyeguxing在4楼的代码没有做准确的平年闰年检测;FOR在7楼的代码输出的格式为 2010-4-1 ,由于未做充分测试,其他问题尚未发现。

判定公历闰年遵循的一般规律为: 四年一闰,百年不闰,四百年再闰.
崩溃。。。。。。。光记得4年的事了,其他的不是忘记了,而是根本就不知道,汗一个。。。

[ 本帖最后由 hanyeguxing 于 2010-4-7 23:27 编辑 ]
寒夜孤星:在没有说明的情况下,本人所有代码均运行在 XP SP3 下 (有问题请发贴,QQ临时会话已关闭)

TOP

4 楼还有起始月输出不正确的问题:
  1. e=!m:~%n%,2!
复制代码
如此截取是有问题的

TOP

借鉴了 4 楼日数序列的方法, 效率仍不高, 看来可看下 FOR 的思路并尝试
  1. @echo off&setlocal enabledelayedexpansion
  2. (set days=312831303130313130313031)
  3. set /p ymds=请输入起始日期(yyyymmdd),要使用系统当前日期,请直接回车:
  4. set /p ymde=请输入截止日期(yyyymmdd),要使用系统当前日期,请直接回车:
  5. if not defined ymds (set ymds=%date:~0,4%%date:~5,2%%date:~8,2%)
  6. if not defined ymde (set ymde=%date:~0,4%%date:~5,2%%date:~8,2%)
  7. if "!ymde!" lss "!ymds!" (
  8.   (set tt=!ymde!)&(set ymde=!ymds!)&(set ymds=!tt!)
  9. )
  10. (set y=!ymds:~0,4!)&(set m=!ymds:~4,2!)&(set d=!ymds:~6,2!)
  11. set /a "y=1!y!-10000, m=1!m!-100, d=1!d!-100"
  12. echo 起始日期为:!y!-!m!-!d!, 截止日期为:!ymde!
  13. (set /a index=m*2-2)& for %%i in (!index!) do set dmax=!days:~%%i,2!
  14. if !m!==2 set /a "dmax+=(^!(y%%4)&^!^!(y%%100))|^!(y%%400)"
  15. (set _y=000!y!)&(set _y=!_y:~-4!)&(set _m=0!m!)&(set _m=!_m:~-2!)
  16. :loop
  17. (set _d=0!d!)&(set _d=!_d:~-2!)
  18. if "!_y!!_m!!_d!" leq "!ymde!" (echo !_y!!_m!!_d!) else goto :break
  19. set /a d+=1
  20. if !d! gtr !dmax! (
  21.   (set d=1)&(set /a m+=1)
  22.   if !m! gtr 12 (set m=1)&(set /a y+=1)&(set _y=000!y!)&(set _y=!_y:~-4!)
  23.   (set _m=0!m!)&(set _m=!_m:~-2!)  
  24. (set /a index=m*2-2)& for %%i in (!index!) do set dmax=!days:~%%i,2!
  25. if !m!==2 set /a "dmax+=(^!(y%%4)&^!^!(y%%100))|^!(y%%400)"
  26. )
  27. goto :loop
  28. :break
  29. pause
复制代码

TOP

原帖由 neorobin 于 2010-4-7 23:43 发表
4 楼还有起始月输出不正确的问题:e=!m:~%n%,2!如此截取是有问题的

没明白。。。能不能具体说一下?
寒夜孤星:在没有说明的情况下,本人所有代码均运行在 XP SP3 下 (有问题请发贴,QQ临时会话已关闭)

TOP

返回列表