Board logo

标题: 批处理版万年历 [打印本页]

作者: zjl5     时间: 2007-5-26 20:43    标题: 批处理版万年历

────────── 版主提示 ──────────
完善后的代码请看20楼 qzwqzw 的脚本
────────── 版主提示 ──────────


::算法:基姆拉尔森计算公式
::W= (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400) mod 7
::在日历里面★=当天
::还没有加入闰年的计算.所以所有的2月都是28天
@echo off& color 27 & mode con cols=40 lines=20 & title 日历,泛滥棏慌°制作.QQ:173459058&&setlocal enabledelayedexpansion
set dated=%date%
:home
cls&echo/
set zdate=%date%
set y=%zdate:~0,4%
set m=%zdate:~5,2%
set d=%date:~8,2%
if %d% geq 32 (echo 错误的日期.&pause>nul&exit)
set d1=01
if "%m%"=="01" (set /a y-=1& set /a m+=12)
if "%m%"=="02" (set /a y-=1& set /a m+=12)
::计算星期公式
set /a w=(%d1%+2*%m%+3*(%m%+1)/5+%y%+%y%/4-%y%/100+%y%/400)%%7+1
set /a ww=(%d%+2*%m%+3*(%m%+1)/5+%y%+%y%/4-%y%/100+%y%/400)%%7+1
set 1=一&set 2=二&set 3=三&set 4=四&set 5=五&set 6=六&set 7=日
if "%date%"=="%dated%" (
echo    这是%date:~0,4%年%date:~5,2%月日历 今天:%dated:~0,4%!-%dated:~5,2%-%dated:~8,2%
) else (
echo    这是%date:~0,4%年%date:~5,2%月日历    ★=当天
echo    你查询的日期是:%date%,星期!%ww%!
)
::还没有加入闰年的计算.所以所有的2月都是28天
set %m%m=31&set %m%m=28&set %m%m=31&set %m%m=30&set %m%m=31&set %m%m=30
set %m%m=31&set %m%m=31&set %m%m=30&set %m%m=31&set %m%m=30&set %m%m=31
set /a cyc=!%m%m!+%w%-1
set n=0
for /l %%i in (0,1,40) do (set w%%i=  )
for /l %%i in (%w%,1,%cyc%) do (
set /a n+=1
set w%%i=0!n!
if !n! GEQ 10 set w%%i=!n!
if !n! EQU !d! set w%%i=★
)
echo/
echo     日   一   二   三   四   五   六
echo ━━━━━━━━━━━━━━━━━━━━
echo     %w0%   %w1%   %w2%   %w3%   %w4%   %w5%   %w6%
echo.
echo     %w7%   %w8%   %w9%   %w10%   %w11%   %w12%   %w13%
echo.
echo     %w14%   %w15%   %w16%   %w17%   %w18%   %w19%   %w20%
echo.
echo     %w21%   %w22%   %w23%   %w24%   %w25%   %w26%   %w27%
echo.
echo     %w28%   %w29%   %w30%   %w31%   %w32%   %w33%   %w34%
echo ━━━━━━━━━━━━━━━━━━━━
echo 输入年月日,可以看当月日历及显示当日星期
set /p date=格式如(2007-02-03)-[E]退出:
if /i "%date%"=="E" exit
goto :home
[ Last edited by bjsh on 2007-7-31 at 02:36 PM ]
作者: lxmxn     时间: 2007-5-26 20:51
不错,加上判断是否闰年的功能就更加完美了。
作者: ieutk     时间: 2007-5-27 14:30
要是能查到农历就更好啦!哈~
作者: qzwqzw     时间: 2007-5-27 15:12
试了试

除了2006-12这样的31天月份显示30天之外

其它月份都显示31天

问题出在这句
set %m%m=31&set %m%m=28&set %m%m=31&set %m%m=30&set %m%m=31&set %m%m=30
set %m%m=31&set %m%m=31&set %m%m=30&set %m%m=31&set %m%m=30&set %m%m=31
还需要继续努力啊
作者: my3439955     时间: 2007-5-27 16:13
这个日历也不错
http://www.cn-dos.net/forum/viewthread.php?tid=27739&fpage=11

还可以支持任意年包括闰年
http://www.cn-dos.net/forum/view ... mp;page=2#pid195566

[ Last edited by my3439955 on 2007-5-27 at 04:20 PM ]
作者: my3439955     时间: 2007-5-27 16:23


  Quote:
Originally posted by ieutk at 2007-5-27 14:30:
要是能查到农历就更好啦!哈~

农历没有规则的公式,只能推算出一段时间然后进行查表
不信的话看看那些支持农历的万年历
农历的支持一般不会超过200年
公历的话就没有这个限制
可以到任意年
作者: zjl5     时间: 2007-5-27 17:45


  Quote:
Originally posted by qzwqzw at 2007-5-27 03:12 PM:
试了试

除了2006-12这样的31天月份显示30天之外

其它月份都显示31天

问题出在这句
[code]
set %m%m=31&set %m%m=28&set %m%m=31&set %m%m=30&set %m%m ...

谢谢qzwqzw大哥帮忙测试,我考虑好了把修改后的再发上来.
作者: qzwqzw     时间: 2007-5-27 18:14
农历这个东西,也许有不查表的办法

听我父亲说,原来家乡有一个二楞子

平时疯疯颠颠的

但唯独掌握一门“神技”十分让人佩服

那就是它可以将古往今来五百年来的老皇历默熟于心

农历大小月以及闰月等问题对他根本不是问题

我未见其人,至今不知道他采用的是什么办法

---------------------------------------------------------

