找回密码
 注册
搜索
[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
查看: 319|回复: 8

[数值计算] 讨论:农历计算BAT出错,,讨论,原因,修正,,

[复制链接]
发表于 2026-3-2 18:25:03 | 显示全部楼层 |阅读模式
以前折腾过一个计算农历的BAT,后来被我整合到我私家的批处理工具箱里!
----------原版本:生肖,甲子,星期,农历---------
  1. setlocal enabledelayedexpansion
  2. set str=日一二三四五六七八九
  3. set sx=猴鸡狗猪鼠牛虎兔龙蛇马羊
  4. set tg=庚辛壬癸甲乙丙丁戊己
  5. set dz=申酉戌亥子丑寅卯辰巳午未
  6. set sdate=%date%
  7. for /f "tokens=1,2,3 delims=-/: " %%i in ("%sdate%") do ((set sy=%%i) && (set sm=%%j) && (set sd=%%k))
  8. if not defined sd set sd=1
  9. if not defined sm set sm=%sy%&set sy=%date:~0,4%
  10. (set sy=0000%sy%) && (set sm=00%sm%) && (set sd=00%sd%)
  11. (set sy=%sy:~-4%) && (set sm=%sm:~-2%) && (set sd=%sd:~-2%)
  12. set /a y=1%sy%-10000, m=1%sm%-100, d=1%sd%-100 2>nul
  13. if %y% lss 100 ( if %y% lss 50 (set /a y+=2000) else (set /a y+=1900)
  14. set sy=!y!)
  15. set/a Q=(y-1901)/4
  16. set/a R=y-1901-4*Q
  17. set n=0
  18. for %%i in (0,31,59,90,120,151,181,212,243,273,304,334) do (set /a n+=1
  19. if %m% equ !n! set z=%%i)
  20. set /a leap="^!(y%%4) & ^!(^!(y%%100)) | ^!(y%%400)"
  21. if %m% gtr 2 (if %leap% equ 0 (set /a z-=1) else (set /a z+=leap))
  22. set/a n=(140*Q+106*(R+1)+z*10+d*10)/295,H=(140*Q+106*(R+1)+z*10+d*10-295*n)/10
  23. if %h% equ 0 set h=29
  24. if %h% leq 10 (if %h% equ 10 (set h=初十) else (set h=初%h%)) else (set h=%h:~0,1%十%h:~-1%号)
  25. for /l %%i in (1,1,9) do (call set h=%%h:%%i=!str:~%%i,1!%%)
  26. set h=%h:0=%
  27. set /a sxnum=%sy% %% 12
  28. set /a tgnum=%sy:~-1%
  29. title 日期:%sy%-%sm%-%sd% 星期!str:~%w%,1! !tg:~%tgnum%,1!!dz:~%sxnum%,1!年 生肖:!sx:~%sxnum%,1! 农历:%h%
  30. set days=31
  31. for %%i in (4 6 9 11) do if %m% equ %%i set days=30
  32. set /a leap="^!(y%%4) & ^!(^!(y%%100)) | ^!(y%%400)"
  33. if %m% equ 2 set /a days=28+%leap%
  34. if %m% leq 2 (set /a y-=1& set /a m+=12)
  35. set /a w=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400+1)%%7
  36. echo. 日期:%sy%-%sm%-%sd% 星期!str:~%w%,1! !tg:~%tgnum%,1!!dz:~%sxnum%,1!年 生肖:!sx:~%sxnum%,1! 农历:%h%
  37. pause>nul
