Last active
September 14, 2023 04:47
-
-
Save flashvnn/0fb13d18ef9b089117fd1b3c2275c8ad to your computer and use it in GitHub Desktop.
AmLich.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Thư viện AmLich. | |
* Example | |
* $am_lich = new AmLich(); | |
* $al = $am_lich->convertSolar2Lunar(30, 10, 2023, 7.0); | |
* Ngày: $al[0], Tháng: $al[1], Năm: $al[2] | |
*/ | |
class AmLich { | |
public function INT($d) { | |
return floor($d); | |
} | |
public function jdFromDate($dd, $mm, $yy) { | |
$a = $this->INT((14 - $mm) / 12); | |
$y = $yy + 4800 - $a; | |
$m = $mm + 12 * $a - 3; | |
$jd = $dd + $this->INT((153 * $m + 2) / 5) + 365 * $y + $this->INT($y / 4) - $this->INT($y / 100) + $this->INT($y / 400) - 32045; | |
if ($jd < 2299161) { | |
$jd = $dd + $this->INT((153 * $m + 2) / 5) + 365 * $y + $this->INT($y / 4) - 32083; | |
} | |
return $jd; | |
} | |
public function jdToDate($jd) { | |
if ($jd > 2299160) { // After 5/10/1582, Gregorian calendar | |
$a = $jd + 32044; | |
$b = $this->INT((4 * $a + 3) / 146097); | |
$c = $a - $this->INT(($b * 146097) / 4); | |
} | |
else { | |
$b = 0; | |
$c = $jd + 32082; | |
} | |
$d = $this->INT((4 * $c + 3) / 1461); | |
$e = $c - $this->INT((1461 * $d) / 4); | |
$m = $this->INT((5 * $e + 2) / 153); | |
$day = $e - $this->INT((153 * $m + 2) / 5) + 1; | |
$month = $m + 3 - 12 * $this->INT($m / 10); | |
$year = $b * 100 + $d - 4800 + $this->INT($m / 10); | |
//echo "day = $day, month = $month, year = $year\n"; | |
return [$day, $month, $year]; | |
} | |
public function getNewMoonDay($k, $timeZone) { | |
$T = $k / 1236.85; // Time in Julian centuries from 1900 January 0.5 | |
$T2 = $T * $T; | |
$T3 = $T2 * $T; | |
$dr = M_PI / 180; | |
$Jd1 = 2415020.75933 + 29.53058868 * $k + 0.0001178 * $T2 - 0.000000155 * $T3; | |
$Jd1 = $Jd1 + 0.00033 * sin((166.56 + 132.87 * $T - 0.009173 * $T2) * $dr); // Mean new moon | |
$M = 359.2242 + 29.10535608 * $k - 0.0000333 * $T2 - 0.00000347 * $T3; // Sun's mean anomaly | |
$Mpr = 306.0253 + 385.81691806 * $k + 0.0107306 * $T2 + 0.00001236 * $T3; // Moon's mean anomaly | |
$F = 21.2964 + 390.67050646 * $k - 0.0016528 * $T2 - 0.00000239 * $T3; // Moon's argument of latitude | |
$C1 = (0.1734 - 0.000393 * $T) * sin($M * $dr) + 0.0021 * sin(2 * $dr * $M); | |
$C1 = $C1 - 0.4068 * sin($Mpr * $dr) + 0.0161 * sin($dr * 2 * $Mpr); | |
$C1 = $C1 - 0.0004 * sin($dr * 3 * $Mpr); | |
$C1 = $C1 + 0.0104 * sin($dr * 2 * $F) - 0.0051 * sin($dr * ($M + $Mpr)); | |
$C1 = $C1 - 0.0074 * sin($dr * ($M - $Mpr)) + 0.0004 * sin($dr * (2 * $F + $M)); | |
$C1 = $C1 - 0.0004 * sin($dr * (2 * $F - $M)) - 0.0006 * sin($dr * (2 * $F + $Mpr)); | |
$C1 = $C1 + 0.0010 * sin($dr * (2 * $F - $Mpr)) + 0.0005 * sin($dr * (2 * $Mpr + $M)); | |
if ($T < -11) { | |
$deltat = 0.001 + 0.000839 * $T + 0.0002261 * $T2 - 0.00000845 * $T3 - 0.000000081 * $T * $T3; | |
} | |
else { | |
$deltat = -0.000278 + 0.000265 * $T + 0.000262 * $T2; | |
}; | |
$JdNew = $Jd1 + $C1 - $deltat; | |
//echo "JdNew = $JdNew\n"; | |
return $this->INT($JdNew + 0.5 + $timeZone / 24); | |
} | |
public function getSunLongitude($jdn, $timeZone) { | |
$T = ($jdn - 2451545.5 - $timeZone / 24) / 36525; // Time in Julian centuries from 2000-01-01 12:00:00 GMT | |
$T2 = $T * $T; | |
$dr = M_PI / 180; // degree to radian | |
$M = 357.52910 + 35999.05030 * $T - 0.0001559 * $T2 - 0.00000048 * $T * $T2; // mean anomaly, degree | |
$L0 = 280.46645 + 36000.76983 * $T + 0.0003032 * $T2; // mean longitude, degree | |
$DL = (1.914600 - 0.004817 * $T - 0.000014 * $T2) * sin($dr * $M); | |
$DL = $DL + (0.019993 - 0.000101 * $T) * sin($dr * 2 * $M) + 0.000290 * sin($dr * 3 * $M); | |
$L = $L0 + $DL; // true longitude, degree | |
//echo "\ndr = $dr, M = $M, T = $T, DL = $DL, L = $L, L0 = $L0\n"; | |
// obtain apparent longitude by correcting for nutation and aberration | |
$omega = 125.04 - 1934.136 * $T; | |
$L = $L - 0.00569 - 0.00478 * sin($omega * $dr); | |
$L = $L * $dr; | |
$L = $L - M_PI * 2 * ($this->INT($L / (M_PI * 2))); // Normalize to (0, 2*PI) | |
return $this->INT($L / M_PI * 6); | |
} | |
public function getLunarMonth11($yy, $timeZone) { | |
$off = $this->jdFromDate(31, 12, $yy) - 2415021; | |
$k = $this->INT($off / 29.530588853); | |
$nm = $this->getNewMoonDay($k, $timeZone); | |
$sunLong = $this->getSunLongitude($nm, $timeZone); // sun longitude at local midnight | |
if ($sunLong >= 9) { | |
$nm = $this->getNewMoonDay($k - 1, $timeZone); | |
} | |
return $nm; | |
} | |
public function getLeapMonthOffsetnth11($a11, $timeZone) { | |
$k = $this->INT(($a11 - 2415021.076998695) / 29.530588853 + 0.5); | |
$last = 0; | |
$i = 1; // We start with the month following lunar month 11 | |
$arc = $this->getSunLongitude($this->getNewMoonDay($k + $i, $timeZone), $timeZone); | |
do { | |
$last = $arc; | |
$i = $i + 1; | |
$arc = $this->getSunLongitude($this->getNewMoonDay($k + $i, $timeZone), $timeZone); | |
} while ($arc != $last && $i < 14); | |
return $i - 1; | |
} | |
/* Comvert solar date dd/mm/yyyy to the corresponding lunar date */ | |
public function convertSolar2Lunar($dd, $mm, $yy, $timeZone) { | |
$dayNumber = $this->jdFromDate($dd, $mm, $yy); | |
$k = $this->INT(($dayNumber - 2415021.076998695) / 29.530588853); | |
$monthStart = $this->getNewMoonDay($k + 1, $timeZone); | |
if ($monthStart > $dayNumber) { | |
$monthStart = $this->getNewMoonDay($k, $timeZone); | |
} | |
$a11 = $this->getLunarMonth11($yy, $timeZone); | |
$b11 = $a11; | |
if ($a11 >= $monthStart) { | |
$lunarYear = $yy; | |
$a11 = $this->getLunarMonth11($yy - 1, $timeZone); | |
} | |
else { | |
$lunarYear = $yy + 1; | |
$b11 = $this->getLunarMonth11($yy + 1, $timeZone); | |
} | |
$lunarDay = $dayNumber - $monthStart + 1; | |
$diff = $this->INT(($monthStart - $a11) / 29); | |
$lunarLeap = 0; | |
$lunarMonth = $diff + 11; | |
if ($b11 - $a11 > 365) { | |
$leapMonthDiff = $this->getLeapMonthOffsetnth11($a11, $timeZone); | |
if ($diff >= $leapMonthDiff) { | |
$lunarMonth = $diff + 10; | |
if ($diff == $leapMonthDiff) { | |
$lunarLeap = 1; | |
} | |
} | |
} | |
if ($lunarMonth > 12) { | |
$lunarMonth = $lunarMonth - 12; | |
} | |
if ($lunarMonth >= 11 && $diff < 4) { | |
$lunarYear -= 1; | |
} | |
return [$lunarDay, $lunarMonth, $lunarYear, $lunarLeap]; | |
} | |
/* Convert a lunar date to the corresponding solar date */ | |
public function convertLunar2Solar($lunarDay, $lunarMonth, $lunarYear, $lunarLeap, $timeZone) { | |
if ($lunarMonth < 11) { | |
$a11 = $this->getLunarMonth11($lunarYear - 1, $timeZone); | |
$b11 = $this->getLunarMonth11($lunarYear, $timeZone); | |
} | |
else { | |
$a11 = $this->getLunarMonth11($lunarYear, $timeZone); | |
$b11 = $this->getLunarMonth11($lunarYear + 1, $timeZone); | |
} | |
$k = $this->INT(0.5 + ($a11 - 2415021.076998695) / 29.530588853); | |
$off = $lunarMonth - 11; | |
if ($off < 0) { | |
$off += 12; | |
} | |
if ($b11 - $a11 > 365) { | |
$leapOff = $this->getLeapMonthOffsetnth11($a11, $timeZone); | |
$leapMonth = $leapOff - 2; | |
if ($leapMonth < 0) { | |
$leapMonth += 12; | |
} | |
if ($lunarLeap != 0 && $lunarMonth != $leapMonth) { | |
return [0, 0, 0]; | |
} | |
else { | |
if ($lunarLeap != 0 || $off >= $leapOff) { | |
$off += 1; | |
} | |
} | |
} | |
$monthStart = $this->getNewMoonDay($k + $off, $timeZone); | |
return $this->jdToDate($monthStart + $lunarDay - 1); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment