Skip to content

Commit 1c4eddb

Browse files
committed
v1.3.4 新增公历日、公历时刻、农历日获取月相;新增月相获取公历日、公历时刻;更新△T参数;修复农历闰月干支错误。
1 parent 1f29ed3 commit 1c4eddb

15 files changed

Lines changed: 302 additions & 47 deletions

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,9 @@
9595
## [1.3.3] - 2025-09-08
9696
1. 修复:极端情况下八字转公历时刻出现遗漏的问题。
9797
2. 优化:代码。
98+
99+
## [1.3.4] - 2025-09-23
100+
1. 新增:公历日、公历时刻、农历日获取月相。
101+
2. 新增:月相获取公历日、公历时刻。
102+
3. 优化:更新△T参数。
103+
4. 修复:农历闰月干支错误(应随上月)。

src/culture/Phase.php

Lines changed: 69 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@
33
namespace com\tyme\culture;
44

55

6+
use com\tyme\jd\JulianDay;
67
use com\tyme\LoopTyme;
8+
use com\tyme\lunar\LunarDay;
9+
use com\tyme\lunar\LunarMonth;
10+
use com\tyme\solar\SolarDay;
11+
use com\tyme\solar\SolarTime;
12+
use com\tyme\util\ShouXingUtil;
713

814
/**
915
* 月相
@@ -12,29 +18,85 @@
1218
*/
1319
class Phase extends LoopTyme
1420
{
15-
static array $NAMES = ['朔月', '既朔月', '蛾眉新月', '蛾眉新月', '蛾眉月', '夕月', '上弦月', '上弦月', '九夜月', '宵月', '宵月', '宵月', '渐盈凸月', '小望月', '望月', '既望月', '立待月', '居待月', '寝待月', '更待月', '渐亏凸月', '下弦月', '下弦月', '有明月', '有明月', '蛾眉残月', '蛾眉残月', '残月', '晓月', '晦月'];
21+
static array $NAMES = ['新月', '蛾眉月', '上弦月', '盈凸月', '满月', '亏凸月', '下弦月', '残月'];
1622

17-
protected function __construct(?int $index = null, ?string $name = null)
23+
/**
24+
* @var int 农历年
25+
*/
26+
protected int $lunarYear;
27+
28+
/**
29+
* @var int 农历月
30+
*/
31+
protected int $lunarMonth;
32+
33+
protected function __construct(int $lunarYear, int $lunarMonth, ?int $index = null, ?string $name = null)
1834
{
1935
if ($index !== null) {
2036
parent::__construct(static::$NAMES, $index);
37+
$m = LunarMonth::fromYm($lunarYear, $lunarMonth)->next(intdiv($index, $this->getSize()));
38+
$this->lunarYear = $m->getYear();
39+
$this->lunarMonth = $m->getMonth();
2140
} else if ($name !== null) {
2241
parent::__construct(static::$NAMES, null, $name);
42+
$this->lunarYear = $lunarYear;
43+
$this->lunarMonth = $lunarMonth;
2344
}
2445
}
2546

26-
static function fromIndex(int $index): static
47+
static function fromIndex(int $lunarYear, int $lunarMonth, int $index): static
2748
{
28-
return new static($index);
49+
return new static($lunarYear, $lunarMonth, $index);
2950
}
3051

31-
static function fromName(string $name): static
52+
static function fromName(int $lunarYear, int $lunarMonth, string $name): static
3253
{
33-
return new static(null, $name);
54+
return new static($lunarYear, $lunarMonth, null, $name);
3455
}
3556

3657
function next(int $n): static
3758
{
38-
return static::fromIndex($this->nextIndex($n));
59+
$size = $this->getSize();
60+
$i = $this->index + $n;
61+
if ($i < 0) {
62+
$i -= $size;
63+
}
64+
$i = intdiv($i, $size);
65+
$m = LunarMonth::fromYm($this->lunarYear, $this->lunarMonth);
66+
if ($i != 0) {
67+
$m = $m->next($i);
68+
}
69+
return static::fromIndex($m->getYear(), $m->getMonth(), $this->nextIndex($n));
70+
}
71+
72+
function getStartSolarTime(): SolarTime
73+
{
74+
$n = (int) floor(($this->lunarYear - 2000) * 365.2422 / 29.53058886);
75+
$i = 0;
76+
$p = M_PI * 2;
77+
$jd = JulianDay::J2000 + ShouXingUtil::ONE_THIRD;
78+
$d = LunarDay::fromYmd($this->lunarYear, $this->lunarMonth, 1)->getSolarDay();
79+
while (true) {
80+
$t = ShouXingUtil::msaLonT(($n + $i) * $p) * 36525;
81+
if (!JulianDay::fromJulianDay($jd + $t - ShouXingUtil::dtT($t))->getSolarDay()->isBefore($d)) {
82+
break;
83+
}
84+
$i++;
85+
}
86+
$r = [0, 90, 180, 270];
87+
$t = ShouXingUtil::msaLonT(($n + $i + $r[intdiv($this->index, 2)] / 360.0) * $p) * 36525;
88+
return JulianDay::fromJulianDay($jd + $t - ShouXingUtil::dtT($t))->getSolarTime();
89+
}
90+
91+
function getSolarTime(): SolarTime
92+
{
93+
$t = $this->getStartSolarTime();
94+
return $this->index % 2 == 1 ? $t->next(1) : $t;
95+
}
96+
97+
function getSolarDay(): SolarDay
98+
{
99+
$d = $this->getStartSolarTime()->getSolarDay();
100+
return $this->index % 2 == 1 ? $d->next(1) : $d;
39101
}
40102
}

