IE盒子

搜索
查看: 84|回复: 0

php实现根据公历日期计算节气

[复制链接]

2

主题

5

帖子

8

积分

新手上路

Rank: 1

积分
8
发表于 2023-3-10 11:35:09 | 显示全部楼层 |阅读模式
节气的产生是由于地球的公转和自转的影响,当地球绕太阳公转时,太阳在地球表面上的位置不断变化,这样地球上的每个地点所接受到的阳光量和热量也不断变化,进而导致不同季节不同气候的变化。

公历的每一年分为24个节气,每个节气都对应着一个特定的天文现象,例如春分节气是在太阳到达黄道的那一天,而冬至节气则是在太阳到达黄经270°的那一天。每个节气都代表着一个季节的开始或者结束。

因此,通过计算每一天太阳所在的位置,我们可以得到该天所对应的节气,从而进行日期转节气的计算。

将阴历日期转换为节气


<?php

function getLunarSolarTerm($timestamp) {
  $year = date('Y', $timestamp);
  $month = date('n', $timestamp);
  $day = date('j', $timestamp);

  // 计算阴历
  $lunar = new Lunar();
  $lunar = $lunar->SolarToLunar($year, $month, $day);
  $lunar_year = $lunar['lunar_year'];
  $lunar_month = $lunar['lunar_month'];
  $lunar_day = $lunar['lunar_day'];

  // 计算节气
  $solarTerm = new SolarTerm();
  $solar_term = $solarTerm->getSolarTerm($lunar_year, $lunar_month, $lunar_day);
  return $solar_term;
}

