用php对农历(阴历/旧历)+n年m月r日进行日期增减的算法,基于lunar工具

今天用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周

评论/留言