从理性角度考虑

现如今所使用的农历

虽然是经过多少朝代历次修订而最终成制的

但最终仍然来源于最早的夏历

而夏历的修订和完善主要依赖于天文学的研究成果

除此而外,应该有纯数学的办法可以计算和预期

[ Last edited by qzwqzw on 2007-5-27 at 06:17 PM ]
作者: zjl5     时间: 2007-5-27 19:50
qzwqzw兄,我把中间的一部分
set %m%m=31&set %m%m=28&set %m%m=31&set %m%m=30&set %m%m=31&set %m%m=30
set %m%m=31&set %m%m=31&set %m%m=30&set %m%m=31&set %m%m=30&set %m%m=31
set /a cyc=!%m%m!+%w%-1
改成了
for %%i in (04 06 09 11) do if "%m%"=="%%i" set flag=1
if defined flag (set cyc1=30) else (set cyc1=31)
set /a leap=%y%%%4
if %m% equ 2 set cyc1=28
if %leap% EQU 0 (if %m% EQU 2 set cyc1=29)
set /a cyc=%cyc1%+%w%-1
效果没有得到太大改善,更大的问题似乎出在for /l %%i in (%w%,1,%cyc%)
我实在想不出.请帮忙改善.
作者: qzwqzw     时间: 2007-5-28 00:29
主要问题在于公式计算的星期顺序和日历显示的星期顺序并不一致

公式计算以星期一起始,星期日结束

日历显示则恰好相反

解决的办法很简单

将公式计算顺序或者日历显示顺序任意调换一个即可

调换公式的星期顺序,只要那句+1移到括号中即可

------------------------------------

另外,2006-12月的问题解决

需要再加一行显示,并同时再增加两个变量

-------------------------------------

其它还有一些问题

比如 if %d% geq 32 中的裸露变量

比如变量 m / d的0前缀问题

再就是变量的命名规范问题

---------------------------------------------

下面是我的代码
@echo off& color 27 & mode con cols=40 lines=20 && setlocal enabledelayedexpansion
set sdate=%date%
:home
cls&echo.
for /f "tokens=1,2,3 delims=-/: " %%i in ("%sdate%") do (
    (set sy=%%i) && (set sm=%%j) && (set sd=%%k)
)
(set sm=10%sm%) && (set sd=10%sd%)
(set sm=%sm:~-2%) && (set sd=%sd:~-2%)
set /a m=1%sm%-100, d=1%sd%-100
if %m% geq 13 (echo.错误的日期.&pause>nul&goto :eof)
if %d% geq 32 (echo.错误的日期.&pause>nul&goto :eof)
set fd=01
set y=%sy%
set /a leap="^!(y %% 4) & ^!(^!(y %% 100)) | ^!(y %% 400)"
::计算星期公式
if 1%m% leq 12 (set /a y-=1& set /a m+=12)
set /a begin=(fd+2*m+3*(m+1)/5+y+y/4-y/100+y/400+1)%%7
set /a week=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400+1)%%7

set weektbl=日一二三四五六七
set prmt=当天
if "%sdate%"=="%date%" set prmt=今天
echo.   %sy%年%sm%月 %prmt%:%sy%-%sm%-%sd%, 星期!weektbl:~%week%,1!

set /a flag=0, n=0
for %%i in (4 6 9 11) do if "%m%"=="%%i" set flag=1
set /a len=31 - flag
if "%m%"=="14" set /a len=28+leap
for /l %%i in (0,1,36) do (set w%%i=  )
set /a end=%len%+%begin%-1
for /l %%i in (%begin%,1,%end%) do (
    set /a n+=1
    set temp=0!n!
    set w%%i=!temp:~-2!
    if !n! EQU !d! set w%%i=★
)
echo.
echo.    日   一   二   三   四   五   六
echo.━━━━━━━━━━━━━━━━━━━━
echo.    %w0%   %w1%   %w2%   %w3%   %w4%   %w5%   %w6%
echo.
echo.    %w7%   %w8%   %w9%   %w10%   %w11%   %w12%   %w13%
echo.
echo.    %w14%   %w15%   %w16%   %w17%   %w18%   %w19%   %w20%
echo.
echo.    %w21%   %w22%   %w23%   %w24%   %w25%   %w26%   %w27%
echo.
echo.    %w28%   %w29%   %w30%   %w31%   %w32%   %w33%   %w34%
echo.
echo.    %w35%   %w36%
echo.━━━━━━━━━━━━━━━━━━━━
echo.输入年月日,可以看当月日历及显示当日星期
set sdate=
set /p sdate=格式如(2007-02-03)-[回车]退出:
if /i "%sdate%"=="" goto :eof
goto :home

作者: zjl5     时间: 2007-5-28 00:57
谢谢,,这样才够完美.
作者: namejm     时间: 2007-6-2 23:38
  在10楼的基础上,修改了一下,得到如下代码,效果的改变如下:

  1、日期数位置固定,星期数序列动态变化;

  2、10以内的日期前面不带0;

  3、再次输入当天日期的话,会一直显示“今天”而不是“当天”;
@echo off
:: 算法:基姆拉尔森计算公式
:: W= (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400) mod 7
:: 把一月和二月看成是上一年的十三月和十四月
:: 例:如果是2004-1-10则换算成:2003-13-10来代入公式计算。
color 27
mode con cols=40 lines=20
setlocal enabledelayedexpansion
set str=一二三四五六日一二三四五六日
set sdate=%date%

:Main
cls&echo.
:: 提取日期并查错
for /f "tokens=1,2,3 delims=-/: " %%i in ("%sdate%") do (
    (set sy=%%i) && (set sm=%%j) && (set sd=%%k)
)
(set sm=10%sm%) && (set sd=10%sd%)
(set sm=%sm:~-2%) && (set sd=%sd:~-2%)
set /a m=1%sm%-100, d=1%sd%-100
if %m% geq 13 (echo.错误的日期.&pause>nul&goto :eof)
if %d% geq 32 (echo.错误的日期.&pause>nul&goto :eof)

:: 计算每个月的日期数
set max=31
for %%i in (4 6 9 11) do if %m% equ %%i set max=30
:: 计算2月份的偏差
if %m% leq 2 (set /a y-=1& set /a m+=12)
set /a leap="^!(y%%4) & ^!(^!(y%%100)) | ^!(y%%400)"
if %m% equ 14 set /a max=28+%leap%

:: 计算指定日期的星期数
set /a w=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400)%%7

:: 计算动态星期数序列
set /a num=w-(d%%7-1)
set var=!str:~%num%,1!
for /l %%i in (0,1,6) do (
    set var_tmp=!str:~%%i,1!
    if "!var!"=="!var_tmp!" set var=!str:~%%i,7!
)


set prmt=当天
if "%sy%-%sm%-%sd%"=="%date%" set prmt=今天
echo.   %sy%年%sm%月 %prmt%:%sy%-%sm%-%sd%,星期!str:~%w%,1!
echo.

:: 生成表头的星期数序列
for /l %%i in (0,1,6) do set /p=   !var:~%%i,1!<nul

:: 生成日期数序列
echo.
echo ━━━━━━━━━━━━━━━━━━━━
for /l %%i in (1,1,%max%) do (
    set /a num=%%i%%7
    set var= %%i
    set var=!var:~-2!
    if %d% equ %%i (
        set /p=   ★<nul
    ) else set /p=   !var!<nul
    if !num! equ 0 echo.&echo.
)
echo.
echo ━━━━━━━━━━━━━━━━━━━━
echo.输入年月日,可以看当月日历及显示当日星期
set sdate=
set /p sdate=格式如(2007-02-03)-[回车]退出:
if not defined sdate exit
goto Main
[ Last edited by namejm on 2007-6-2 at 11:50 PM ]
作者: qzwqzw     时间: 2007-6-3 00:07
这种显示方式并不符合日常习惯

估计很难被人接受

如果不想使用过多的变量

可以使用for将日期顺序输出

只要控制好换行的时机就没有什么问题

另外最好可以控制一下年份的范围和格式

最多只需输入两位年份数

50~99判定为19xx
00~49判定为20xx

计算太远的星期没有太多意义
作者: namejm     时间: 2007-6-3 00:15
  动态显示星期序列的做法确实是不太合乎习惯,刚才觉得这个很有意思,就拿来改编了一下,呵呵,仅作为一种新效果而推出。

  "计算太远的星期没有太多意义" 这句话不知道指的是什么,暂时没有什么过多的想法,若有什么有意思的想法的话,我也想听听^_^。
作者: qzwqzw     时间: 2007-6-3 02:16
例如以下代码的效果
@echo off
:: 算法:基姆拉尔森计算公式
:: W= (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400) mod 7
:: 把一月和二月看成是上一年的十三月和十四月
:: 例:如果是2004-1-10则换算成:2003-13-10来代入公式计算。
color 27
mode con cols=40 lines=20
setlocal enabledelayedexpansion
set str=日一二三四五六
set prmt=今天
set sdate=%date%

:Main
cls&echo.
:: 日期提取、格式化与校验
for /f "tokens=1,2,3 delims=-/: " %%i in ("%sdate%") do (
    (set sy=%%i) && (set sm=%%j) && (set sd=%%k)
)
(set sy=00%sy%) && (set sm=10%sm%) && (set sd=10%sd%)
(set sy=%sy:~-2%) && (set sm=%sm:~-2%) && (set sd=%sd:~-2%)
set /a y=1%sy%-100, m=1%sm%-100, d=1%sd%-100
if %y% lss 50 (set /a y+=2000) else (set /a y+=1900)
set sy=%y%
if %m% geq 13 (echo.错误的日期.&pause>nul&goto :eof)
if %d% geq 32 (echo.错误的日期.&pause>nul&goto :eof)

:: 计算每个月的天数
set days=31
for %%i in (4 6 9 11) do if %m% equ %%i set days=30
:: 计算2月份的偏差
set /a leap="^!(y%%4) & ^!(^!(y%%100)) | ^!(y%%400)"
if %m% equ 2 set /a days=28+%leap%
if %m% leq 2 (set /a y-=1& set /a m+=12)
:: 计算指定日期的星期数
set /a w=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400+1)%%7

echo.   %sy%年%sm%月  %prmt%:%sy%-%sm%-%sd%,星期!str:~%w%,1!
echo.

:: 生成日期数序列
set /a wb=(w+35-d) %% 7, we=wb+days+1, day=1
echo.    日   一   二   三   四   五   六
echo. ━━━━━━━━━━━━━━━━━━━
set /p= <nul
for /l %%i in (0,1,36) do (
    set "temp=  "
    if %%i GTR %wb% if %%i LSS %we% (
        set temp=0!day!
        set temp=!temp:~-2!
        if !d! EQU !day! set temp=★
        set /a day+=1
    )
    set /p=   !temp!<nul
    set /a "wm=(%%i+1)%%7"
    if !wm! equ 0 echo.&echo.&set /p= <nul
)
echo.
echo  ━━━━━━━━━━━━━━━━━━━
echo. 输入日期可以看当月日历及显示当日星期
echo.
set sdate=
set /p sdate= 格式如:07-02-03,[回车]退出:
set prmt=当天
if defined sdate goto Main

