干支纪日是现今历史上最长的纪日法,也是中国特有的历法,据考从伏羲氏就开始有创建,从中国古代的夏朝就已经开始使用。我国的干支纪日,从鲁隐公三年二月己巳日(公元前720年2月10日)开始,一直到今天,都未曾间断。
干支历采用六十甲子循环记载年月日时的信息,干支历的年月信息,与公历、农历的年不同,是以节气为根据的,就是根据地球与太阳的旋转角度精确计算的,干支历中,每年以立春作为开始,每月以节气中的节开始,立春为一月,惊蛰为二月,依次类推.
干支历中,月份的地支排列是:一月建寅,二月建卯,... 十一月建子,十二月建丑,时辰的地支排列是:子、丑、寅、... 、戌、亥
关于推断月干和时干的信息,古人为了方便记忆,有口诀流传下来,可以根据年干推断月干,根据日干推断时干,推月干的称为“五虎遁元诀", 推时干的称为"五鼠遁元诀", 虎和鼠的称谓来源于地支对应的十二生肖,而今人多直接称为”年上起月诀“和”日上起时诀".www.14271.com
五虎遁元诀:
甲己之年丙作首
乙庚之年戊为头
丙辛之岁寻庚上
丁壬壬寅顺水流
若问戊癸何方发
甲寅之上好追求
五鼠遁元诀:
甲己还加甲
乙庚丙作初
丙辛从戊起
丁壬庚子居
戊癸何方发
实现这个公历转干支历算法用到的节气计算部分的代码,见我前面的一篇文章:寿星万年历---Lua实现
以下是公历转干支历的lua实现:
--公历转干支历实现 --[[干支历的年以立春发生时刻(注意,不是立春日的0时)为年干支的起点;各月干支以十二节时刻(注意,不一定是各节气日的0时) --]] --require('common') require('jieqi') GanZhiLi = { } --创建干支历对象 function GanZhiLi:new() local o = {} setmetatable(o, self) self.__index = self o:setTime(os.time()) return o end --将offset的数值转化为特定偏移下的周期数,起始数,偏移量,周期 function GanZhiLi:calRound(start, offset, round) if start > round or start <=0 then return nil end --参数不对 offset = math.floor(math.fmod(start+offset, round)) if offset >=0 then if offset==0 then offset=round end return offset else return round + offset end end --周期循环数 function calR2(n, round) local x = math.floor(math.fmod(n,round)) if x==0 then x=round end return x end --设置用于转换干支历的公历时间 function GanZhiLi:setTime(t) self.ttime = t self.tday = os.date('*t', t) --for k,v in pairs(self.tday) do -- print(k,v) --end --先取公历今年的干支 self.jqs = getYearJQ(self.tday.year) self.ganZhiYearNum = self:calGanZhiYearNum() if self.ganZhiYearNum ~= self.tday.year then --如果在节气上还没到今年的立春,则还没到干支历的今年,需要取干支历的年份的24节气 self.jqs = getYearJQ(self.ganZhiYearNum) end self.ganZhiMonNum = self:calGanZhiMonthNum() self.curJq = self:getCurJQ() end function GanZhiLi:getCurJQ() --for i=1,24 do -- local x = os.date('*t', self.jqs[i]) -- print(x.year, x.month, x.day, x.hour, x.min, x.sec) --end local x = 0 if self.ttime < self.jqs[1] then return nil end --出错,计算错年了? for i=1,23 do if self.jqs[i] <= self.ttime and self.jqs[i+1] > self.ttime then x=i break end end if x==0 then x=24 end return x --返回以立春为起始序号1的节气 end --根据公历年份和节气计算干支历的年份 function GanZhiLi:calGanZhiYearNum() if (self.ttime < self.jqs[1]) then return self.tday.year -1 else return self.tday.year end end --获取干支月份 function GanZhiLi:calGanZhiMonthNum() if self.ttime < self.jqs[1] then return nil end local x = 0 if self.ttime < self.jqs[1] then return nil end --出错,计算错年了? for i=1,23 do if self.jqs[i] <= self.ttime and self.jqs[i+1] > self.ttime then x=i end end if x==0 then x=24 end return math.floor((x+1)/2) end --返回年的干支序号,1为甲子。。。 function GanZhiLi:getYearGanZhi() local jiaziYear = 1984 --甲子年 --print(self.ganZhiYearNum) local yeardiff = self.ganZhiYearNum - jiaziYear return self:calRound(1,yeardiff,60) end --返回年的天干号,1为甲 function GanZhiLi:getYearGan() local idx = self:getYearGanZhi() return self:calR2(idx,10) end --返回年的地支号,1为子 function GanZhiLi:getYearZhi() local idx = self:getYearGanZhi() return self:calR2(idx,12) end --返回月的干支号 function GanZhiLi:getMonGanZhi() local ck ={year=2010,month=2,day=4,hour=6,min=42,sec=0} local x = os.time(ck) --参考月,立春时间2010-2-4 6:42:00对应的干支序号为15 local ydiff = self.ganZhiYearNum - ck.year local mdiff = self.ganZhiMonNum-1 if ydiff >=0 then mdiff = ydiff*12 + mdiff else mdiff = (ydiff+1)*12 + mdiff -12 end return self:calRound(15,mdiff, 60) end function GanZhiLi:getMonGan() local idx = self:getMonGanZhi() return self:calR2(idx,10) end function GanZhiLi:getMonZhi() local idx = self:getMonGanZhi() return self:calR2(idx,12) end --返回日的干支号,甲子从1开始 function GanZhiLi:getDayGanZhi() local DAYSEC = 24*3600 local jiaziDayTime = os.time({year=2012, month=8, day=30, hour=23, min=0,sec=0}) local daydiff = math.floor((self.ttime - jiaziDayTime)/DAYSEC) return self:calRound(1,daydiff,60) end --返回日的天干号 function GanZhiLi:getDayGan() local idx = self:getDayGanZhi() return self:calR2(idx,10) end --返回日的地支号 function GanZhiLi:getDayZhi() local idx = self:getDayGanZhi() return self:calR2(idx,12) end --返回时辰的干支号 function GanZhiLi:getHourGanZhi() local SHICHENSEC=3600*2 local jiaziShiTime = os.time({year=2012, month=8, day=30, hour=23, min=0, sec=0}) local shiDiff = math.floor((self.ttime - jiaziShiTime)/SHICHENSEC) return self:calRound(1,shiDiff,60) end --返回时干号 function GanZhiLi:getShiGan() local idx = self:getHourGanZhi() return self:calR2(idx,10) end --返回时支号 function GanZhiLi:getShiZhi() local idx = self:getHourGanZhi() return self:calR2(idx,12) end --====================以下是测试代码============= local jqB={ --节气表 "立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露", "秋分","寒露","霜降","立冬","小雪","大雪","冬至","小寒","大寒",} --天干 local tiangan = {'甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'} --地支 local dizhi = {'子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥'} --根据六十甲子序号,返回六十甲子字符串,甲子从1开始 local function get60JiaZiStr(i) local gan = i % 10 if gan == 0 then gan = 10 end local zhi = i % 12 if zhi == 0 then zhi = 12 end return tiangan[gan]..dizhi[zhi] end --测试 x = GanZhiLi:new() x:setTime(os.time({year=2000,month=11, day=22,hour=12,min=4,sec=5})) --x:setTime(os.time()) yidx = x:getYearGanZhi() midx = x:getMonGanZhi() didx = x:getDayGanZhi() hidx = x:getHourGanZhi() print('干支:' .. get60JiaZiStr(yidx) .. ' ' .. get60JiaZiStr(midx) .. ' ' .. get60JiaZiStr(didx) .. ' ' .. get60JiaZiStr(hidx)) print('干支年份:' .. x.ganZhiYearNum .. ', 干支月份' .. x.ganZhiMonNum .. ', 当前节气:' .. jqB[x.curJq] )