复制代码
由于我的个人原因,鄙人写BAT 不喜欢开启 延迟变量,,
--------下是被我修改过的无“延迟变量”版本,农历计算部分的计算代码---------
后来我把代码修改了,,,改成,,,,,,,,,,,
  1. Set/a y=1%date:~0,4%-10000, m=1%date:~5,2%-100, d=1%date:~8,2%-100
  2. Set/a Q=(y-1901)/4
  3. Set/a R=y-1901-4*Q
  4. If %m%==1 Set z=0
  5. If %m%==2 Set z=31
  6. If %m%==3 Set z=59
  7. If %m%==4 Set z=90
  8. If %m%==5 Set z=120
  9. If %m%==6 Set z=151
  10. If %m%==7 Set z=181
  11. If %m%==8 Set z=212
  12. If %m%==9 Set z=243
  13. If %m%==10 Set z=273
  14. If %m%==11 Set z=304
  15. If %m%==12 Set z=334
  16. Set/a leap="!(y%%4) & !(y%%100) | !(y%%400)"
  17. If %m% gtr 2 (If %leap% equ 0 (Set/a z-=1) else (Set/a z+=leap))
  18. Set/a n=(140*Q+106*(R+1)+z*10+d*10)/295,H=(140*Q+106*(R+1)+z*10+d*10-295*n)/10
  19. If %h% equ 0 Set h=29
  20. If %h% leq 10 (If %h% equ 10 (Set h=初十) else (Set h=初%h%)) else (Set h=%h:~0,1%十%h:~-1%号)
  21. Set h=%h:1=一%
  22. Set h=%h:2=二%
  23. Set h=%h:3=三%
  24. Set h=%h:4=四%
  25. Set h=%h:5=五%
  26. Set h=%h:6=六%
  27. Set h=%h:7=七%
  28. Set h=%h:8=八%
  29. Set h=%h:9=九%
  30. Set h=%h:0=%
  31. Set 农历=%h%
  32. echo.日期:%DATE%
  33. echo.农历:%农历%
  34. pause>nul
复制代码
以前使用的时候农历计算都基本能对得上,,,,
最后一次对的上农历是在上个月没过年前 农历十六号吧!,,
原版本(带延迟变量)和鄙人修改的(无延迟变量)版本都对得上,,
但是昨天发现农历少了一天,,,,
可能早就出现错误了,(公历2月换3月?或春节过后?)但是昨天才发现,,,,,
顺着计算公式查了半天,没弄明白是啥回事,,,
有大神们知道是啥情况不?讨论讨论呗,,,,
几年前用的时候基本都对得上啊!为什么就在这个2月份一过就出错了呢?折腾了好久也没弄明白,,。。
后来只有硬修改,把,Set/a n=(140*Q+106*(R+1)+z*10+d*10)/295,H=(140*Q+106*(R+1)+z*10+d*10-295*n)/10
核心计算公式,,,,硬桥硬码的加了个,,,
Set/a n=(140*Q+106*(R+1)+z*10+d*10)/295,H=((140*Q+106*(R+1)+z*10+d*10-295*n)/10)+1,,,修正值(也可以是个变量数),,,
农历是对得上了,,,可疑问依然纯在,,
之前问了不少A1,可他们给的答案都,,可能是没案例,没法完美解答吧,,,
或许是鄙人问的方法不对?,,各位出来讨论讨论呗。。。!


------------------------------------------------------------------
鄙人的私家批处理工具箱,重达 380多K,,里面塞满了,各种奇奇怪怪稀奇古怪的脚本和代码,有混编VBS,JS,HTA,Ps的,生成小程序的,也有折腾注册表的,加密解密,计算优化的各种各类都有,(调用第三方的也有,不计算在内),,
由于我写的主脚本,会多次重新调用各种标签和外调计算,也会在注册表和右键那里调用主脚本的计算公式或内里代码,,
开启“延迟变量”,会在各种标签跳跃和调用间出错和表达出错,符号出错,,所以,我写脚本的时候会尽量避开“延迟变量”,,,
我最常调用主脚本的功能有,截图折腾,换算折腾,文件折腾,系统折腾,服务折腾,右键折腾,加密折腾,资料折腾,,,各种折,各种腾,,,
心态老了,就只折腾这些怀旧代码,把“工具箱”一扔到U盘里,基本WIN PC 上很多疑难和设置都能搞定一半,现在只堆自己的小“工具箱”,,,,
发表于 2026-3-2 20:32:15 | 显示全部楼层
本帖最后由 aloha20200628 于 2026-3-2 21:11 编辑

回复 1# jiavip

是闰、平年的问题吧
2月份有多少天,要看这一年是不是闰年,闰年就是 2 月有 29 天,平年就是 2 月有 28 天
判断闰年 = 能被 4 整除但不能被 100 整除,或能被 400 整除
举例如下:
2024:能被 4 整除、不能被 100 整除,是闰年
1900:能被 100 整除、不能被 400 整除,是平年
2000:能被 400 整除,是闰年

参考》http://www.bathome.net/thread-70132-1-1.html
或有更多疑虑可拷问 ai ...
 楼主| 发表于 2026-3-2 21:38:32 | 显示全部楼层
