'春节', '0115' => '元宵节', '0505' => '端午节', '0707' => '七夕节', '0815' => '中秋节', '0909' => '重阳节', '1208' => '腊八节', '1230' => '除夕' ); // 阳历节日 private static $solar_festivals = array( '0101' => '元旦', '0214' => '情人节', '0308' => '妇女节', '0312' => '植树节', '0401' => '愚人节', '0501' => '劳动节', '0504' => '青年节', '0601' => '儿童节', '0701' => '建党节', '0801' => '建军节', '0910' => '教师节', '1001' => '国庆节', '1225' => '圣诞节' ); public static function solar_to_lunar($year, $month, $day) { // 计算与1900年1月31日相差的天数 $offset = self::get_offset_days($year, $month, $day); // 计算农历年份 $i = 1900; for($i = 1900; $i < 2101 && $offset > 0; $i++) { $year_days = self::get_year_days($i); $offset -= $year_days; } if($offset < 0) { $offset += $year_days; $i--; } $lunar_year = $i; // 计算农历月份 $leap = self::get_leap_month($lunar_year); $is_leap = false; for($i = 1; $i < 13 && $offset > 0; $i++) { if($leap > 0 && $i == ($leap + 1) && !$is_leap) { --$i; $is_leap = true; $days = self::get_leap_days($lunar_year); } else { $days = self::get_month_days($lunar_year, $i); } if($is_leap && $i == ($leap + 1)) { $is_leap = false; } $offset -= $days; } if($offset == 0 && $leap > 0 && $i == $leap + 1) { if($is_leap) { $is_leap = false; } else { $is_leap = true; --$i; } } if($offset < 0) { $offset += $days; --$i; } $lunar_month = $i; $lunar_day = $offset + 1; // 计算天干地支年 $gan_year = ($lunar_year - 4) % 10; $zhi_year = ($lunar_year - 4) % 12; // 构建结果数组 $result = array( 'year' => $lunar_year, 'month' => $lunar_month, 'day' => $lunar_day, 'leap' => $is_leap, 'gan_year' => self::$gan[$gan_year], 'zhi_year' => self::$zhi[$zhi_year], 'animal' => self::$animals[$zhi_year] ); // 添加节气信息 $result['solar_term'] = self::get_solar_term($year, $month, $day); // 添加阳历节日 $solar_festival_key = sprintf('%02d%02d', $month, $day); $result['solar_festival'] = isset(self::$solar_festivals[$solar_festival_key]) ? self::$solar_festivals[$solar_festival_key] : ''; // 添加农历节日 $lunar_festival_key = sprintf('%02d%02d', $lunar_month, $lunar_day); $result['lunar_festival'] = isset(self::$lunar_festivals[$lunar_festival_key]) ? self::$lunar_festivals[$lunar_festival_key] : ''; // 特殊处理除夕 if ($lunar_month == 12 && $lunar_day == self::get_month_days($lunar_year, 12)) { $result['lunar_festival'] = '除夕'; } return $result; } private static function get_offset_days($year, $month, $day) { $offset = 0; for($i = 1900; $i < $year; $i++) { if(self::is_leap_year($i)) { $offset += 366; } else { $offset += 365; } } for($i = 1; $i < $month; $i++) { $offset += self::get_solar_month_days($year, $i); } $offset += $day - 1; return $offset - 30; } private static function is_leap_year($year) { return ($year % 4 == 0 && $year % 100 != 0) || ($year % 400 == 0); } private static function get_solar_month_days($year, $month) { $days = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); if ($month == 2 && self::is_leap_year($year)) { return 29; } return $days[$month - 1]; } private static function get_year_days($year) { $sum = 348; for ($i = 0x8000; $i > 0x8; $i >>= 1) { $sum += (self::$lunar_info[$year - 1900] & $i) ? 1 : 0; } return $sum + self::get_leap_days($year); } private static function get_leap_days($year) { if (self::get_leap_month($year)) { return (self::$lunar_info[$year - 1900] & 0x10000) ? 30 : 29; } return 0; } private static function get_leap_month($year) { return self::$lunar_info[$year - 1900] & 0xf; } private static function get_month_days($year, $month) { return (self::$lunar_info[$year - 1900] & (0x10000 >> $month)) ? 30 : 29; } private static function get_solar_term($year, $month, $day) { $index = ($month - 1) * 2; $term1_day = floor(self::get_term_day($year, $index)); $term2_day = floor(self::get_term_day($year, $index + 1)); if ($day == $term1_day) { return self::$solar_terms[$index]; } if ($day == $term2_day) { return self::$solar_terms[$index + 1]; } return ''; } private static function get_term_day($year, $n) { $offset = self::$solar_terms_offset[$n]; // 确保 offset 是一个有效的字符串 if (!is_string($offset) || strlen($offset) < 4) { return 0; // 返回一个默认值以避免错误 } $diff = $year - 1900; $century = floor($diff / 100); $year_offset = $diff % 100; // 修正计算公式 $day = (int)substr($offset, 0, 2) + $century * (int)substr($offset, 2, 1) + floor($year_offset * (int)substr($offset, 3, 1) / 100); return $day; } }