PHP项目节气计算如何后端推算二十四节气

wen PHP项目 34

本文目录导读:

PHP项目节气计算如何后端推算二十四节气

  1. 基于天文算法的精确计算
  2. 简化版(基于固定公式)
  3. 使用第三方库
  4. 实用功能扩展
  5. 注意事项

我来为你详细说明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";

注意事项

  1. 精度问题:简化版算法精度较低,适合非关键应用
  2. 时区处理:确保服务器时区设置正确
  3. 性能优化:对于大量计算,建议缓存结果
  4. 年份范围:不同算法的适用年份范围不同

选择哪种方式取决于你的具体需求:

  • 需要精确时间:使用完整天文算法
  • 快速实现:使用简化版
  • 生产环境:建议使用成熟的第三方库

抱歉,评论功能暂时关闭!