作者: Michael     时间: 2007-6-3 11:16


  Quote:
Originally posted by qzwqzw at 2007-5-27 06:14 PM:
农历这个东西,也许有不查表的办法

听我父亲说,原来家乡有一个二楞子

平时疯疯颠颠的

但唯独掌握一门“神技”十分让人佩服

那就是它可 ...

唯一的办法就是教会你家乡的“二愣子”学会批处理。呵呵。
作者: namejm     时间: 2007-6-3 13:32
  发个使用更加方便一点的代码,对日历多余的空行做删除处理,修正了15楼代码中查询2007年7月份时只有30天的错误,此错误是由于当月1日正好是星期日、而37次循环只能扫描到30日引起的,更多的改变请看代码说明。
@echo off
:: 算法:基姆拉尔森计算公式
:: W= (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400) mod 7
:: 把一月和二月看成是上一年的十三月和十四月
:: 例:如果是2004-1-10则换算成:2003-13-10来代入公式计算。

:: 输入的日期格式为:年-月-日(-可以替换为:、/,可以混用)
:: 在日历里面,★=当天

:: 支持多种格式的日期输入:
:: ① 若只输入一个数,则认为是查询当年月份,自动截取后两位数字查询,★标在1日上;
:: ② 若输入两个数,则认为是查询年和月,★标在1日上;
:: ③ 输全的话,★标在指定日期上

:: 关于年份的转换:
:: ① 若年份上输入的是两位数,则作如下转换:
::     50~99判定为19xx
::     00~49判定为20xx
:: ② 若输入的年份不是两位的,则把年份前面的所有0去掉之后,
::    计算该年份的日期;

color 27
mode con cols=40 lines=20
setlocal enabledelayedexpansion
set str=日一二三四五六
set sdate=%date%

:Main
cls&echo.
:: 日期提取、格式化与校验
for /f "tokens=1,2,3 delims=-/: " %%i in ("%sdate%") do (
    (set sy=%%i) && (set sm=%%j) && (set sd=%%k)
)
if not defined sd set sd=1
if not defined sm set sm=%sy%& set sy=%date:~0,4%
(set sm=10%sm%) && (set sd=10%sd%)
(set sm=%sm:~-2%) && (set sd=%sd:~-2%)
set y=%sy%
set /a m=1%sm%-100, d=1%sd%-100
if not "%sy:~2%"=="" goto check
if "%sy:~1%"=="" goto check
set sy=00%sy%
set sy=%sy:~-2%
set /a y=1%sy%-100
if %y% lss 50 (set /a y+=2000) else (set /a y+=1900)
set sy=%y%
:check
for %%i in (%y% %m% %d%) do (
    if %%i equ 0 echo.错误的日期.&pause>nul&set sdate=%date%&goto Main
)
for /f "delims=0 tokens=*" %%i in ("%sy%") do set /a sy=%%i,y=%%i
if %m% geq 13 (echo.错误的日期.&pause>nul&set sdate=%date%&goto Main)
if %d% geq 32 (echo.错误的日期.&pause>nul&set sdate=%date%&goto Main)

:: 计算每个月的天数
set days=31
for %%i in (4 6 9 11) do if %m% equ %%i set days=30
:: 计算2月份的偏差
set /a leap="^!(y%%4) & ^!(^!(y%%100)) | ^!(y%%400)"
if %m% equ 2 set /a days=28+%leap%
if %m% leq 2 (set /a y-=1& set /a m+=12)
:: 计算指定日期的星期数
set /a w=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400+1)%%7
::set /a w=(%d%+2*%m%+3*(%m%+1)/5+%y%+%y%/4-%y%/100+%y%/400+1)%%7

set prmt=当天
if "%sy%-%sm%-%sd%"=="%date%" set prmt=今天
echo.   %sy%年%sm%月  %prmt%:%sy%-%sm%-%sd%,星期!str:~%w%,1!
echo.

:: 生成日期数序列
set /a wb=(w+35-d) %% 7, we=wb+days+1, day=1
echo.    日   一   二   三   四   五   六
echo. ━━━━━━━━━━━━━━━━━━━
set /p= <nul
if %wb% equ 6 (set begin=7) else set begin=0
for /l %%i in (%begin%,1,37) do (
    set "temp=  "
    if %%i GTR %wb% if %%i LSS %we% (
        set temp= !day!
        set temp=!temp:~-2!
        if !d! EQU !day! set temp=★
        set /a day+=1
    )
    set /p=   !temp!<nul
    if !day! gtr !days! goto end
    set /a "wm=(%%i+1)%%7"
    if !wm! equ 0 echo.&echo.&set /p= <nul
)
:end
echo.
echo  ━━━━━━━━━━━━━━━━━━━
echo. 输入日期可以看当月日历及显示当日星期
echo.
set sdate=
set /p sdate= 格式如:07-02-03,[回车]退出:
if defined sdate goto Main
[ Last edited by namejm on 2007-6-3 at 02:50 PM ]
作者: qzwqzw     时间: 2007-6-3 14:25
2007年7月的问题我注意到了

不过那时已没有时间改了
----------------------------------

空行的删除会让提示信息和输入日期为止频繁变动

对排版效果的改善起不到积极作用

所以我没有考虑
----------------------------------
日期格式化检查部分的改动比较乱

输入7-6-3得到的是7-06-03(年份没有格式化)

输入0得到的是2007-00-01(月份没有校验)

月与日的缺省值原本是10月/10日

