今天用php实现对农历(阴历/旧历)的增减计算,因为这个不是历法不是世界通用的,所以并不是像strtotime直接对时间戳增减的方式完成,
但是操作方式也类似,只不过绕多了一步。
首先介绍一个农历阳历操作工具Lunar.php:
lunar是一个无依赖的支持阳历和阴历的日历工具库,它开源免费,有javascript、java、c#、php、python、go、typescript版本,不依赖第三方,支持阳历阴历互转,它能用来制作日历,甚至算命。
目前支持公历和农历、星座、干支、生肖、节气、节日、彭祖百忌、每日宜忌、吉神宜趋、凶煞宜忌、吉神方位、冲煞、纳音、星宿、八字、五行、十神、建除十二值星、青龙名堂等十二神、黄道黑道日及吉凶等。
旧版本支持的时间跨度:1901-01-01(庚子年冬月十一)至2099-12-31(己未年冬月二十),v1.2.0及以上版本支持0001年至9999年。
github地址:https://github.com/6tail/lunar-php-standalone
里面可以对阳历或者阴历增减x天,也就是next(x)函数,但是不太适用。基于这个类(Lunar这个工具可以很方便地将阴阳历互转)我写了一个简单的逻辑去对农历(阴历/旧历)+n年m月r日的对日期增减方式操作方式:
include ("Lunar.php"); use com\nlf\calendar\util\HolidayUtil; use com\nlf\calendar\Lunar; use com\nlf\calendar\Solar; $solar = Solar::fromYmd(2021,04,28); //根据阳历获取农历对象 $lunar = $solar->getLunar(); $ly = $lunar->getYear(); $lm = $lunar->getMonth(); $ld = $lunar->getDay(); //加1年对应的农历 $nextLunar = Lunar::fromYmd($ly + 1, $lm, $ld); $nextLunarStr = $nextLunar->toString(); $nextSolar = $nextLunar->getSolar()->toString(); echo $nextLunarStr,'<br>';//二〇二二年三月十七 echo $nextSolar,'<br>';//2022-04-17
原理很简单,就是对应的年月日增减即可,这样补充了next只能增减天数的不足。
这个很简单,当时想多了,想找个和strtotime("+x year",time());//这种一步到位的,后来想想上面自己这种先分开再处理的方式也可以,将上面的封装一下也可以一步到位。
但是,这个是有局限性的,比如不能日数加减不能超范围(超出本月),建议用next函数,月数加减不能超年限(本年),需要手动判断。
根据某些规律计算的年月日增减功能,和strtotime功能类型,只是没有写对时分秒的增减:
函数封装方式:
/** * 阳历增减天数、月数、周数、年数 * @author http://blog.alipay168.cn * @param $express string 表达式 * @param $lunarYmd string 阴历日期 * @return array */ function cal_lunar($express, $lunarYmd) { //拆分年月日时分秒 list($ly, $lm, $ld) = explode('-', date('Y-m-d', strtotime($lunarYmd))); $express = trim($express); if (stripos($express, 'd') !== false) { //取出符号,"+" 或者 "-" $symbol = substr($express, 0, 1); $num = intval(trim(str_replace(['day', 'days', 'd', '+', '-'], '', $express))); $nextLunar = Lunar::fromYmd($ly, $lm, $ld); $nextLunar = $symbol == '+' ? $nextLunar->next($num) : $nextLunar->next(-$num); $lunar = $nextLunar->getYear() . '-' . $nextLunar->getMonth() . '-' . $nextLunar->getDay(); $nextLunarStr = $nextLunar->toString(); $nextSolar = $nextLunar->getSolar()->toString(); } elseif (stripos($express, 'w') !== false) { //取出符号,"+" 或者 "-" $symbol = substr($express, 0, 1); $num = intval(trim(str_replace(['week', 'w', 'weeks', '+', '-'], '', $express))); //转换为周的天数 $num = 7 * $num; $nextLunar = Lunar::fromYmd($ly, $lm, $ld); $nextLunar = $symbol == '+' ? $nextLunar->next($num) : $nextLunar->next(-$num); $lunar = $nextLunar->getYear() . '-' . $nextLunar->getMonth() . '-' . $nextLunar->getDay(); $nextLunarStr = $nextLunar->toString(); $nextSolar = $nextLunar->getSolar()->toString(); } elseif (stripos($express, 'm') !== false) { //取出符号,"+" 或者 "-" $symbol = substr($express, 0, 1); $num = intval(trim(str_replace(['month', 'months', 'm', '+', '-'], '', $express))); if ($symbol == '+') { $addNum = $lm + $num; if ($addNum <= 12) { $lm = $addNum; } else { $ly = $ly + intval($addNum / 12); $lm = $addNum % 12; } } else { if ($num < $lm) { $lm = $lm - $num; } else { $lm = 12 - ($num - $lm) % 12; $ly = $ly - intvaL(($num + $lm) / 12); } } $nextLunar = Lunar::fromYmd($ly, $lm, $ld); $nextLunarStr = $nextLunar->toString(); $lunar = $nextLunar->getYear() . '-' . $nextLunar->getMonth() . '-' . $nextLunar->getDay(); $nextSolar = $nextLunar->getSolar()->toString(); } elseif (stripos($express, 'y') !== false) { //取出符号,"+" 或者 "-" $symbol = substr($express, 0, 1); $num = intval(trim(str_replace(['year', 'years', 'y', '+', '-'], '', $express))); $nextLunar = Lunar::fromYmd($symbol == '+' ? $ly + $num : $ly - $num, $lm, $ld); $nextLunarStr = $nextLunar->toString(); $lunar = $nextLunar->getYear() . '-' . $nextLunar->getMonth() . '-' . $nextLunar->getDay(); $nextSolar = $nextLunar->getSolar()->toString(); } else { $nextLunar = Lunar::fromYmd($ly, $lm, $ld); $nextLunarStr = $nextLunar->toString(); $lunar = $ly . '-' . $lm . '-' . $ld; $nextSolar = $nextLunar->getSolar()->toString(); } return [ 'lunar' => $lunar, 'lunarStr' => $nextLunarStr, 'solar' => $nextSolar, ]; } print_r(cal_lunar('-2 month',20210317)); Array ( [lunar] => 2021-1-17 [lunarStr] => 二〇二一年正月十七 [solar] => 2021-02-28 )
通过上面自己封装计算的农历增减函数,很方便地进行年月日的增减了,比如
cal_lunar('-2 month',20210317);//当前农历减2个月
cal_lunar('-99 month',20210317);//当前农历减99个月
cal_lunar('+5 month',20210317);//当前农历增5个月
cal_lunar('-99 day',20210317);//当前农历增99天
cal_lunar('-3 week',20210317);//当前农历减3周