本帖最后由 plp626 于 2012-4-15 09:37 编辑
{~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
本贴主要讨论时间日期计算的算法思想(几乎纯数学,外加set/a运算技巧)
可参照 HAT翻译了Ritchie Lawrence 的时间日期函数库;为引子,开启大家思路;
方便交流,做如下约定:
一个时间变量(可以称作复合型变量)由6个整数组成,分别为:【年数,月数,日数,时数,分数,秒数】- :: 方便讨论这6个整数分别用如下字母表示[y,m,d,h,f,s]
- y取值范围[-10000,10000];
- (暂时不考虑y为负值的情形,只考虑公元1年1月1日之后的情形;视难度而定)
- m取值范围[1,12]
- d取值范围[1,31]
- h取值范围[0,23]
- f取值范围[0,59]
- s取值范围[0,59]
- :: 比如 2012-04-03,1:02:09秒这个时间对应的值为 y=2012,m=4,d=3,h=1,f=2,s=9
复制代码 本贴重点是算法思想,阐述思路是重点;
代码虽然作为载体不很重要,但也请给出最简短高效的实现代码;
(在便于阅读的条件下,一行set/a 实现最好)
主要解决一下问题;
(一)给定两个时间,求其相隔的天数;或者秒数
Q1:
y1,m1,d1,h1,f1,s1 (初时间); y1,m1,d1,h2,f2,s2(末时间) // 初末时间符合客观现实
求其相隔多少秒sec- :fun1
- set/a y=2012,m=4,d=3,h1=1,f1=2,s1=9
- set/a h2=1,f2=3,s2=9
- rem ---- 你的代码1 -----
- echo %out%
- rem 输出值out=60
复制代码 Q2:
y1,m1,d1,h1,f1,s1 (初时间); y2,m2,d2,h1,f1,s1(末时间) // 初末时间符合客观现实
求其相隔多少天day- :fun2
- set/a y1=2012,m1=4,d1=3,h=1,f=2,s=9
- set/a y2=2012,m2=5,d2=3
- rem ---- 你的代码1 -----
- echo %out%
- rem 输出值out=31
复制代码 Q3:
y1,m1,d1,h1,f1,s1 (初时间); y2,m2,d2,h2,f2,s2(末时间) // 初末时间符合客观现实
求其相隔多少天day+多少秒sec (day,sec 为 非负数,day范围[0,+2147483647]sec范围为[0,86399])- :fun3
- set/a y1=2012,m1=4,d1=3,h1=1,f1=2,s1=9
- set/a y2=2012,m2=4,d2=5,h2=1,f2=2,s2=10
- rem ---- 你的代码1 -----
- echo %out%
- rem 输出值out=2 1
复制代码 (二)给定一个时间,y,m,d,h,f,s 求其 x天或x秒之后的时间
Q4:
给定 y,m,d,h,f,s;求x天后的;y,m,d,h,f,s (x为负数表示之前,x范围:[-2147483647, +2147483648])- :fun4
- set/a y=2012,m=4,d=3,h=1,f=2,s=9
- set/a x=-4
- rem ---- 你的代码 -----
- echo %out%
- rem 输出值out=2012 3 30 1 2 9
复制代码 Q5:
给定 y,m,d,h,f,s;求x秒后的;y,m,d,h,f,s (x为负数表示之前,x范围:[-86399, +86399])- :fun5
- set/a y=2012,m=4,d=3,h=1,f=2,s=9
- set/a x=-61
- rem ---- 你的代码 -----
- echo %out%
- rem 输出值out=2012 4 3 1 1 8
复制代码 (三)给定一个日期,求其星期数- :fun6 给定一个日期,求其星期数
- set/a y=2012,m=4,d=3
- rem ---- 你的代码 -----
- echo %out%
- rem 输出值out=2
复制代码 为建立适合cmd的时间变量数据结构,增加一个成员;跑秒,即百分之一秒;
这样一个时间变量有7个成员(年,月,日,时,分,秒,跑秒),为方便交流约定分别用字母(y,m,d,h,f,s,p)表示;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
回复 7# CrLf
Q1就是Q3的特殊情形(同一天内的两时间差)
Q2也是Q3的特殊情形(同一时分秒下,两日期相隔的天数)
对于你说的问题我不够秒数不细致造成误会;sec取值范围为[0,86399](已更新);
把第一类问题分解成Q1,Q2,是有原因的;
一天=86400秒,秒数可以转换为天数,天数也能转换为秒数,那么求时间差,给出day+sec不是多次一举?
非也,set/a 能支持的最大数值2147483647,2147483647sec=24855day=58year
为了能兼容表示超过58年的情形,用两个数表示时间差,day和sec;day相当于时间差值的高位,sec相当于时间差值的低位;
所以,sec的取值范围为[0,86399]
第一类问题的核心是Q2,这里推荐大家参看15楼的思想;
对于第二类问我还没好思路,大家继续参看15楼的思想,交流下;
把算法思想吃透了,代码真就是工具了;
-----------------------------------------------------------
回复 5# CrLf
只测试了你的天数转日期,是把1969-9-11作为参考日期的第0天;只见代码不见思想;- :d2ymd <day> <ret:y> <ret:m> <ret:d>
- @echo off
- :d2ymd
- setlocal enabledelayedexpansion
- set/a d=%1
- set/a "d+=719050,d-=d/1461-d/36524+d/146097,y=d/365+1,r=^!(y%%4)-^!(y%%100)+^!(y%%400),d+=(d%%=365)/(212+r)*30+r,d+=^!^!(d/(59+r))*(2-r),m=d/61*2+d%%61/31,d-=m*61/2+m*61%%2-1,m+=1-m/8"
- endlocal&if %4. neq . (set %2=%y%&set %3=%m%&set %4=%d%)else echo %y% %m% %d%
复制代码 保存为d2ymd.bat,发现不少bug:- ->d2ymd 841
- 1971 12 31
- ->d2ymd 842
- 1972 1 2
- ->d2ymd 1223
- 1973 1 16
- ->d2ymd 1222
- 1973 1 16
- 还有很多bug。。。
复制代码 --------------------------------------------- |