只是考虑到实现起来比较简单
----------------------------------
当日/今日的显示

现在觉得意义不大

尤其是与带星期的%date%比较

[ Last edited by qzwqzw on 2007-6-3 at 02:33 PM ]
作者: namejm     时间: 2007-6-3 14:57


  Quote:
Originally posted by qzwqzw at 2007-6-3 14:25:
输入7-6-3得到的是7-06-03(年份没有格式化)

  想把这个代码做成万年历,7年表示公元7年,所以没法格式化。

  Quote:
输入0得到的是2007-00-01(月份没有校验)

  17楼的代码已经添加了对日期和月份为0时的检测。

  Quote:
当日/今日的显示
现在觉得意义不大
尤其是与带星期的%date%比较

  碰到带星期格式的%date%,确实比较令人头痛,提取时间的代码很难做到完全兼容。另外,日期分隔符也可以人为指定,这就更难以兼容了。
作者: qzwqzw     时间: 2007-6-3 15:36
已经说过了,万年历没有太多意义

有谁会查公元元年的星期呢?

那时候都甚至没有格里高利历法

如果真想做专业的年表

那就需要连公元前一起考虑

谁知道这个公式在公元前是否仍然适用

而且你的代码也已经加入了0~55的判断

那就说明也默认了0~55是+了2000年的
----------------------------------------------------

将日期格式化校验代码简化后如下
:: 月历查询工具 中国DOS联盟专用版 转载请注明版权
:: 原创:zjl5  更新:namejm, qzwqzw 2007-06-03

:: 算法:基姆拉尔森计算公式
:: W= (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400) mod 7
:: 把一月和二月看成是上一年的十三月和十四月
:: 例:如果是2004-1-10则换算成:2003-13-10来代入公式计算。

:: 输入的日期格式为:年-月-日(-可以替换为:、/,可以混用)
:: 在日历里面,★=当天

:: 支持多种格式的日期输入:
:: ① 若只输入一个数,则认为是查询当年月份,自动截取后两位数字查询,★标在1日上;
:: ② 若输入两个数,则认为是查询年和月,★标在1日上;
:: ③ 输全的话,★标在指定日期上

:: 关于年份的转换:
:: ① 若年份上输入的数字少于三位,则作如下转换:
::     50~99判定为19xx
::     0~49判定为20xx
:: ② 若输入的年份数字超过两位,则截取后四位字符(不足部分在高位补0),
::    按 ① 的规则计算该年份的日期;

@echo off
color 3F
mode con cols=40 lines=20
setlocal enabledelayedexpansion
set str=日一二三四五六
set sdate=%date%

:Main
cls&echo.
:: 日期提取、格式化与校验
for /f "tokens=1,2,3 delims=-/: " %%i in ("%sdate%") do (
    (set sy=%%i) && (set sm=%%j) && (set sd=%%k)
)
if not defined sd set sd=1
if not defined sm set sm=%sy%& set sy=%date:~0,4%

(set sy=0000%sy%) && (set sm=00%sm%) && (set sd=00%sd%)
(set sy=%sy:~-4%) && (set sm=%sm:~-2%) && (set sd=%sd:~-2%)
cd.
set /a y=1%sy%-10000, m=1%sm%-100, d=1%sd%-100 2>nul
if errorlevel 1 goto Error
if %y% lss 100 (
    if %y% lss 50 (set /a y+=2000) else (set /a y+=1900)
    set sy=!y!
)
if %m% lss 13 if %d% lss 32 goto Calc

:Error
echo.错误的日期.
pause>nul
set sdate=%date%
goto Main

:Calc
:: 计算每个月的天数
set days=31
for %%i in (4 6 9 11) do if %m% equ %%i set days=30
:: 计算2月份的偏差
set /a leap="^!(y%%4) & ^!(^!(y%%100)) | ^!(y%%400)"
if %m% equ 2 set /a days=28+%leap%
if %m% leq 2 (set /a y-=1& set /a m+=12)
:: 计算指定日期的星期数
set /a w=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400+1)%%7

echo.  %sy%年%sm%月  查询日:%sy%-%sm%-%sd%,星期!str:~%w%,1!
echo.
:: 生成月历
set /a wb=(w+35-d) %% 7, we=wb+days+1, day=1
echo.    日   一   二   三   四   五   六
echo. ━━━━━━━━━━━━━━━━━━━
set /p= <nul
for /l %%i in (0,1,37) do (
    set "temp=  "
    if %%i GTR %wb% if %%i LSS %we% (
        set temp= !day!
        set temp=!temp:~-2!
        if !d! EQU !day! set temp=★
        set /a day+=1
    )
    set /p=   !temp!<nul
    set /a "wm=(%%i+1)%%7"
    if !wm! equ 0 echo.&echo.&set /p= <nul
)
echo.
echo  ━━━━━━━━━━━━━━━━━━━
echo.  输入日期可查询当日星期并显示当月月历
echo.
set sdate=
set /p sdate=  格式如:07-02-03,[回车]退出:
if defined sdate goto Main
[ Last edited by qzwqzw on 2007-8-5 at 06:48 PM ]
作者: namejm     时间: 2007-6-3 16:10


  Quote:
Originally posted by qzwqzw at 2007-6-3 15:36:
已经说过了,万年历没有太多意义
有谁会查公元元年的星期呢?
那时候都甚至没有格里高利历法

  呵呵,万年历确实没太多的意义,我就把它当作游戏来做吧^_^。

  Quote:
