摘要:背景最近做到一個(gè)項(xiàng)目需要陰歷與陽歷的相互轉(zhuǎn)換網(wǎng)上找了很多資料發(fā)現(xiàn)很多都是不準(zhǔn)的但是給了我參考價(jià)值算法借用百度百科的陽歷太陽歷又稱為陽歷,是以地球繞太陽公轉(zhuǎn)的運(yùn)動(dòng)周期為基礎(chǔ)而制定的歷法。
背景
最近做到一個(gè)項(xiàng)目, 需要陰歷與陽歷的相互轉(zhuǎn)換, 網(wǎng)上找了很多資料, 發(fā)現(xiàn)很多都是不準(zhǔn)的, 但是給了我參考價(jià)值
算法借用百度百科的 :
陽歷太陽歷又稱為陽歷,是以地球繞太陽公轉(zhuǎn)的運(yùn)動(dòng)周期為基礎(chǔ)而制定的歷法。
太陽歷的歷年近似等于回歸年,一年12個(gè)月,這個(gè)“月”,實(shí)際上與朔望月無關(guān)。
陽歷的月份、日期都與太陽在黃道上的位置較好地符合,根據(jù)陽歷的日期,在一年中可以明顯看出四季寒暖變化的情況;但在每個(gè)月份中,看不出月亮的朔、望、兩弦。
如今世界通行的公歷就是一種陽歷,平年365天,閏年366天,每四年一閏,每滿百年少閏一次,到第四百年再閏,即每四百年中有97個(gè)閏年。公歷的歷年平均長度與回歸年只有26秒之差,要累積3300年才差一日。
希吉來歷系太陰歷,其計(jì)算方法是: 以太陰圓缺一周為一月,歷時(shí)29日12小時(shí)44分2.8秒,太陰圓缺十二周為一年,歷時(shí)354日8小時(shí)48分33.6秒。每一年的12個(gè)月中,6個(gè)單數(shù)月份(即1、3、5、7、9、11月)為“大建”,每月為30天; 6個(gè)雙數(shù)月份(2、4、6、8、10、12月)為“小建”,每月為29天;在逢閏之年,將12月改大月為30天。該歷以30年為一周期,每一周期里的第2、5、7、10、13、16、18、21、24、26、29年,共11年為閏年, 不設(shè)置閏月,而在12月末置一閏日,閏年為355日,另19年為平年,每年354日。故平均每年為354日8小時(shí)48分。按該歷全年實(shí)際天數(shù)計(jì)算,比回歸年約少10日21小時(shí)1分,積2.7回歸年相差一月,積32.6回歸年相差一年。該歷對(duì)晝夜的計(jì)算,以日落為一天之始,到次日日落為一日,通常稱為夜行前,即黑夜在前,白晝?cè)诤螅瑯?gòu)成一天。希吉來歷每年9月(萊麥丹)為伊斯蘭教齋戒之月, 對(duì)這個(gè)月的起訖除了計(jì)算之外,還要由觀察新月是否出現(xiàn)來決定。 即在8月29日這天進(jìn)行觀測,如見新月,第二日即為9月1日,黎明前開始齋戒,8月仍為小建; 如不見新月,第三日則為9月1日,8月即變?yōu)椤按蠼ā薄5搅?月29日傍晚,也需要看月,如見新月,第二天就是10月1日,即為開齋節(jié)日,使9月變成“小建”;如未見新月,齋戒必須再延一天,9月即為“大建”。 12月(祖勒·希哲)上旬為朝覲日期,12月10日為宰牲節(jié)日。該歷的星期,使用七曜(日、月、火、水、木、金、土)記日的周日法。每周逢金曜為“主麻日”,穆斯林在這一天舉行“聚禮”。
思路借用: https://blog.csdn.net/hsd2012... 這里的解釋: 要想計(jì)算給定的時(shí)間對(duì)于的農(nóng)歷是哪一天,我們需要找一個(gè)參考時(shí)間,然后以該參考時(shí)間計(jì)算以后的時(shí)間。首先計(jì)算當(dāng)前時(shí)間與參考時(shí)間相差的天數(shù),然后通過求出農(nóng)歷每年的天數(shù),計(jì)算當(dāng)前時(shí)間對(duì)應(yīng)的是哪一年的第幾天,最后計(jì)算出屬于那個(gè)月的哪一個(gè)日期。
計(jì)算生肖屬相目前的做法是 陰歷年份 - 1900 + 36 然后除以 12 取余數(shù), 得出生肖屬相的序號(hào), 至于為啥這么計(jì)算, 我是沒搞懂, 網(wǎng)上也搜了很多也沒說清楚, 這里參考文章: https://juejin.im/entry/59904...
private function yearShengXiao($lunarYear) { // TODO 至于為什么這樣弄, 我也沒搞清楚 return self::SHENG_XIAO[($lunarYear - self::MIN_YEAR + 36) % 12]; // 年的屬相 }年的干支算法
網(wǎng)上搜到的做法是用公元年來計(jì)算, 但是不對(duì), 然后我換成陰歷年居然就跟百度的日歷能對(duì)上了, 這個(gè)我也沒弄清楚, 但是能算出來了, 公式: 年數(shù)先減三,除10余數(shù)是天干,基數(shù)改用12除,余數(shù)便是地支年 (如果余數(shù)為 0 ,則取最大序號(hào))
private function yearGanZhi($lunarYear) { // 年數(shù)先減三,除10余數(shù)是天干,基數(shù)改用12除,余數(shù)便是地支年 (如果余數(shù)為 0 ,則取最大序號(hào)) $yJiShu = $lunarYear - 3; $yTianGan = ($yJiShu % 10 == 0) ? 10 : $yJiShu % 10; $yDiZhi = ($yJiShu % 12 == 0) ? 10 : $yJiShu % 12; $yGanZhi = self::TIAN_GAN[$yTianGan - 1] . self::DI_ZHI[$yDiZhi - 1]; // // 由于是從 0 開始,這里再減一 return $yGanZhi; }月的干支算法
網(wǎng)上搜索了, 沒找到好的實(shí)現(xiàn)方式, 麻煩知道的在這里說一下,
日的干支算法網(wǎng)上搜到的:
G = 4C + [C / 4] + 5y + [y / 4] + [3 * (M + 1) / 5] + d - 3 Z = 8C + [C / 4] + 5y + [y / 4] + [3 * (M + 1) / 5] + d + 7 + i 其中C 是世紀(jì)數(shù)減一,y 是年份后兩位,M 是月份,d 是日數(shù)。1月和2月按上一年的13月和14月來算。奇數(shù)月i=0,偶數(shù)月i=6。G 除以10的余數(shù)是天干,Z 除以12的余數(shù)是地支。
但是不對(duì), 麻煩有懂也告知下
PHP 的實(shí)現(xiàn)完整代碼format("Y"); $lunarMonth = $dateTime->format("n"); $lunarDay = $dateTime->format("j"); // 檢查是否合法 if (!$this->checkLunarDate($lunarYear, $lunarMonth, $lunarDay, $leapMonthFlag)) { return ""; } $offset = 0; for ($i = self::MIN_YEAR; $i < $lunarYear; $i++) { $yearDaysCount = $this->getYearDays($i); // 求陰歷某年天數(shù) $offset += $yearDaysCount; } //計(jì)算該年閏幾月 $leapMonth = $this->getLeapMonth($lunarYear); if ($leapMonthFlag && $leapMonth != $lunarMonth) { // 您輸入的閏月標(biāo)志有誤 return ""; } if ($leapMonth == 0 || ($lunarMonth < $leapMonth) || ($lunarMonth == $leapMonth && !$leapMonthFlag)) { for ($i = 1; $i < $lunarMonth; $i++) { $tempMonthDaysCount = $this->getMonthDays($lunarYear, $i); $offset += $tempMonthDaysCount; } // 檢查日期是否大于最大天 if ($lunarDay > $this->getMonthDays($lunarYear, $lunarMonth)) { // 不合法的農(nóng)歷日期 return ""; } $offset += intval($lunarDay); // 加上當(dāng)月的天數(shù) } else { //當(dāng)年有閏月,且月份晚于或等于閏月 for ($i = 1; $i < $lunarMonth; $i++) { $tempMonthDaysCount = $this->getMonthDays($lunarYear, $i); $offset += $tempMonthDaysCount; } if ($lunarMonth > $leapMonth) { $temp = $this->getLeapMonthDays($lunarYear); // 計(jì)算閏月天數(shù) $offset += $temp; // 加上閏月天數(shù) if ($lunarDay > $this->getMonthDays($lunarYear, $lunarMonth)) { // 不合法的農(nóng)歷日期 return ""; } $offset += intval($lunarDay); } else { // 如果需要計(jì)算的是閏月,則應(yīng)首先加上與閏月對(duì)應(yīng)的普通月的天數(shù) // 計(jì)算月為閏月 $temp = $this->getMonthDays($lunarYear, $lunarMonth); // 計(jì)算非閏月天數(shù) $offset += $temp; if ($lunarDay > $this->getLeapMonthDays($lunarYear)) { // 不合法的農(nóng)歷日期 return ""; } $offset += intval($lunarDay); } } try { $newDateTime = new DateTime(self::START_DATE_STR); } catch (Exception $exception) { return ""; } $sumH = 24 * $offset; $newDateTime->add(new DateInterval("PT" . $sumH . "H")); return $newDateTime->format("Y-m-d"); } /** * 把陽歷轉(zhuǎn)換為中文的陰歷 * @param string $date * @return string */ public function solarToChineseLunar($date) { $dateTime = new DateTime($date); list($lunarYear, $lunarMonth, $lunarDay, $leapMonth, $leapMonthFlag) = $this->calculateLunar($dateTime); $result = ""; if($leapMonthFlag && $lunarMonth == $leapMonth){ $result .= "閏"; } $solarYear = (int)$dateTime->format("Y"); $solarMoth = (int)$dateTime->format("n"); $solarDay = (int)$dateTime->format("j"); $result .= self::CHINESE_NUMBER_SPECIAL[$lunarMonth-1] . "月"; $result .= $this->chineseDayString($lunarDay) . "日"; // 年的天干地支 $yGanZhi = $this->yearGanZhi($lunarYear); // 生肖屬相 $yShengXiao = $this->yearShengXiao($lunarYear); $result .= "," . $yGanZhi . "年 [" . $yShengXiao . "年]"; // 月的天干地支 $mTianGanDiZhi = $this->mothGanZhi($solarYear, $solarMoth, $solarDay); $result .= "," . $mTianGanDiZhi . "月"; // 日的天干地支 $dTianGanDiZhi = $this->dayGanZhi($solarYear, $solarMoth, $solarDay); $result .= "," . $dTianGanDiZhi . "日"; return $result; } /** * 陽歷轉(zhuǎn)換為簡單的中文陰歷 * @param string $date * @return string */ public function solarToSimpleLunar($date) { $dateTime = new DateTime($date); list($lunarYear, $lunarMonth, $lunarDay, $leapMonth, $leapMonthFlag) = $this->calculateLunar($dateTime); $result = $lunarYear . "年"; if($leapMonthFlag && $lunarMonth == $leapMonth) { $result .= "閏"; } if($lunarMonth < 10){ $result .= "0" . $lunarMonth . "月"; } else { $result .= $lunarMonth . "月"; } if($lunarDay < 10){ $result .= "0" . $lunarDay . "日"; } else { $result .= $lunarDay . "日"; } return $result; } /** * 陽歷轉(zhuǎn)為正常的陰歷 * @param string $date * @param bool $isLeapMonth 是否是閏月 * @return string */ public function solarToLunar($date, &$isLeapMonth = false) { $dateTime = new DateTime($date); list($lunarYear, $lunarMonth, $lunarDay, $leapMonth, $leapMonthFlag) = $this->calculateLunar($dateTime); $result = $lunarYear . "-"; if($lunarMonth < 10){ $result .= "0" . $lunarMonth . "-"; } else { $result .= $lunarMonth . "-"; } if($lunarDay < 10){ $result .= "0" . $lunarDay; } else { $result .= $lunarDay; } $isLeapMonth = false; if($leapMonthFlag && $lunarMonth == $leapMonth) { $isLeapMonth = true; } return $result; } /** * 計(jì)算當(dāng)前日期的陰歷 * @param DateTime $dateTime * @return array */ private function calculateLunar($dateTime) { $i = 0; $temp = 0; $leapMonthFlag = false; $isLeapYear = false; $startDate = new DateTime(self::START_DATE_STR); $offset = $this->daysBwteen($dateTime, $startDate); for($i = self::MIN_YEAR; $i < self::MAX_YEAR; $i++){ $temp = $this->getYearDays($i); //求當(dāng)年農(nóng)歷年天數(shù) if($offset - $temp < 1){ break; } else { $offset -= $temp; } } $lunarYear = $i; $leapMonth = $this->getLeapMonth($lunarYear); //計(jì)算該年閏哪個(gè)月 //設(shè)定當(dāng)年是否有閏月 if($leapMonth > 0 ){ $isLeapYear = true; } else { $isLeapYear = false; } for($i = 1; $i <= 12; $i++){ if($i == $leapMonth + 1 && $isLeapYear){ $temp = $this->getLeapMonthDays($lunarYear); $isLeapYear = false; $leapMonthFlag = true; $i--; } else { $temp = $this->getMonthDays($lunarYear, $i); } $offset -= $temp; if($offset <= 0){ break; } } $offset += $temp; $lunarMonth = $i; $lunarDay = $offset; return [$lunarYear, $lunarMonth, $lunarDay, $leapMonth, $leapMonthFlag]; } /** * 檢查陰歷是否合法 * @param int $lunarYear * @param int $lunarMonth * @param int $lunarDay * @param bool $leapMonthFlag * @return bool * @throws Exception */ private function checkLunarDate($lunarYear, $lunarMonth, $lunarDay, $leapMonthFlag = false) { if ($lunarYear < self::MIN_YEAR || $lunarYear > self::MAX_YEAR) { // 非法農(nóng)歷年份 return false; } if ($lunarMonth < 1 || $lunarMonth > 12) { // 非法農(nóng)歷月份 return false; } if ($lunarDay < 1 || $lunarDay > 30) { // 中國的月最多30天 // 非法農(nóng)歷天數(shù) return false; } $leap = $this->getLeapMonth($lunarYear); // 計(jì)算該年應(yīng)該閏哪個(gè)月 if ($leapMonthFlag == true && $lunarMonth != $leap) { // 非法閏月 return false; } return true; } /** * 計(jì)算該月總天數(shù) * @param int $year * @param int $month * @return int */ private function getMonthDays($year, $month) { if ($month > 31 || $month < 0) { // error month return 0; } // 0X0FFFF[0000 {1111 1111 1111} 1111]中間12位代表12個(gè)月,1為大月,0為小月 $bit = 1 << (16 - $month); if (((self::LUNAR_INFO[$year - 1900] & 0x0FFFF) & $bit) == 0) { return 29; } return 30; } /** * 計(jì)算陰歷年的總天數(shù) * @param int $year * @return int */ private function getYearDays($year) { $sum = 29 * 12; for ($i = 0x8000; $i >= 0x8; $i >>= 1) { if ((self::LUNAR_INFO[$year - 1900] & 0xfff0 & $i) != 0) { $sum++; } } return $sum + $this->getLeapMonthDays($year); } /** * 計(jì)算陰歷年閏月多少天 * @param int $year * @return int */ private function getLeapMonthDays($year) { if ($this->getLeapMonth($year) != 0) { if ((self::LUNAR_INFO[$year - 1900] & 0xf0000) == 0) { return 29; } return 30; } return 0; } /** * 計(jì)算陰歷年閏哪個(gè)月 1-12 , 沒閏傳回 0 * @param int $year * @return int */ private function getLeapMonth($year) { return (int)(self::LUNAR_INFO[$year - 1900] & 0xf); } /** * 計(jì)算差的天數(shù) * @param DateTime $date * @param DateTime $startDate * @return int */ private function daysBwteen($date, $startDate) { $subValue = floatval($date->getTimestamp() - $startDate->getTimestamp()) / 86400.0 + 0.5; return intval($subValue); } /** * 計(jì)算年天干地支 * @param $lunarYear * @return string */ private function yearGanZhi($lunarYear) { // 年數(shù)先減三,除10余數(shù)是天干,基數(shù)改用12除,余數(shù)便是地支年 (如果余數(shù)為 0 ,則取最大序號(hào)) $yJiShu = $lunarYear - 3; $yTianGan = ($yJiShu % 10 == 0) ? 10 : $yJiShu % 10; $yDiZhi = ($yJiShu % 12 == 0) ? 10 : $yJiShu % 12; $yGanZhi = self::TIAN_GAN[$yTianGan - 1] . self::DI_ZHI[$yDiZhi - 1]; // // 由于是從 0 開始,這里再減一 return $yGanZhi; } /** * 計(jì)算年的生肖屬相 * @param $lunarYear * @return mixed */ private function yearShengXiao($lunarYear) { // TODO 至于為什么這樣弄, 我也沒搞清楚 return self::SHENG_XIAO[($lunarYear - self::MIN_YEAR + 36) % 12]; // 年的屬相 } // TODO 尚未實(shí)現(xiàn) /** * 計(jì)算日的天干地支 * @param $solarYear * @param $solarMoth * @param $solarDay * @return string */ private function dayGanZhi($solarYear, $solarMoth, $solarDay) { return ""; } // TODO 尚未實(shí)現(xiàn) /** * 計(jì)算月的天干地支 * @param $solarYear * @param $solarMoth * @param $solarDay * @return string */ private function mothGanZhi($solarYear, $solarMoth, $solarDay) { return ""; } /** * 把天轉(zhuǎn)換為中文字符 * @param int $day * @return mixed|string */ private function chineseDayString($day) { $chineseTen = ["初", "十", "廿", "三"]; $n = 0; if($day % 10 == 0){ $n = 9; } else { $n = $day % 10 - 1; } if($day > 30){ return ""; } if($day == 20){ return "二十"; } else if($day == 10){ return "初十"; } else { return $chineseTen[$day / 10] . self::CHINESE_NUMBER[$n]; } } } $solarLunar = new SolarLunar(); $solarDate = "2010-01-05"; $new_date = $solarLunar->solarToChineseLunar($solarDate); var_dump($solarDate . " 轉(zhuǎn)為陰歷: " . $new_date); $new_date = $solarLunar->solarToSimpleLunar($solarDate); var_dump($solarDate . " 轉(zhuǎn)為陰歷, 中文: " . $new_date); $new_date = $solarLunar->solarToLunar($solarDate, $isLeapMonth); var_dump("是否是閏月: " . ($isLeapMonth ? "是" : "否")); var_dump($solarDate . " 轉(zhuǎn)為陰歷: " . $new_date); $lunarDate = "2099-11-25"; $new_date = $solarLunar->lunarToSolar($lunarDate, false); var_dump($lunarDate . " 轉(zhuǎn)新歷為: " . $new_date);
輸出:
string(67) "2010-01-05 轉(zhuǎn)為陰歷: 冬月廿一日,己丑年 [牛年],月,日" string(50) "2010-01-05 轉(zhuǎn)為陰歷, 中文: 2009年11月21日" string(20) "是否是閏月: 否" string(35) "2010-01-05 轉(zhuǎn)為陰歷: 2009-11-21" string(35) "2099-11-25 轉(zhuǎn)新歷為: 2100-01-05"GO 實(shí)現(xiàn)方式
https://github.com/nosixtools...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/30847.html
摘要:背景最近做到一個(gè)項(xiàng)目需要陰歷與陽歷的相互轉(zhuǎn)換網(wǎng)上找了很多資料發(fā)現(xiàn)很多都是不準(zhǔn)的但是給了我參考價(jià)值算法借用百度百科的陽歷太陽歷又稱為陽歷,是以地球繞太陽公轉(zhuǎn)的運(yùn)動(dòng)周期為基礎(chǔ)而制定的歷法。 背景 最近做到一個(gè)項(xiàng)目, 需要陰歷與陽歷的相互轉(zhuǎn)換, 網(wǎng)上找了很多資料, 發(fā)現(xiàn)很多都是不準(zhǔn)的, 但是給了我參考價(jià)值 算法 借用百度百科的 : 陽歷 太陽歷又稱為陽歷,是以地球繞太陽公轉(zhuǎn)的運(yùn)動(dòng)周期為基礎(chǔ)而...
摘要:背景最近做到一個(gè)項(xiàng)目需要陰歷與陽歷的相互轉(zhuǎn)換網(wǎng)上找了很多資料發(fā)現(xiàn)很多都是不準(zhǔn)的但是給了我參考價(jià)值算法借用百度百科的陽歷太陽歷又稱為陽歷,是以地球繞太陽公轉(zhuǎn)的運(yùn)動(dòng)周期為基礎(chǔ)而制定的歷法。 背景 最近做到一個(gè)項(xiàng)目, 需要陰歷與陽歷的相互轉(zhuǎn)換, 網(wǎng)上找了很多資料, 發(fā)現(xiàn)很多都是不準(zhǔn)的, 但是給了我參考價(jià)值 算法 借用百度百科的 : 陽歷 太陽歷又稱為陽歷,是以地球繞太陽公轉(zhuǎn)的運(yùn)動(dòng)周期為基礎(chǔ)而...
知識(shí)普及 陽歷:就是以太陽來計(jì)算日期的一類歷法; 陰歷:根據(jù)月亮周期制定出的歷法,由陰轉(zhuǎn)晴,再由晴轉(zhuǎn)陰為一個(gè)月,換算下來合29天12個(gè)小時(shí)44分零二秒八,接近30天。 公歷:屬陽歷的一種,我國現(xiàn)在使用的就是公歷; 農(nóng)歷:我國的農(nóng)歷是一種陰陽合歷,用來指導(dǎo)農(nóng)業(yè)十分方便。 總結(jié)來說公歷屬于陽歷,但是陽歷并不一定是公歷。農(nóng)歷不是陰歷,而是陰陽歷,是以陰歷為主,陽歷為輔。 公歷:用阿拉伯?dāng)?shù)...
引言 我們正處在一個(gè)知識(shí)爆炸的時(shí)代,伴隨著信息量的劇增和人工智能的蓬勃發(fā)展,互聯(lián)網(wǎng)公司越發(fā)具有強(qiáng)烈的個(gè)性化、智能化信息展示的需求。而信息展示個(gè)性化的典型應(yīng)用主要包括搜索列表、推薦列表、廣告展示等等。 很多人不知道的是,看似簡單的個(gè)性化信息展示背后,涉及大量的數(shù)據(jù)、算法以及工程架構(gòu)技術(shù),這些足以讓大部分互聯(lián)網(wǎng)公司望而卻步。究其根本原因,個(gè)性化信息展示背后的技術(shù)是排序?qū)W習(xí)問題(Learning to ...
閱讀 1121·2021-09-22 15:32
閱讀 1722·2019-08-30 15:53
閱讀 3253·2019-08-30 15:53
閱讀 1404·2019-08-30 15:43
閱讀 453·2019-08-28 18:28
閱讀 2566·2019-08-26 18:18
閱讀 668·2019-08-26 13:58
閱讀 2528·2019-08-26 12:10