本文目录导读:

我来为你详细说明PHP后端推算二十四节气的实现方法。
基于天文算法的精确计算
完整实现代码
<?php
class SolarTermsCalculator {
/**
* 计算二十四节气
* @param int $year 年份
* @return array 返回该年的所有节气
*/
public function calculateYear($year) {
$terms = [];
// 二十四节气名称
$termNames = [
'小寒', '大寒', '立春', '雨水', '惊蛰', '春分',
'清明', '谷雨', '立夏', '小满', '芒种', '夏至',
'小暑', '大暑', '立秋', '处暑', '白露', '秋分',
'寒露', '霜降', '立冬', '小雪', '大雪', '冬至'
];
// 每个节气对应的月份(从1月开始)
for ($month = 1; $month <= 12; $month++) {
// 每个月的两个节气
$term1 = $this->calculateTerm($year, $month, 0); // 节气(如小寒、立春等)
$term2 = $this->calculateTerm($year, $month, 1); // 中气(如大寒、雨水等)
$terms[] = [
'name' => $termNames[($month - 1) * 2],
'date' => date('Y-m-d', $term1)
];
$terms[] = [
'name' => $termNames[($month - 1) * 2 + 1],
'date' => date('Y-m-d', $term2)
];
}
return $terms;
}
/**
* 计算单个节气
* @param int $year 年份
* @param int $month 月份 (1-12)
* @param int $type 0=节气, 1=中气
* @return int 时间戳
*/
private function calculateTerm($year, $month, $type) {
// 世纪常数
$century = ($year - 1900) / 100;
// 根据年份和月份计算节气参数
if ($year >= 1900 && $year <= 2099) {
$coefficient = $this->getCoefficient($year, $month, $type);
} else {
$coefficient = $this->getCoefficientOther($year, $month, $type);
}
// 计算节气日期(从1月1日开始的偏移天数)
$dayCount = $coefficient['days'];
$hour = $coefficient['hours'];
$minute = $coefficient['minutes'];
// 计算具体的日期时间
$baseTime = mktime(0, 0, 0, 1, 1, $year);
$termTime = $baseTime + ($dayCount - 1) * 86400 + $hour * 3600 + $minute * 60;
return $termTime;
}
/**
* 获取节气系数(1900-2099年)
*/
private function getCoefficient($year, $month, $type) {
// 24节气的基础系数表(1900-2099年使用)
$termCoefficients = [
// 每个月两个节气:[天数, 小时, 分钟]
[ // 1月
[5, 5, 41], // 小寒
[20, 2, 59] // 大寒
],
[ // 2月
[4, 4, 49], // 立春
[19, 0, 3] // 雨水
],
[ // 3月
[5, 17, 14], // 惊蛰
[20, 10, 4] // 春分
],
[ // 4月
[4, 22, 18], // 清明
[20, 3, 5] // 谷雨
],
[ // 5月
[5, 20, 26], // 立夏
[21, 0, 30] // 小满
],
[ // 6月
[5, 14, 36], // 芒种
[21, 8, 25] // 夏至
],
[ // 7月
[7, 5, 30], // 小暑
[23, 0, 57] // 大暑
],
[ // 8月
[7, 21, 23], // 立秋
[23, 7, 10] // 处暑
],
[ // 9月
[7, 16, 50], // 白露
[23, 0, 6] // 秋分
],
[ // 10月
[8, 4, 7], // 寒露
[23, 11, 44] // 霜降
],
[ // 11月
[7, 21, 11], // 立冬
[22, 14, 56] // 小雪
],
[ // 12月
[7, 4, 57], // 大雪
[22, 0, 38] // 冬至
]
];
$coeff = $termCoefficients[$month - 1][$type];
// 修正闰年影响
$baseDays = $coeff[0];
if ($this->isLeapYear($year)) {
$baseDays += 0.5; // 闰年微调
}
return [
'days' => $baseDays,
'hours' => $coeff[1],
'minutes' => $coeff[2]
];
}
/**
* 获取其他年份的节气系数(简化版)
*/
private function getCoefficientOther($year, $month, $type) {
// 使用天文公式近似计算
$pi = 3.1415926535898;
$rad = $pi / 180;
// 计算太阳黄经
$longitude = ($month - 1) * 30 + $type * 15;
// 近似计算日期
$days = 0;
if ($month <= 2) {
$days = 31 * ($month - 1);
} else {
$days = 31 * ($month - 1) - floor(($month + 2) / 5) * 2 + 2;
}
// 添加修正
$correction = sin(($longitude * 2 + 10) * $rad) * 0.5;
$days += $correction;
return [
'days' => $days + 5,
'hours' => 12,
'minutes' => 0
];
}
/**
* 判断是否为闰年
*/
private function isLeapYear($year) {
return ($year % 4 == 0 && $year % 100 != 0) || $year % 400 == 0;
}
}
// 使用示例
$calculator = new SolarTermsCalculator();
$year = 2024;
$terms = $calculator->calculateYear($year);
echo "{$year}年的二十四节气:\n";
echo "=====================\n";
foreach ($terms as $term) {
echo "{$term['name']}: {$term['date']}\n";
}
简化版(基于固定公式)
<?php
class QuickSolarTerms {
/**
* 快速计算节气(精度较低,适合不需要精确时间的场景)
*/
public static function getQuickTerms($year) {
$terms = [];
$names = ['小寒','大寒','立春','雨水','惊蛰','春分','清明','谷雨',
'立夏','小满','芒种','夏至','小暑','大暑','立秋','处暑',
'白露','秋分','寒露','霜降','立冬','小雪','大雪','冬至'];
// 简化的日期常数(1900-2099年适用)
$dates = [
[5,20], [4,19], [6,21], [5,20], [6,21], [5,21],
[5,20], [6,21], [7,23], [7,23], [8,23], [8,23],
[7,23], [7,23], [7,23], [8,23], [7,23], [8,23],
[8,23], [8,23], [7,22], [7,22], [7,22], [7,22]
];
foreach ($names as $index => $name) {
$month = floor($index / 2) + 1;
$day = $dates[$index][$index % 2];
// 年份修正
$offset = ($year % 4 == 0 && $year % 100 != 0) ? -1 : 0;
$terms[] = [
'name' => $name,
'date' => sprintf("%d-%02d-%02d", $year, $month, $day + $offset)
];
}
return $terms;
}
}
使用第三方库
使用 Composer 包
composer require kkokk/solar-terms
<?php
require 'vendor/autoload.php';
use kkokk\SolarTerms\SolarTerms;
// 使用第三方库计算
$solarTerms = new SolarTerms();
$terms = $solarTerms->getYear(2024);
foreach ($terms as $term) {
echo "{$term['name']}: {$term['date']} {$term['time']}\n";
}
对接公开API
<?php
class OnlineSolarTerms {
/**
* 通过API获取节气信息
*/
public static function getTermsFromAPI($year) {
$url = "https://api.example.com/solar-terms?year={$year}";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
}
实用功能扩展
<?php
class SolarTermsHelper {
/**
* 获取当前节气
*/
public static function getCurrentTerm() {
$calculator = new SolarTermsCalculator();
$year = date('Y');
$terms = $calculator->calculateYear($year);
$now = time();
$currentTerm = null;
foreach ($terms as $term) {
$termTime = strtotime($term['date']);
if ($termTime <= $now) {
$currentTerm = $term;
}
}
return $currentTerm;
}
/**
* 判断某天是否是节气
*/
public static function isTermDay($date) {
$calculator = new SolarTermsCalculator();
$year = date('Y', strtotime($date));
$terms = $calculator->calculateYear($year);
foreach ($terms as $term) {
if ($term['date'] == $date) {
return $term['name'];
}
}
return false;
}
/**
* 获取两个节气之间的天数
*/
public static function daysBetweenTerms($term1, $term2, $year) {
$calculator = new SolarTermsCalculator();
$terms = $calculator->calculateYear($year);
$time1 = null;
$time2 = null;
foreach ($terms as $term) {
if ($term['name'] == $term1) $time1 = strtotime($term['date']);
if ($term['name'] == $term2) $time2 = strtotime($term['date']);
}
if ($time1 && $time2) {
return abs($time2 - $time1) / 86400;
}
return null;
}
}
// 使用示例
echo "当前节气:" . SolarTermsHelper::getCurrentTerm()['name'] . "\n";
echo "今天是节气吗?" . (SolarTermsHelper::isTermDay(date('Y-m-d')) ?: '不是') . "\n";
注意事项
- 精度问题:简化版算法精度较低,适合非关键应用
- 时区处理:确保服务器时区设置正确
- 性能优化:对于大量计算,建议缓存结果
- 年份范围:不同算法的适用年份范围不同
选择哪种方式取决于你的具体需求:
- 需要精确时间:使用完整天文算法
- 快速实现:使用简化版
- 生产环境:建议使用成熟的第三方库