而且你的代码也已经加入了0~55的判断
那就说明也默认了0~55是+了2000年的

  实际上,在我的代码里,我加的是00~55的判断,并非0~55,所以,如果要让脚本自动加上19或20的前缀的话,就要输入两位数的年份。

  20楼的代码充分考虑了大众的阅读习惯和查询习惯,并对日期做了格式化处理,已经非常完善了。只是关于年份转换的那部分说明,直接从我那段代码里复制过来,所描述的效果和你的代码功能不完全吻合,建议把它改成这样:

  Quote:
:: 关于年份的转换:
:: ① 若年份上输入的数字少于三位,则作如下转换:
::     50~99判定为19xx
::     0~49判定为20xx
:: ② 若输入的年份数字超过两位,则截取后四位字符(不足部分在高位补0),
::    按 ① 的规则计算该年份的日期;


作者: qzwqzw     时间: 2007-6-3 22:16
多谢指出

已经修正
作者: zjl5     时间: 2007-6-16 03:05
还是找不到算农历的方法,只能算出生肖和农历干支年.
@echo off&setlocal enabledelayedexpansion
set sx=猴鸡狗猪鼠牛虎兔龙蛇马羊
set tg=庚辛壬癸甲乙丙丁戊己
set dz=申酉戌亥子丑寅卯辰巳午未
set /p year=请输入农历年:
set /a sxnum=%year% %% 12
set /a tgnum=%year:~-1%
echo/&echo %year%年生肖是:!sx:~%sxnum%,1!    农历 !tg:~%tgnum%,1!!dz:~%sxnum%,1! 年
echo/&echo 按任意键算出从1800-2500年中属!sx:~%sxnum%,1!的年份.
pause>nul&set n=1799&echo/
:a
set /a n+=1
set /a ynum=!n! %% 12
set /a tgnum=!n:~-1!
if !n! equ 2500 ECHO -结束,按任意键退出.&pause>nul&exit
if !ynum! equ !sxnum! (echo 属!sx:~%sxnum%,1!的年份还有 !n! 年    农历 !tg:~%tgnum%,1!!dz:~%ynum%,1! 年&goto :a) else (goto :a)

作者: whswbiori     时间: 2007-8-1 05:00
气氛真好 你们2个好活跃啊 看了3,4个帖子 都有你们
]
作者: kidzgy     时间: 2007-8-1 09:17
到底最完美一点的是拿一个啊?
作者: kidzgy     时间: 2007-8-1 09:21
20楼的,如果日期输入错误,会出现死循环。一直都是错误。
作者: qzwqzw     时间: 2007-8-1 10:15
请说详细些
输入什么样的错误日期?
在什么地方死循环?
作者: youxi01     时间: 2007-8-1 12:33
namejm兄和qzwqzw兄还有这么高的兴致啊,佩服ing
作者: kidzgy     时间: 2007-8-1 18:04


  Quote:
Originally posted by qzwqzw at 2007-8-1 10:15 AM:
请说详细些
输入什么样的错误日期?
在什么地方死循环?

我复制你的代码到bat中,不管输入什么,字母也好,按照你的格式输入也好,07-02-03都没有用,回车之后提示错误,此时按任意键回不了主菜单,造成一个死循环,一直停留在错误界面内,若不关闭的话。
作者: qzwqzw     时间: 2007-8-1 18:36
无法复现的你的错误
如果你懂得简单的批处理调试技巧的话
可以在代码的错误提示前
插入一条语句查看此时变量接受输入的结果

echo [%OS%][%date%][%sDate%][%y%=%m%=%d%]
作者: kidzgy     时间: 2007-8-2 07:19
我可是在20楼 点击 [Copy to clipboard]  复制到文本里去,然后改扩展名。

怎么会没有问题呢?你试着重新复制你自己的代码到bat中去,然后运行,输入里面所举的例子,会提示错误的。此时错误的界面一直是个循环,不管你按任意键,还是一样。
作者: qzwqzw     时间: 2007-8-2 07:55
应该是你的情况比较特殊一些
我和早前的namejm讨论都没有遇到这个问题
这次为了测试特意使用IE打开了这个页面
试了 [Copy to clipboard]  功能
也没有任何问题

所以请还是按照的建议插入调试语句看看结果再说
作者: frankkf     时间: 2007-8-2 13:31
[Copy to clipboard]  功能应该没问题
以前一些code我也用的是[Copy to clipboard]  功能

  Quote:
这次为了测试特意使用IE打开了这个页面

那qzwqzw用什么看网页?
firefox或者是opera?~~
作者: kidzgy     时间: 2007-8-2 16:47
http://upload.programfan.com/upfile/200708021645310.rar
你试试我这个,看看是不是有这个问题,我可是完全复制下来的哦。

随便打一个字,然后回车。提示“错误的日期.” 然后不管你按什么键是不会回到原来的界面的。
作者: qzwqzw     时间: 2007-8-3 07:03
非常感谢你的报告!
因此我又揭开了微软cmd的一个secret

解决你的问题方法很简单
请将你的代码文件扩展名改为.cmd
或者在代码中的set /a前加上一句 cd. 以复位错误号为0

==================================

现在描述一下解决问题的过程
首先下载到你的测试文件后
测试运行果然发现你所述的问题

然后我对问题代码与我的正常运行的源代码进行比较
发现问题代码分别在第2行和第一个goto Main所在行行尾多出两个空格
因为第2个空格位置的特殊性
我以为找到了问题所在

因为我使用的是EditPlus编辑源代码
它保存代码时会自动清除行尾的空格
而帖出去的代码很可能是因为使用了其它编辑器修改后多出来的

然而我在去除掉多余空格测试却发现问题依然存在
再次二进制比较两个代码文件的结果是完全一致