src/culture/PhaseDay.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
namespace com\tyme\culture;
4+
5+
6+
use com\tyme\AbstractCultureDay;
7+
8+
/**
9+
* 月相第几天
10+
* @author 6tail
11+
* @package com\tyme\culture
12+
*/
13+
class PhaseDay extends AbstractCultureDay
14+
{
15+
function __construct(Phase $phase, int $dayIndex)
16+
{
17+
parent::__construct($phase, $dayIndex);
18+
}
19+
20+
/**
21+
* 月相
22+
*
23+
* @return Phase 月相
24+
*/
25+
function getPhase(): Phase
26+
{
27+
return $this->culture;
28+
}
29+
}

src/jd/JulianDay.php

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -88,19 +88,18 @@ function getSolarDay(): SolarDay
8888
*/
8989
function getSolarTime(): SolarTime
9090
{
91-
$n = (int)($this->day + 0.5);
92-
$f = $this->day + 0.5 - $n;
91+
$d = (int)($this->day + 0.5);
92+
$f = $this->day + 0.5 - $d;
9393

94-
if ($n >= 2299161) {
95-
$c = (int)(($n - 1867216.25) / 36524.25);
96-
$n += 1 + $c - intdiv($c, 4);
94+
if ($d >= 2299161) {
95+
$c = (int)(($d - 1867216.25) / 36524.25);
96+
$d += 1 + $c - intdiv($c, 4);
9797
}
98-
$n += 1524;
99-
$y = (int)(($n - 122.1) / 365.25);
100-
$n -= (int)(365.25 * $y);
101-
$m = (int)($n / 30.601);
102-
$n -= (int)(30.601 * $m);
103-
$d = $n;
98+
$d += 1524;
99+
$y = (int)(($d - 122.1) / 365.25);
100+
$d -= (int)(365.25 * $y);
101+
$m = (int)($d / 30.601);
102+
$d -= (int)(30.601 * $m);
104103
if ($m > 13) {
105104
$m -= 12;
106105
} else {

src/lunar/LunarDay.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use com\tyme\culture\fetus\FetusDay;
1111
use com\tyme\culture\God;
1212
use com\tyme\culture\Phase;
13+
use com\tyme\culture\PhaseDay;
1314
use com\tyme\culture\ren\MinorRen;
1415
use com\tyme\culture\star\nine\NineStar;
1516
use com\tyme\culture\star\six\SixStar;
@@ -286,14 +287,32 @@ function getFetusDay(): FetusDay
286287
return FetusDay::fromLunarDay($this);
287288
}
288289

290+
/**
291+
* 月相第几天
292+
*
293+
* @return PhaseDay 月相第几天
294+
*/
295+
function getPhaseDay(): PhaseDay
296+
{
297+
$today = $this->getSolarDay();
298+
$m = $this->month->next(1);
299+
$p = Phase::fromIndex($m->getYear(), $m->getMonth(), 0);
300+
$d = $p->getSolarDay();
301+
while ($p->getSolarDay()->isAfter($today)) {
302+
$p = $p->next(-1);
303+
$d = $p->getSolarDay();
304+
}
305+
return new PhaseDay($p, $today->subtract($d));
306+
}
307+
289308
/**
290309
* 月相
291310
*
292311
* @return Phase 月相
293312
*/
294313
function getPhase(): Phase
295314
{
296-
return Phase::fromIndex($this->day - 1);
315+
return $this->getPhaseDay()->getPhase();
297316
}
298317

299318
/**

src/lunar/LunarMonth.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ function getWeeks(int $start): array
332332
*/
333333
function getSixtyCycle(): SixtyCycle
334334
{
335-
return SixtyCycle::fromName(sprintf('%s%s', HeavenStem::fromIndex(($this->year->getSixtyCycle()->getHeavenStem()->getIndex() + 1) * 2 + $this->indexInYear)->getName(), EarthBranch::fromIndex($this->indexInYear + 2)->getName()));
335+
return SixtyCycle::fromName(sprintf('%s%s', HeavenStem::fromIndex($this->year->getSixtyCycle()->getHeavenStem()->getIndex() * 2 + $this->month + 1)->getName(), EarthBranch::fromIndex($this->month + 1)->getName()));
336336
}
337337

338338
/**

src/sixtycycle/SixtyCycleHour.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,9 @@ function getNineStar(): NineStar
167167
{
168168
$solar = $this->solarTime->getSolarDay();
169169
$dongZhi = SolarTerm::fromIndex($solar->getYear(), 0);
170-
$xiaZhi = $dongZhi->next(12);
171170
$earthBranchIndex = $this->getIndexInDay() % 12;
172171
$index = [8, 5, 2][$this->day->getSixtyCycle()->getEarthBranch()->getIndex() % 3];
173-
if (!$solar->isBefore($dongZhi->getJulianDay()->getSolarDay()) && $solar->isBefore($xiaZhi->getJulianDay()->getSolarDay())) {
172+
if (!$solar->isBefore($dongZhi->getJulianDay()->getSolarDay()) && $solar->isBefore($dongZhi->next(12)->getJulianDay()->getSolarDay())) {
174173
$index = 8 + $earthBranchIndex - $index;
175174
} else {
176175
$index -= $earthBranchIndex;

src/solar/SolarDay.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
use com\tyme\culture\dog\DogDay;
1010
use com\tyme\culture\nine\Nine;
1111
use com\tyme\culture\nine\NineDay;
12+
use com\tyme\culture\Phase;
13+
use com\tyme\culture\PhaseDay;
1214
use com\tyme\culture\phenology\Phenology;
1315
use com\tyme\culture\phenology\PhenologyDay;
1416
use com\tyme\culture\plumrain\PlumRain;
@@ -461,4 +463,31 @@ function getRabByungDay(): RabByungDay
461463
return RabByungDay::fromSolarDay($this);
462464
}
463465

466+
/**
467+
* 月相第几天
468+
*
469+
* @return PhaseDay 月相第几天
470+
*/
471+
function getPhaseDay(): PhaseDay
472+
{
473+
$month = $this->getLunarDay()->getLunarMonth()->next(1);
474+
$p = Phase::fromIndex($month->getYear(), $month->getMonth(), 0);
475+
$d = $p->getSolarDay();
476+
while ($d->isAfter($this)) {
477+
$p = $p->next(-1);
478+
$d = $p->getSolarDay();
479+
}
480+
return new PhaseDay($p, $this->subtract($d));
481+
}
482+
483+
/**
484+
* 月相
485+
*
486+
* @return Phase 月相
487+
*/
488+
function getPhase(): Phase
489+
{
490+
return $this->getPhaseDay()->getPhase();
491+
}
492+
464493
}

src/solar/SolarTime.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55

66
use com\tyme\AbstractTyme;
7+
use com\tyme\culture\Phase;
78
use com\tyme\culture\phenology\Phenology;
89
use com\tyme\jd\JulianDay;
910
use com\tyme\lunar\LunarHour;
@@ -286,4 +287,19 @@ function getSixtyCycleHour(): SixtyCycleHour
286287
{
287288
return SixtyCycleHour::fromSolarTime($this);
288289
}
290+
291+
/**
292+
* 月相
293+
*
294+
* @return Phase 月相
295+
*/
296+
function getPhase(): Phase
297+
{
298+
$month = $this->getLunarHour()->getLunarDay()->getLunarMonth()->next(1);
299+
$p = Phase::fromIndex($month->getYear(), $month->getMonth(), 0);
300+
while ($p->getSolarTime()->isAfter($this)) {
301+
$p = $p->next(-1);
302+
}
303+
return $p;
304+
}
289305
}