$timestamp = strtotime("2023-02-15");
$solar_term = getLunarSolarTerm($timestamp);
echo "The solar term on " . date('Y-m-d', $timestamp) . " is " . $solar_term;接下来,来构建函数。
function solarToLunar($date) {
  $dateArray = explode("-", $date);
  $year = intval($dateArray[0]);
  $month = intval($dateArray[1]);
  $day = intval($dateArray[2]);
  
  // 判断是否是闰年
  $isLeap = false;
  if (($year % 4 == 0 && $year % 100 != 0) || $year % 400 == 0) {
    $isLeap = true;
  }
  
  // 每个月的天数
  $monthDays = array(31, 28 + $isLeap, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
  
  // 计算阴历的天数
  $lunarDay = 0;
  for ($i = 0; $i < $month - 1; $i++) {
    $lunarDay += $monthDays[$i];
  }
  $lunarDay += $day;
  
  // 将阴历天数转换为阴历月份和日
  $lunarMonth = 0;
  for ($i = 0; $i < 12; $i++) {
    if ($lunarDay <= $monthDays[$i]) {
      $lunarMonth = $i + 1;
      break;
    }
    $lunarDay -= $monthDays[$i];
  }
  $lunar['lunar_year'] = $year;
  $lunar['lunar_month'] = $lunarMonth;
  $lunar['lunar_day'] = $lunarDay;
  return $lunar;
}注意到,还需要将阴历日期转换为节气。下面提供一个较为粗略的算法,实际上问题比较多。
function getSolarTerm($time) {
    $solarTerms = array(
        "小寒", "大寒", "立春", "雨水",
        "惊蛰", "春分", "清明", "谷雨",
        "立夏", "小满", "芒种", "夏至",
        "小暑", "大暑", "立秋", "处暑",
        "白露", "秋分", "寒露", "霜降",
        "立冬", "小雪", "大雪", "冬至"
    );

    $d = (int)(($time - 31556925974.7 * floor($time / 31556925974.7)) / 36524.2259);
    $g = $d + 114;
    $solarTermsIndex = floor(($g - 1) * 24 / 365.2422) % 24;

    return $solarTerms[$solarTermsIndex];
}将阳历日期转换为节气


下面是阳历日期转换为节气的函数。

function getSolarTerm($date) {
  $dateArray = explode("-", $date);
  $year = intval($dateArray[0]);
  $month = intval($dateArray[1]);
  $day = intval($dateArray[2]);
  
  // 节气表
  $solarTermTable = array(
    array(array(4,19),array(5,5)),
    array(array(5,20),array(6,6)),
    array(array(6,21),array(7,7)),
    array(array(7,22),array(8,8)),
    array(array(8,23),array(9,8)),
    array(array(9,23),array(10,8)),
    array(array(10,24),array(11,7)),
    array(array(11,22),array(12,6)),
    array(array(12,22),array(1,5)),
    array(array(1,20),array(2,3)),
    array(array(2,18),array(3,5)),
    array(array(3,21),array(4,5)),
    array(array(4,20),array(5,5)),
    array(array(5,21),array(6,6)),
    array(array(6,22),array(7,7)),
    array(array(7,23),array(8,7)),
    array(array(8,23),array(9,7)),
    array(array(9,23),array(10,7)),
    array(array(10,24),array(11,6)),
    array(array(11,23),array(12,6)),
    array(array(12,21),array(1,4)),
    array(array(1,20),array(2,3)),
    array(array(2,19),array(3,4)),
    array(array(3,21),array(4,4)),
    array(array(4,21),array(5,5)),
    array(array(5,22),array(6,5)),
    array(array(6,22),array(7,7)),
    array(array(7,22),array(8,7)),
    array(array(8,22),array(9,7)),
    array(array(9,22),array(10,7)),
    array(array(10,23),array(11,7)),
    array(array(11,22),array(12,6)),
    array(array(12,21),array(1,5)),
  );
  
  $solarTerms = array("小寒","大寒","立春","雨水","惊蛰","春分",
                       "清明","谷雨","立夏","小满","芒种","夏至",
                       "小暑","大暑","立秋","处暑","白露","秋分",
"寒露","霜降","立冬","小雪","大雪","冬至");

$idx = intval(($year - 1900) * 24.22 + ($month - 1) * 2);
if ($month == 12) {
if ($day >= $solarTermTable[$idx][1][0]) {
$idx ++;
}
}
else if ($month == 1) {
if ($day < $solarTermTable[$idx][0][0]) {
$idx --;
}
}
else if ($month == $solarTermTable[$idx][1][1]) {
if ($day >= $solarTermTable[$idx][1][0]) {
$idx ++;
}
}
else if ($month == $solarTermTable[$idx][0][1]) {
if ($day < $solarTermTable[$idx][0][0]) {
$idx --;
}
}

return $solarTerms[$idx % 24];
}通过儒略日法转换节气


此算法基于计算机科学家 Peter Duffett-Smith 的节气计算方法。它通过使用儒略日数(Julian Day Number)来提高准确度,并通过计算与当前节气的距离来确定当前的节气。

function getSolarTerm($time) {
    $solarTerms = array(
        "小寒", "大寒", "立春", "雨水",
        "惊蛰", "春分", "清明", "谷雨",
        "立夏", "小满", "芒种", "夏至",
        "小暑", "大暑", "立秋", "处暑",
        "白露", "秋分", "寒露", "霜降",
        "立冬", "小雪", "大雪", "冬至"
    );

    $d = JulianDayNumber($time) - 2451545.0;
    $d0 = 365.2422 * floor($d / 365.2422);
    $l = mod($d, 365.2422);
    $g = (int)($l / 29.5306);
    $t = mod($l, 29.5306);
    $b = floor((($g * 6 + $t) * 24 + 12) / 365.2422);
    $solarTermsIndex = $g * 2 + $b;

    return $solarTerms[$solarTermsIndex];
}

function JulianDayNumber($time) {
    $jd = 2440588 + floor($time / 86400);
    $f = ($time / 86400.0 - floor($time / 86400.0)) * 86400.0;
    $jd = $jd + $f / (3600 + 24) * (3600 + 24) / 3600;
    return $jd;
}

function mod($a, $b) {
    return $a - floor($a / $b) * $b;
}
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表