回复 2# aloha20200628


    我知道!,,我只是想知道,为什么前几年都没出错,为什么这段时间出错了!,,(额,可能以前也出错过,但是那时候忙于生活没发现!)
我想知道的是  这个公式,它计算出错的部分!然后用修正变量去补足,,

我甚至还能给出一条Ps 的命令,但是我脚本的写法是想照顾没有 Ps的系统,,
  1. @echo off
  2. powershell -ExecutionPolicy Bypass -NoProfile -C "$a=[System.Globalization.ChineseLunisolarCalendar]::new();$b=Get-Date;$c=$a.GetYear($b);$d=$a.GetMonth($b);$e=$a.GetDayOfMonth($b);$f=$a.IsLeapMonth($c,$d);Write-Host('农历日期: {0} 年 {1} 月 {2} 日' -f $c, $d, $e) -ForegroundColor Green;if ($f) {Write-Host '闰月' -ForegroundColor Yellow}"
  3. pause>nul
复制代码
所谓的讨论意义就在这里,不是什么都靠 A1 ,而是用实在的讨论去解构问题,去理解问题,而不是对着A1 自说自话,这也是讨论的根本,,,
发表于 2026-3-2 22:43:23 | 显示全部楼层
回复 3# jiavip

为何要用 ‘拷问’ ,就是要用前所未有的 ‘效率’ 从 ai 获取,而拷问之所得必须还要 ‘去伪存真、去粗取精’,这就要靠自己的真功夫了...
 楼主| 发表于 2026-3-2 23:04:22 | 显示全部楼层
回复 4# aloha20200628


    额,,,思维不在一个维度!,,换句话来说:这个帖子本身讨论的就不是代码,也不是“效率”,更不是“拷问”,,
像我和我以前的那些圈子,能从一些逻辑关系,一些代码瞎表达,瞎扯到时局,瞎扯到婚姻生活,,,
我喜欢以前的那种氛围和那种气氛,因为从一些离经叛道的逻辑里,可以借鉴出一些造码思路,和拆解思维,,
说白了,讨论问题的核心,并不是核心的根本!人不可能为了一个命令或代码就不眠不休!,,
所以,这个贴并不是找答案,更像是在找一些共通感,,
或许这个脚本的错误,我以前早就知道了,而是以前没发出来,,正如:以前忙于生活,,忽略了很多、
现在难得静心下来,又旧菜新炒,,,更多的是交流,交流一些感悟,一些共存!,,
正如前文:心态老了,,,而老家伙,喜欢怀旧,怀旧以前,,(正是鄙人),,,
发表于 2026-3-3 09:10:08 | 显示全部楼层
本帖最后由 ShowCode 于 2026-3-3 09:11 编辑

测试用例:
set date=2026-01-01
set sdate=%date%

计算结果:
日期:2026-01-01 星期四 丙午年 生肖:马 农历:一十三号

正确结果:
乙巳 [蛇] 年 农历 十一月十三

屎山代码,多说无益。
发表于 2026-3-3 09:13:45 | 显示全部楼层
具体原因 :

- 平年2月有28天,3月1日是第31+28=59天,所以3月的z值应该是59
- 闰年2月有29天,3月1日是第31+29=60天,所以需要将z值加1
- 但代码中对于平年,错误地执行了 z -= 1 ,导致平年的z值变成了58,少了1天
修复方案 :
将闰年处理部分的逻辑修改为:

- 如果是闰年且月份大于2,z加1
- 如果不是闰年,不需要调整z值
发表于 2026-3-3 17:20:35 | 显示全部楼层
农历需要查表吧,农历每19年中有7个闰年,闰年里面有某个月会重复,比如闰六月;千万不要把公历的闰年跟农历的闰年混淆了;
发表于 2026-3-4 12:53:15 | 显示全部楼层

据说尚未发现由公历推算农历的完美算法,有兴趣者过一遍2008年老帖 》 http://www.bathome.net/thread-560-1-1.html,此帖楼主当年也承认这一说法... 即使采用 powershell 即从 .net 搬运过来的 System.Globalization.ChineseLunisolarCalendar 库函数推算,也存在某些错误...
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|批处理之家 ( 渝ICP备10000708号 )

GMT+8, 2026-3-17 05:45 , Processed in 0.019935 second(s), 8 queries , File On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表