src/util/ShouXingUtil.php

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,18 @@ class ShouXingUtil
5959
2000, 63.87, 0.1, 0, 0,
6060
2005, 64.7, 0.21, 0, 0,
6161
2012, 66.8, 0.22, 0, 0,
62-
2018, 73.6, 0.40, 0, 0,
63-
2021, 78.1, 0.44, 0, 0,
64-
2024, 83.1, 0.55, 0, 0,
65-
2028, 98.6
62+
// 2018, 69.0, 0.36, 0, 0,
63+
// 使用skyfeild的DE440s△T预测数据拟合
64+
2016, 68.1024, 0.5456, -0.0542, -0.001172,
65+
2020, 69.3612, 0.0422, -0.0502, 0.006216,
66+
2024, 69.1752, -0.0335, -0.0048, 0.000811,
67+
2028, 69.0206, -0.0275, 0.0055, -0.000014,
68+
2032, 68.9981, 0.0163, 0.0054, 0.000006,
69+
2036, 69.1498, 0.0599, 0.0053, 0.000026,
70+
2040, 69.4751, 0.1035, 0.0051, 0.000046,
71+
2044, 69.9737, 0.1469, 0.0050, 0.000066,
72+
2048, 70.6451, 0.1903, 0.0049, 0.000085,
73+
2050, 71.0457
6674
);
6775
private static array $XL0 = array(
6876
10000000000,

0 commit comments

Comments
 (0)