$yDiZhi=($yJiShu% 12==0)?10 :美元yJiShu % 12$ yganzhi=self :3360 Tian _ gan[$ ytiangan-1]。self :3360 di _ zhi[$ y dizhi-1];////从0开始,所以我在这里再减去r
eturn $yGanZhi;
}
月的干支算法
网上搜索了, 没找到好的实现方式, 麻烦知道的在这里说一下,
日的干支算法
网上搜到的:
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 是世纪数减一,y 是年份后两位,M 是月份,d 是日数。1月和2月按上一年的13月和14月来算。奇数月i=0,偶数月i=6。G 除以10的余数是天干,Z 除以12的余数是地支。
但是不对, 麻烦有懂也告知下
PHP 的实现完整代码
<?php
/**
* 阳历和新历的转换
*/
class SolarLunar {
// 最小年
const MIN_YEAR = 1900;
// 最大年
const MAX_YEAR = 2100;
// 开始的日期
const START_DATE_STR = "1900-01-30";
const CHINESE_NUMBER = ["一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二"];
const CHINESE_NUMBER_SPECIAL = ["正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "冬", "腊"];
const TIAN_GAN = ["甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"];
const DI_ZHI = ["子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"];
const SHENG_XIAO = ["鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪"];
// 阴历年份的数据
const LUNAR_INFO = [
0x04bd8,0x04ae0,0x0a570,0x054d5,0x0d260,0x0d950,0x16554,0x056a0,0x09ad0,0x055d2,//1900-1909
0x04ae0,0x0a5b6,0x0a4d0,0x0d250,0x1d255,0x0b540,0x0d6a0,0x0ada2,0x095b0,0x14977,//1910-1919
0x04970,0x0a4b0,0x0b4b5,0x06a50,0x06d40,0x1ab54,0x02b60,0x09570,0x052f2,0x04970,//1920-1929
0x06566,0x0d4a0,0x0ea50,0x06e95,0x05ad0,0x02b60,0x186e3,0x092e0,0x1c8d7,0x0c950,//1930-1939
0x0d4a0,0x1d8a6,0x0b550,0x056a0,0x1a5b4,0x025d0,0x092d0,0x0d2b2,0x0a950,0x0b557,//1940-1949
0x06ca0,0x0b550,0x15355,0x04da0,0x0a5b0,0x14573,0x052b0,0x0a9a8,0x0e950,0x06aa0,//1950-1959
0x0aea6,0x0ab50,0x04b60,0x0aae4,0x0a570,0x05260,0x0f263,0x0d950,0x05b57,0x056a0,//1960-1969
0x096d0,0x04dd5,0x04ad0,0x0a4d0,0x0d4d4,0x0d250,0x0d558,0x0b540,0x0b6a0,0x195a6,//1970-1979
0x095b0,0x049b0,0x0a974,0x0a4b0,0x0b27a,0x06a50,0x06d40,0x0af46,0x0ab60,0x09570,//1980-1989
0x04af5,0x04970,0x064b0,0x074a3,0x0ea50,0x06b58,0x055c0,0x0ab60,0x096d5,0x092e0,//1990-1999
0x0c960,0x0d954,0x0d4a0,0x0da50,0x07552,0x056a0,0x0abb7,0x025d0,0x092d0,0x0cab5,//2000-2009
0x0a950,0x0b4a0,0x0baa4,0x0ad50,0x055d9,0x04ba0,0x0a5b0,0x15176,0x052b0,0x0a930,//2010-2019
0x07954,0x06aa0,0x0ad50,0x05b52,0x04b60,0x0a6e6,0x0a4e0,0x0d260,0x0ea65,0x0d530,//2020-2029
0x05aa0,0x076a3,0x096d0,0x04bd7,0x04ad0,0x0a4d0,0x1d0b6,0x0d250,0x0d520,0x0dd45,//2030-2039
0x0b5a0,0x056d0,0x055b2,0x049b0,0x0a577,0x0a4b0,0x0aa50,0x1b255,0x06d20,0x0ada0,//2040-2049
0x14b63,0x09370,0x049f8,0x04970,0x064b0,0x168a6,0x0ea50, 0x06b20,0x1a6c4,0x0aae0,//2050-2059
0x0a2e0,0x0d2e3,0x0c960,0x0d557,0x0d4a0,0x0da50,0x05d55,0x056a0,0x0a6d0,0x055d4,//2060-2069
0x052d0,0x0a9b8,0x0a950,0x0b4a0,0x0b6a6,0x0ad50,0x055a0,0x0aba4,0x0a5b0,0x052b0,//2070-2079
0x0b273,0x06930,0x07337,0x06aa0,0x0ad50,0x14b55,0x04b60,0x0a570,0x054e4,0x0d160,//2080-2089
0x0e968,0x0d520,0x0daa0,0x16aa6,0x056d0,0x04ae0,0x0a9d4,0x0a2d0,0x0d150,0x0f252,//2090-2099
0x0d520];
/**
* 阴历转阳历
* @param string $date
* @param bool $leapMonthFlag
* @return string
*/
public function lunarToSolar($date = "", $leapMonthFlag = false) {
try {
$dateTime = new DateTime($date);
} catch (Exception $exception) {
return "";
}
$lunarYear = $dateTime->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); // 求阴历某年天数
$offset += $yearDaysCount;
}
//计算该年闰几月
$leapMonth = $this->getLeapMonth($lunarYear);
if ($leapMonthFlag && $leapMonth != $lunarMonth) {
// 您输入的闰月标志有误
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)) {
// 不合法的农历日期
return "";
}
$offset += intval($lunarDay); // 加上当月的天数
} else { //当年有闰月,且月份晚于或等于闰月
for ($i = 1; $i < $lunarMonth; $i++) {
$tempMonthDaysCount = $this->getMonthDays($lunarYear, $i);
$offset += $tempMonthDaysCount;
}
if ($lunarMonth > $leapMonth) {
$temp = $this->getLeapMonthDays($lunarYear); // 计算闰月天数
$offset += $temp; // 加上闰月天数
if ($lunarDay > $this->getMonthDays($lunarYear, $lunarMonth)) {
// 不合法的农历日期
return "";
}
$offset += intval($lunarDay);
} else { // 如果需要计算的是闰月,则应首先加上与闰月对应的普通月的天数
// 计算月为闰月
$temp = $this->getMonthDays($lunarYear, $lunarMonth); // 计算非闰月天数
$offset += $temp;
if ($lunarDay > $this->getLeapMonthDays($lunarYear)) {
// 不合法的农历日期
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");
}
/**
* 把阳历转换为中文的阴历
* @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;
}
/**
* 阳历转换为简单的中文阴历
* @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;
}
/**
* 阳历转为正常的阴历
* @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;
}
/**
* 计算当前日期的阴历
* @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); //求当年农历年天数
if($offset – $temp < 1){
break;
} else {
$offset -= $temp;
}
}
$lunarYear = $i;
$leapMonth = $this->getLeapMonth($lunarYear); //计算该年闰哪个月
//设定当年是否有闰月
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) {
// 非法农历年份
return false;
}
if ($lunarMonth < 1 || $lunarMonth > 12) {
// 非法农历月份
return false;
}
if ($lunarDay < 1 || $lunarDay > 30) { // 中国的月最多30天
// 非法农历天数
return false;
}
$leap = $this->getLeapMonth($lunarYear); // 计算该年应该闰哪个月
if ($leapMonthFlag == true && $lunarMonth != $leap) {
// 非法闰月
return false;
}
return true;
}
/**
* 计算该月总天数
* @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个月,1为大月,0为小月
$bit = 1 << (16 – $month);
if (((self::LUNAR_INFO[$year – 1900] & 0x0FFFF) & $bit) == 0) {
return 29;
}
return 30;
}
/**
* 计算阴历年的总天数
* @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);
}
/**
* 计算阴历年闰月多少天
* @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;
}
/**
* 计算阴历年闰哪个月 1-12 , 没闰传回 0
* @param int $year
* @return int
*/
private function getLeapMonth($year) {
return (int)(self::LUNAR_INFO[$year – 1900] & 0xf);
}
/**
* 计算差的天数
* @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);
}
/**
* 计算年天干地支
* @param $lunarYear
* @return string
*/
private function yearGanZhi($lunarYear)
{
// 年数先减三,除10余数是天干,基数改用12除,余数便是地支年 (如果余数为 0 ,则取最大序号)
$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;
}
/**
* 计算年的生肖属相
* @param $lunarYear
* @return mixed
*/
private function yearShengXiao($lunarYear)
{
// TODO 至于为什么这样弄, 我也没搞清楚
return self::SHENG_XIAO[($lunarYear – self::MIN_YEAR + 36) % 12]; // 年的属相
}
// TODO 尚未实现
/**
* 计算日的天干地支
* @param $solarYear
* @param $solarMoth
* @param $solarDay
* @return string
*/
private function dayGanZhi($solarYear, $solarMoth, $solarDay)
{
return "";
}
// TODO 尚未实现
/**
* 计算月的天干地支
* @param $solarYear
* @param $solarMoth
* @param $solarDay
* @return string
*/
private function mothGanZhi($solarYear, $solarMoth, $solarDay)
{
return "";
}
/**
* 把天转换为中文字符
* @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 . " 转为阴历: " . $new_date);
$new_date = $solarLunar->solarToSimpleLunar($solarDate);
var_dump($solarDate . " 转为阴历, 中文: " . $new_date);
$new_date = $solarLunar->solarToLunar($solarDate, $isLeapMonth);
var_dump("是否是闰月: " . ($isLeapMonth ? "是" : "否"));
var_dump($solarDate . " 转为阴历: " . $new_date);
$lunarDate = "2099-11-25";
$new_date = $solarLunar->lunarToSolar($lunarDate, false);
var_dump($lunarDate . " 转新历为: " . $new_date);
输出:
string(67) "2010-01-05 转为阴历: 冬月廿一日,己丑年 [牛年],月,日"
string(50) "2010-01-05 转为阴历, 中文: 2009年11月21日"
string(20) "是否是闰月: 否"
string(35) "2010-01-05 转为阴历: 2009-11-21"
string(35) "2099-11-25 转新历为: 2100-01-05"
如果想要学习交流PHP的朋友,可以关注小编,私信【学习交流】手机用户可以直接私信,电脑端尚未开放此功能,需要下载app,我已经设置了自动回复,具体后续会自动回复各位。
1.文章《【阴历转阳历】PHP实现农历阳历的相互转换(支持1900~2100年)》援引自互联网,为网友投稿收集整理,仅供学习和研究使用,内容仅代表作者本人观点,与本网站无关,侵删请点击页脚联系方式。
2.文章《【阴历转阳历】PHP实现农历阳历的相互转换(支持1900~2100年)》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。
相关推荐
- . 现代买票为什么带上携程保险
- . 潮阳怎么去广州南站
- . 湖南马拉河怎么样
- . 烧纸为什么到三岔路口
- . 百色为什么这么热
- . 神州租车怎么样
- . 芜湖方特哪个适合儿童
- . 护肤品保养液是什么类目
- . 早晚的护肤保养有哪些项目
- . 女孩护肤品怎么保养的最好