然后我开始漫长的跟踪调试
我发现问题代码总是在因为一次set /a的错误产生错误号9167后
不会再因为正确的set /a而复位错误号0
而正常代码就无此问题

经过再三的思索
终于确定这个问题与文件扩展名相关
也就是说,
在.bat文件中set 产生的错误总不会被set所复位
而在.cmd文件中则是可以的

以下是一段测试代码
将它分别保存为.bat和.cmd文件进行测试后发现
二者结果不同
至此问题基本明晰
@echo off
set /a ii=23 + 12
echo %errorlevel%.
set /a ii=23 + 09
echo %errorlevel%.
echo %errorlevel%.
set ii=23
echo %errorlevel%.
pause
但是至于这个问题的深层原因尚没有找到
这个留待有心人继续探索
而且我在EditPlus的工具栏中运行.bat文件并没有遇到此问题
作者: kidzgy     时间: 2007-8-3 20:04
那请你更新一下20楼的代码,以至于更完善一点。
不管在bat还是cmd中,能够保证正常运行就够了。
作者: kidzgy     时间: 2007-8-4 18:05
还是有错误,还是保存到BAT的时候,输入07-02-03提示错误。

我是复制20楼的代码到BAT中和CMD中分别测试的。
作者: qzwqzw     时间: 2007-8-4 19:02
问题已经查明
仍然是set的errorlevel问题

至于问题的细节
和代码的修改
就留给你当今晚的作业吧

也算考一考你对这个问题的认识
作者: kidzgy     时间: 2007-8-4 19:14
不会吧,我对批处理不是很熟悉啊,不像你们那么懂得资深。

