|
3 | 3 | namespace com\tyme\culture; |
4 | 4 |
|
5 | 5 |
|
| 6 | +use com\tyme\jd\JulianDay; |
6 | 7 | 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; |
7 | 13 |
|
8 | 14 | /** |
9 | 15 | * 月相 |
|
12 | 18 | */ |
13 | 19 | class Phase extends LoopTyme |
14 | 20 | { |
15 | | - static array $NAMES = ['朔月', '既朔月', '蛾眉新月', '蛾眉新月', '蛾眉月', '夕月', '上弦月', '上弦月', '九夜月', '宵月', '宵月', '宵月', '渐盈凸月', '小望月', '望月', '既望月', '立待月', '居待月', '寝待月', '更待月', '渐亏凸月', '下弦月', '下弦月', '有明月', '有明月', '蛾眉残月', '蛾眉残月', '残月', '晓月', '晦月']; |
| 21 | + static array $NAMES = ['新月', '蛾眉月', '上弦月', '盈凸月', '满月', '亏凸月', '下弦月', '残月']; |
16 | 22 |
|
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) |
18 | 34 | { |
19 | 35 | if ($index !== null) { |
20 | 36 | 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(); |
21 | 40 | } else if ($name !== null) { |
22 | 41 | parent::__construct(static::$NAMES, null, $name); |
| 42 | + $this->lunarYear = $lunarYear; |
| 43 | + $this->lunarMonth = $lunarMonth; |
23 | 44 | } |
24 | 45 | } |
25 | 46 |
|
26 | | - static function fromIndex(int $index): static |
| 47 | + static function fromIndex(int $lunarYear, int $lunarMonth, int $index): static |
27 | 48 | { |
28 | | - return new static($index); |
| 49 | + return new static($lunarYear, $lunarMonth, $index); |
29 | 50 | } |
30 | 51 |
|
31 | | - static function fromName(string $name): static |
| 52 | + static function fromName(int $lunarYear, int $lunarMonth, string $name): static |
32 | 53 | { |
33 | | - return new static(null, $name); |
| 54 | + return new static($lunarYear, $lunarMonth, null, $name); |
34 | 55 | } |
35 | 56 |
|
36 | 57 | function next(int $n): static |
37 | 58 | { |
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; |
39 | 101 | } |
40 | 102 | } |
0 commit comments