<?php
header('Content-Type: text/html; charset=utf-8');
class LunarCalendar {
private $P = [19416,19168,42352,21717,53856,55632,91476,22176,39632,21970,19168,42422,42192,53840,119381,46400,54944,44450,38320,84343,18800,42160,46261,27216,27968,109396,11104,38256,21234,18800,25958,54432,59984,28309,23248,11104,100067,37600,116951,51536,54432,120998,46416,22176,107956,9680,37584,53938,43344,46423,27808,46416,86869,19872,42448,83315,21200,43432,59728,27296,44710,43856,19296,43748,42352,21088,62051,55632,23383,22176,38608,19925,19152,42192,54484,53840,54616,46400,46496,103846,38320,18864,43380,42160,45690,27216,27968,44870,43872,38256,19189,18800,25776,29859,59984,27480,21952,43872,38613,37600,51552,55636,54432,55888,30034,22176,43959,9680,37584,51893,43344,46240,47780,44368,21977,19360,42416,86390,21168,43312,31060,27296,44368,23378,19296,42726,42208,53856,60005,54576,23200,30371,38608,19415,19152,42192,118966,53840,54560,56645,46496,22224,21938,18864,42359,42160,43600,111189,27936,44448];
private $B = "日一二三四五六七八九十";
private $O = "鼠牛虎兔龙蛇马羊猴鸡狗猪";
private $K = "甲乙丙丁戊己庚辛壬癸";
private $J = "子丑寅卯辰巳午未申酉戌亥";
private $D = [0,21208,43467,63836,85337,107014,128867,150921,173149,195551,218072,240693,263343,285989,308563,331033,353350,375494,397447,419210,440795,462224,483532,504758];
private function d($k) {
$j = 348;
for ($h = 0x8000; $h > 8; $h >>= 1) {
$j += ($this->P[$k-1900] & $h) ? 1 : 0;
}
return $j + $this->getLeapMonthDays($k);
}
private function getGanZhi($h) {
return mb_substr($this->K, $h % 10, 1, 'UTF-8') . mb_substr($this->J, $h % 12, 1, 'UTF-8');
}
private function getLeapMonthDays($h) {
if ($this->hasLeapMonth($h)) {
return ($this->P[$h-1900] & 65536) ? 30 : 29;
} else {
return 0;
}
}
private function hasLeapMonth($h) {
return $this->P[$h-1900] & 15;
}
private function getMonthDays($i, $h) {
return ($this->P[$i-1900] & (65536 >> $h)) ? 30 : 29;
}
private function e($i, $h) {
return ($this->P[$i-1900] & (65536 >> $h)) ? 30 : 29;
}
private function C($m) {
$j = 0;
$h = 0;
$l = new DateTime('1900-01-31');
$n = ($m->getTimestamp() - $l->getTimestamp()) / 86400;
$this->dayCyl = $n + 40;
$this->monCyl = 14;
for ($k = 1900; $k < 2050 && $n > 0; $k++) {
$h = $this->d($k);
$n -= $h;
$this->monCyl += 12;
}
if ($n < 0) {
$n += $h;
$k--;
$this->monCyl -= 12;
}
$this->year = $k;
$this->yearCyl = $k - 1864;
$j = $this->hasLeapMonth($k);
$this->isLeap = false;
for ($k = 1; $k < 13 && $n > 0; $k++) {
if ($j > 0 && $k == ($j + 1) && $this->isLeap == false) {
--$k;
$this->isLeap = true;
$h = $this->b($this->year);
} else {
$h = $this->e($this->year, $k);
}
if ($this->isLeap == true && $k == ($j + 1)) {
$this->isLeap = false;
}
$n -= $h;
if ($this->isLeap == false) {
$this->monCyl++;
}
}
if ($n == 0 && $j > 0 && $k == $j + 1) {
if ($this->isLeap) {
$this->isLeap = false;
} else {
$this->isLeap = true;
--$k;
--$this->monCyl;
}
}
if ($n < 0) {
$n += $h;
--$k;
--$this->monCyl;
}
$this->month = $k;
$this->day = $n + 1;
}
private function padZero($h) {
return $h < 10 ? "0" . $h : $h;
}
private function f($i, $j) {
$h = $i;
$patterns = [
'yyyy' => function($matches) use ($h) {
return str_pad($h->format('Y'), 4, '0', STR_PAD_LEFT);
},
'dd' => function($matches) use ($h) {
return $this->padZero($h->format('d'));
},
'd' => function($matches) use ($h) {
return $h->format('d');
},
'MM' => function($matches) use ($h) {
return $this->padZero($h->format('m'));
},
'M' => function($matches) use ($h) {
return $h->format('m');
}
];
return preg_replace_callback('/dd?d?d?|MM?M?M?|yy?y?y?/', function($matches) use ($patterns) {
return $patterns[$matches[0]]($matches);
}, $j);
}
public function __construct($date) {
$this->date = $date;
$this->solarYear = $this->f($date, "yyyy");
$this->solarMonth = $this->f($date, "M");
$this->solarDate = $this->f($date, "d");
$this->solarWeekDay = $date->format('w');
$this->solarWeekDayInChinese = "星期" . mb_substr($this->B, $this->solarWeekDay, 1, 'UTF-8');
$X = new stdClass();
$this->C($date);
$X->year = $this->year;
$X->month = $this->month;
$X->isLeap = $this->isLeap;
$X->day = $this->day;
$X->yearCyl = $this->yearCyl;
$X->monCyl = $this->monCyl;
$X->dayCyl = $this->dayCyl;
$this->lunarYear = $X->year;
$this->shengxiao = mb_substr($this->O, ($this->lunarYear - 4) % 12, 1, 'UTF-8');
$this->lunarMonth = $X->month;
$this->lunarIsLeapMonth = $X->isLeap;
$this->lunarDate = $X->day;
$this->ganzhiYear = $this->getGanZhi($X->yearCyl);
$this->ganzhiMonth = $this->getGanZhi($X->monCyl);
$this->ganzhiDate = $this->getGanZhi($X->dayCyl++);
}
public function getLunarMonthName($month) {
$monthNames = ["正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "冬", "腊"];
return $monthNames[$month - 1];
}
public function getLunarDayName($day) {
if ($day == 1) return "初一";
if ($day == 2) return "初二";
if ($day == 3) return "初三";
if ($day == 4) return "初四";
if ($day == 5) return "初五";
if ($day == 6) return "初六";
if ($day == 7) return "初七";
if ($day == 8) return "初八";
if ($day == 9) return "初九";
if ($day == 10) return "初十";
if ($day == 20) return "二十";
if ($day == 30) return "三十";
if ($day < 20) return "十" . mb_substr("一二三四五六七八九", $day - 11, 1, 'UTF-8');
if ($day < 30) return "廿" . mb_substr("一二三四五六七八九", $day - 21, 1, 'UTF-8');
return "";
}
}
// Example usage:
$date = new DateTime();
$lunar = new LunarCalendar($date);
echo "农历" . $lunar->getLunarMonthName($lunar->lunarMonth) . "月" . $lunar->getLunarDayName(floor($lunar->lunarDate)) . "日";
echo " " . $lunar->ganzhiYear . "年";
echo " " . $lunar->ganzhiMonth . "月";
echo " " . $lunar->ganzhiDate . "日";