如果叫我测试那还行,如果叫我修复问题,那简直是为难我。。
作者: zjl5     时间: 2007-8-4 23:20
qzwqzw兄可能太忙了...
我就针对症状改改吧.可能会引出更多的问题呵~`
另外加入了 针对农历的生肖和干支年计算.
:: 月历查询工具 中国DOS联盟专用版 转载请注明版权
:: 原创:zjl5  更新:namejm, qzwqzw 2007-06-03

:: 算法:基姆拉尔森计算公式
:: W= (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400) mod 7
:: 把一月和二月看成是上一年的十三月和十四月
:: 例:如果是2004-1-10则换算成:2003-13-10来代入公式计算。

:: 输入的日期格式为:年-月-日(-可以替换为:、/,可以混用)
:: 在日历里面,★=当天

:: 支持多种格式的日期输入:
:: ① 若只输入一个数,则认为是查询当年月份,自动截取后两位数字查询,★标在1日上;
:: ② 若输入两个数,则认为是查询年和月,★标在1日上;
:: ③ 输全的话,★标在指定日期上

:: 关于年份的转换:
:: ① 若年份上输入的数字少于三位,则作如下转换:
::     50~99判定为19xx
::     0~49判定为20xx
:: ② 若输入的年份数字超过两位,则截取后四位字符(不足部分在高位补0),
::    按 ① 的规则计算该年份的日期;

@echo off
color 3F
mode con cols=40 lines=20
setlocal enabledelayedexpansion
set str=日一二三四五六
set sdate=%date%

:Main
cls&echo.
:: 日期提取、格式化与校验
for /f "tokens=1,2,3 delims=-/: " %%i in ("%sdate%") do (
    (set sy=%%i) && (set sm=%%j) && (set sd=%%k))
if %sm% geq 13 (echo 错误的日期.&pause>nul&(set sdate=%date%)&pause>nul&goto :main)
if %sd% geq 32 (echo 错误的日期.&pause>nul&(set sdate=%date%)&pause>nul&goto :main)
if not defined sd set sd=1
if not defined sm set sm=%sy%& set sy=%date:~0,4%
(set sy=0000%sy%) && (set sm=00%sm%) && (set sd=00%sd%)
(set sy=%sy:~-4%) && (set sm=%sm:~-2%) && (set sd=%sd:~-2%)
set /a y=1%sy%-10000, m=1%sm%-100, d=1%sd%-100 2>nul
if %y% lss 100 (
    if %y% lss 50 (set /a y+=2000) else (set /a y+=1900)
    set sy=!y!
)
if %m% lss 13 if %d% lss 32 goto Calc

:Calc
set sx=猴鸡狗猪鼠牛虎兔龙蛇马羊
set tg=庚辛壬癸甲乙丙丁戊己
set dz=申酉戌亥子丑寅卯辰巳午未
set /a sxnum=%sy% %% 12
set /a tgnum=%sy:~-1%
title   农历!tg:~%tgnum%,1!!dz:~%sxnum%,1!年    生肖:!sx:~%sxnum%,1!
:: 计算每个月的天数
set days=31
for %%i in (4 6 9 11) do if %m% equ %%i set days=30
:: 计算2月份的偏差
set /a leap="^!(y%%4) & ^!(^!(y%%100)) | ^!(y%%400)"
if %m% equ 2 set /a days=28+%leap%
if %m% leq 2 (set /a y-=1& set /a m+=12)
:: 计算指定日期的星期数
set /a w=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400+1)%%7

echo.  %sy%年%sm%月  查询日:%sy%-%sm%-%sd%,星期!str:~%w%,1!
echo.
:: 生成月历
set /a wb=(w+35-d) %% 7, we=wb+days+1, day=1
echo.    日   一   二   三   四   五   六
echo. ━━━━━━━━━━━━━━━━━━━
set /p= <nul
for /l %%i in (0,1,37) do (
    set "temp=  "
    if %%i GTR %wb% if %%i LSS %we% (
        set temp= !day!
        set temp=!temp:~-2!
        if !d! EQU !day! set temp=★
        set /a day+=1
    )
    set /p=   !temp!<nul
    set /a "wm=(%%i+1)%%7"
    if !wm! equ 0 echo.&echo.&set /p= <nul
)
echo.
echo  ━━━━━━━━━━━━━━━━━━━
echo.  输入日期可查询当日星期并显示当月月历
echo.
set sdate=
set /p sdate=  格式如:07-02-03,[回车]退出:
if defined sdate goto Main

作者: zjl5     时间: 2007-8-5 01:21
奇怪%errorlevel%怎么会是9167,兄台解释一下,谢谢!!
因为没有编辑贴子的权限,所以又得另发一张了.
:: 月历查询工具 中国DOS联盟专用版 转载请注明版权
:: 原创:zjl5  更新:namejm, qzwqzw 2007-06-03

:: 算法:基姆拉尔森计算公式
:: W= (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400) mod 7
:: 把一月和二月看成是上一年的十三月和十四月
:: 例:如果是2004-1-10则换算成:2003-13-10来代入公式计算。

:: 输入的日期格式为:年-月-日(-可以替换为:、/,可以混用)
:: 在日历里面,★=当天

:: 支持多种格式的日期输入:
:: ① 若只输入一个数,则认为是查询当年月份,自动截取后两位数字查询,★标在1日上;
:: ② 若输入两个数,则认为是查询年和月,★标在1日上;
:: ③ 输全的话,★标在指定日期上

:: 关于年份的转换:
:: ① 若年份上输入的数字少于三位,则作如下转换:
::     50~99判定为19xx
::     0~49判定为20xx
:: ② 若输入的年份数字超过两位,则截取后四位字符(不足部分在高位补0),
::    按 ① 的规则计算该年份的日期;

@echo off
color 3F
mode con cols=40 lines=20
setlocal enabledelayedexpansion
set str=日一二三四五六
set sdate=%date%

:Main
cls&echo.
:: 日期提取、格式化与校验
for /f "tokens=1,2,3 delims=-/: " %%i in ("%sdate%") do (
    (set sy=%%i) && (set sm=%%j) && (set sd=%%k)
)
if not defined sd set sd=1
if not defined sm set sm=%sy%& set sy=%date:~0,4%

(set sy=0000%sy%) && (set sm=00%sm%) && (set sd=00%sd%)
(set sy=%sy:~-4%) && (set sm=%sm:~-2%) && (set sd=%sd:~-2%)
set /a y=1%sy%-10000, m=1%sm%-100, d=1%sd%-100 2>nul
if errorlevel 9167 goto Error
if %y% lss 100 (
    if %y% lss 50 (set /a y+=2000) else (set /a y+=1900)
    set sy=!y!
)
if %m% lss 13 if %d% lss 32 goto Calc

:Error
echo.错误的日期.
pause>nul
cd.
set sdate=%date%
goto Main

:Calc
set sx=猴鸡狗猪鼠牛虎兔龙蛇马羊
set tg=庚辛壬癸甲乙丙丁戊己
set dz=申酉戌亥子丑寅卯辰巳午未
set /a sxnum=%sy% %% 12
set /a tgnum=%sy:~-1%
title   农历!tg:~%tgnum%,1!!dz:~%sxnum%,1!年    生肖:!sx:~%sxnum%,1!
:: 计算每个月的天数
set days=31
for %%i in (4 6 9 11) do if %m% equ %%i set days=30
:: 计算2月份的偏差
set /a leap="^!(y%%4) & ^!(^!(y%%100)) | ^!(y%%400)"
if %m% equ 2 set /a days=28+%leap%
if %m% leq 2 (set /a y-=1& set /a m+=12)
:: 计算指定日期的星期数
set /a w=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400+1)%%7

echo.  %sy%年%sm%月  查询日:%sy%-%sm%-%sd%,星期!str:~%w%,1!
echo.
:: 生成月历
set /a wb=(w+35-d) %% 7, we=wb+days+1, day=1
echo.    日   一   二   三   四   五   六
echo. ━━━━━━━━━━━━━━━━━━━
set /p= <nul
for /l %%i in (0,1,37) do (
    set "temp=  "
    if %%i GTR %wb% if %%i LSS %we% (
        set temp= !day!
        set temp=!temp:~-2!
        if !d! EQU !day! set temp=★
        set /a day+=1
    )
    set /p=   !temp!<nul
    set /a "wm=(%%i+1)%%7"
    if !wm! equ 0 echo.&echo.&set /p= <nul
)
echo.
echo  ━━━━━━━━━━━━━━━━━━━
echo.  输入日期可查询当日星期并显示当月月历
echo.
set sdate=
set /p sdate=  格式如:07-02-03,[回车]退出:
if defined sdate goto Main

作者: qzwqzw     时间: 2007-8-5 18:47
9167是set /a因为无效数字(比如09)错误产生的errorlevel
需要注意的是set /p如果未获取到任何输入也会产生1的errorlevel
而且即使set /a和set /p再正常运行也不会复位早前的errorlevel

也就是说,在命令行或者.bat脚本中
set命令只有在运行出错时才会置errorlevel为非0值
在正确运行时是不会置0值的

而在.cmd脚本中
set在正确运行时是会置errorlevel为0值的
作者: sunny04551     时间: 2007-8-20 15:30
要是能查到农历就更好
作者: meicnk     时间: 2007-8-27 11:16
很好,收藏中
作者: hmilywenjia     时间: 2008-5-26 14:14
今天上来看到namejm的消息很是高兴啊,一直关注你的消息,你没事就好