农历阳历数据的转换查询数据库来源Excel的数据列,需要的数据主要有两个:1)农历每月初一对应的阳历日期,;2)农历每月的天数;例如19000101 29 19000131,即表示一九〇〇年正月初一的阳历日期为一九〇〇年一月三十一日(阳历),该正月的天数为29天。将这些数据按照一定的格式写成txt数据文件,以供ahk后续的读取用。思路及代码如下:

?

一、查农历和查阳历分开两个ahk库文件,

?

二、根据阳历查询农历:

首先建立txt数据文件,每行按照这样的格式:190001,31,1900,01,0 ,数据之间采用英文逗号隔开,各数据对应的含义分别为:阳历的年月,农历月初一对应的阳历日期,对应的农历年月,对应的农历月是否为闰月(1或者0);建立二维数组,其中第一维对应的为txt文件的行,第二维及为每行的各列数据,最大序列为5。根据输入的str2字符串作为查询的阳历日期(如20001101或2000/11/01或2000-11-01),对此字符串进行分解,对应分解出年月日,分别赋值给yy1,mm1,dd1。这里面首先要对输入的数据进行一个有效性检查。有效性检查主要依次判断:A)如果yy1>2099或者yy1<1899,则超出数据库的范围,退出查询。B)如果mm1>12或者mm1<1则表示不符合月份范围,退出查询。C)如果mm1=2,表示2月份,如果mod(yy1,4)>0表示平年,此时如果dd1>28,则表示日期超范围,退出查询,如果mod(yy1,4)>0且dd1>29则表示日期超出范围,这里面还需要单独判断整百年与400的余数才是29天的情况。D)如果mm1等于2,4,6,9,11时且dd1>30则日期超出范围退出查询;E)如果mm1=1,3,5,7,8,10,12时且dd1>31则日期超出范围,退出查询。这里面还需要细分输入的字符是否符合日期格式的规范以及是否包含非法符号等等。在日期判断无误合法以后,开始进行数据匹配。

首先合并yy1与mm1,形成年月的字符组合,以此数据对数组进行loop循环查找,查找到了相同的数据后,则获取当前的a_index序号,并break退出循环。(此时有一个情况:就是同一个年月的阳历可能跨越两个农历月,比如当月的1日为农历月初一,当月的31日为农历次月的初一。但是由于在前期数据库生成的时候按照先后顺序,所以采用loop方法查询到该日期的时候,一般都是在小日期的那条数据,不会查询到大日期的那条数据。但是需要对日期dd1进行一个判断,如果当前输入的dd1小于该条数据对应的阳历日期列,那么表示查询的日期不是当前条数据对应的农历月,而是在此农历月之前的一个月,这里需要增加一个序号减1的操作,对应代码:

;当查询的日期小于当前数据库的序列日期,表示当前时间的农历比记录的农历小,记录回退一格
    if (dd1< lunar_arr[cur_index,2]) ;此处第二列数据存储的农历月初一对应的阳历日期
    {
        cur_index :=cur_index -1
    }

这样就获取了查询日期最接近的农历月初一所对应的阳历日期数据(类似于excel的match获得的小于等于的最大值)

然后根据输入的数据YYYYMMDD与该条数据的YYYYMMDD的日期进行天数差值计算,从而获得输入日期与农历月初一日期的差值,从而就获得了输入日期对应的农历月日结果。代码如下:

    ;计算当前日期与数据库序列记录日期的天数差值及为农历的日期(因为序列记录为当月初一)
    lunar_day_find :=yy1 . mm1 . dd1 ;输入的日期数据
            ;获得查询日期阳历的星期
    FormatTime, weekname, %lunar_day_find%, WDay
    
    lunar_day_datebase := lunar_arr[cur_index,1] . lunar_arr[cur_index,2] ;数据库中对应的农历月初一的阳历日期数据
    envsub, lunar_day_find, % lunar_day_datebase ,days ;获得两个日期之间的差值
    lunar_day_find += 1 ;这里需要+1,所得的数字即为农历月的日期,如结果为27,则对应农历日期为廿七。

这样得到的lunar_day_find变量结果就是要查询的农历日期(envsub命令会自动对变量计算查之后再重新赋值给此变量)

后续经过一些处理就可以显出要查询的农历日期及星期。

?

三、根据农历查询阳历:

根据农历反查阳历的思路与上面阳历查询农历的思路基本类似,在建立txt数据库以及数组的时候列的设置有一些细微的位置调整;然后同样先对日期的有效性判断,农历的日期有效性判断相对比阳历的简单些:A)查询年份和月份是否符合范围,B)查询日期是否>30或者<1,因为农历同样的月份大小不是固定,而且最大只有两种29,30。C)增加一个判断,当前输入的农历年月的天数是否超过数据库的记录天数,代码如下:

?

                 if (dd1 > solar_arr[cur_index,2]) ;这里第2列存储的当前农历月的天数,如果输入的超过此天数则表示日期非法
                {
                    return % yy1 . "年" . mm1 . "月无" . dd1 . "天,查找中断!`n请重新输入日期"
                    exitapp
                }

不过在此指前首先要采用loop循环匹配的方法获得yy1 . mm1组合的年月匹配所在的数据条目。

因为农历存在闰月的设置,所以农历的查询相比阳历的查询来说需要增加一个参数,比如在输入的日期后面空格R这样的来表示查询当前的闰月,同样闰月的设置也是没有规律的,所以如果输入数据中带有R参数,那么需要查找当前年月所在的闰月(如果存在闰月,则闰月就是当前行的下一行),将所查询到的cur_index下一1位。代码如下:

?

                  ;判断是否查询闰月
                if (runyue="R")
                {
                    if (solar_arr[cur_index+1,3]<>1)
                    {
                        return  % yy1 . "年无闰" . mm1 . "月,查找中断! `n请不带R参数进行查询"
                        exitapp
                    }
                    else
                    {
                        cur_index:=cur_index+1 ;表示查询的为当前闰月,记录后移一位
                    }
                    
                }

?

在数据有效并且闰月参数匹配正确后,根据当前的序列cur_index获得对应的农历月初一的阳历日期,将当前的阴历日期作为天数差值与阳历日期进行计算,获得当前农历日期对应的阳历日期,从而获得正确的查询结果。代码如下:

?

                solar_day_find:=solar_arr[cur_index,4] ;获取当月初一的阳历日期
                solar_day_find +=dd1-1, Days ;将差值与对应阳历日期计算,得出阳历日期,注意此处要-1。
                
                formattime, solar_day_find, %solar_day_find%, yyyy年MM月dd日 ;
                FormatTime, weekname, %solar_day_find%, WDay

?这样获得的solar_day_find就是农历对应的阳历日期查询结果以及星期。

?