Skip to content

Commit

Permalink
v1.1.1 新增时辰获取黄道黑道十二神;新增五行和方位互转;新增天干五合、地支六合、地支六害;修复获取当年第几周报错的问题;优化性能。
Browse files Browse the repository at this point in the history
  • Loading branch information
6tail committed Jul 30, 2024
1 parent 9ec3d6d commit c8d49c4
Show file tree
Hide file tree
Showing 17 changed files with 262 additions and 166 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,10 @@
3. 新增:每日宜忌、时辰宜忌。
4. 新增:支持方法扩展。
5. 修复:农历日获取时辰列表遇闰月报错的问题。

## [1.1.1] - 2024-07-30
1. 新增:时辰获取黄道黑道十二神。
2. 新增:五行和方位互转。
3. 新增:天干五合、地支六合、地支六害。
4. 修复:获取当年第几周报错的问题。
5. 优化:性能。
10 changes: 10 additions & 0 deletions src/culture/Direction.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,14 @@ function getLand(): Land
{
return Land::fromIndex($this->index);
}

/**
* 五行
*
* @return Element 五行
*/
function getElement(): Element
{
return Element::fromIndex([4, 2, 0, 0, 2, 3, 3, 2, 1][$this->index]);
}
}
9 changes: 9 additions & 0 deletions src/culture/Element.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,13 @@ function getRestrained(): static
{
return $this->next(-2);
}

/**
* 方位
* @return Direction 方位
*/
function getDirection(): Direction
{
return Direction::fromIndex([2, 8, 4, 6, 0][$this->index]);
}
}
33 changes: 20 additions & 13 deletions src/holiday/LegalHoliday.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,21 +72,28 @@ function next(int $n): ?static
}
$index += $n;
$y = $year;
$forward = $n > 0;
$add = $forward ? 1 : -1;
while ($forward ? ($index >= $size) : ($index < 0)) {
if ($forward) {
if ($n > 0) {
while ($index >= $size) {
$index -= $size;
$y += 1;
$size = 0;
if(preg_match_all(sprintf($reg, $y), static::$DATA, $matches)) {
$size = count($matches[0]);
}
if ($size < 1) {
return null;
}
}
$y += $add;
$size = 0;
if(preg_match_all(sprintf($reg, $y), static::$DATA, $matches)) {
$size = count($matches[0]);
}
if ($size < 1) {
return null;
}
if (!$forward) {
} else {
while ($index < 0) {
$y -= 1;
$size = 0;
if(preg_match_all(sprintf($reg, $y), static::$DATA, $matches)) {
$size = count($matches[0]);
}
if ($size < 1) {
return null;
}
$index += $size;
}
}
Expand Down
35 changes: 3 additions & 32 deletions src/lunar/LunarDay.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use com\tyme\AbstractTyme;
use com\tyme\culture\Direction;
use com\tyme\culture\Duty;
use com\tyme\culture\Element;
use com\tyme\culture\fetus\FetusDay;
use com\tyme\culture\God;
use com\tyme\culture\Phase;
Expand Down Expand Up @@ -109,25 +110,7 @@ function __toString(): string

function next(int $n): LunarDay
{
if ($n == 0) {
return self::fromYmd($this->getYear(), $this->getMonth(), $this->day);
}
$d = $this->day + $n;
$m = $this->month;
$dayCount = $m->getDayCount();
$forward = $n > 0;
$add = $forward ? 1 : -1;
while ($forward ? ($d > $dayCount) : ($d <= 0)) {
if ($forward) {
$d -= $dayCount;
}
$m = $m->next($add);
$dayCount = $m->getDayCount();
if (!$forward) {
$d += $dayCount;
}
}
return self::fromYmd($m->getYear(), $m->getMonthWithLeap(), $d);
return $n == 0 ? self::fromYmd($this->getYear(), $this->getMonth(), $this->day) : $this->getSolarDay()->next($n)->getLunarDay();
}

/**
Expand Down Expand Up @@ -296,10 +279,7 @@ function getNineStar(): NineStar
function getJupiterDirection(): Direction
{
$index = $this->getSixtyCycle()->getIndex();
if ($index % 12 < 6) {
return Direction::fromIndex([2, 8, 4, 6, 0][intdiv($index, 12)]);
}
return $this->month->getLunarYear()->getJupiterDirection();
return $index % 12 < 6 ? Element::fromIndex(intdiv($index, 12))->getDirection() : $this->month->getLunarYear()->getJupiterDirection();
}

/**
Expand Down Expand Up @@ -403,13 +383,4 @@ function getSixStar(): SixStar
{
return SixStar::fromIndex(($this->month->getMonth() + $this->day - 2) % 6);
}

function equals(mixed $o): bool
{
if (!($o instanceof LunarDay)) {
return false;
}
return $this->month->equals($o->getMonth()) && $this->day == $o->getDay();
}

}
19 changes: 11 additions & 8 deletions src/lunar/LunarHour.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

use com\tyme\AbstractTyme;
use com\tyme\culture\star\nine\NineStar;
use com\tyme\culture\star\twelve\TwelveStar;
use com\tyme\culture\Taboo;
use com\tyme\eightchar\EightChar;
use com\tyme\sixtycycle\EarthBranch;
Expand Down Expand Up @@ -262,6 +263,16 @@ function getSixtyCycle(): SixtyCycle
return SixtyCycle::fromName(sprintf('%s%s', HeavenStem::fromIndex($heavenStemIndex)->getName(), EarthBranch::fromIndex($earthBranchIndex)->getName()));
}

/**
* 黄道黑道十二神
*
* @return TwelveStar 黄道黑道十二神
*/
function getTwelveStar(): TwelveStar
{
return TwelveStar::fromIndex($this->getSixtyCycle()->getEarthBranch()->getIndex() + (8 - $this->getDaySixtyCycle()->getEarthBranch()->getIndex() % 6) * 2);
}

/**
* 九星(时家紫白星歌诀:三元时白最为佳,冬至阳生顺莫差,孟日七宫仲一白,季日四绿发萌芽,每把时辰起甲子,本时星耀照光华,时星移入中宫去,顺飞八方逐细查。夏至阴生逆回首,孟归三碧季加六,仲在九宫时起甲,依然掌中逆轮跨。)
*
Expand Down Expand Up @@ -319,12 +330,4 @@ function getAvoids(): array
{
return Taboo::getHourAvoids($this->getDaySixtyCycle(), $this->getSixtyCycle());
}

function equals(mixed $o): bool
{
if (!($o instanceof LunarHour)) {
return false;
}
return $this->day->equals($o->getDay()) && $this->hour == $o->getHour() && $this->minute == $o->getMinute() && $this->second == $o->getSecond();
}
}
148 changes: 86 additions & 62 deletions src/lunar/LunarMonth.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
*/
class LunarMonth extends AbstractTyme
{
/**
* @var array 缓存
*/
private static array $cache = array();

static array $NAMES = ['正月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'];


Expand Down Expand Up @@ -55,58 +60,85 @@ class LunarMonth extends AbstractTyme
*/
protected JulianDay $firstJulianDay;

protected function __construct(int $year, int $month)
protected function __construct(int $year, int $month, array $cache = null)
{
$currentYear = LunarYear::fromYear($year);
$currentLeapMonth = $currentYear->getLeapMonth();
if ($month == 0 || $month > 12 || $month < -12) {
throw new InvalidArgumentException(sprintf('illegal lunar month: %d', $month));
}
$leap = $month < 0;
$m = abs($month);
if ($leap && $m != $currentLeapMonth) {
throw new InvalidArgumentException(sprintf('illegal leap month %d in lunar year %d', $m, $year));
}
if ($cache !== null) {
$m = (int)$cache[1];
$this->year = LunarYear::fromYear((int)$cache[0]);
$this->month = abs($m);
$this->leap = $m < 0;
$this->dayCount = (int)$cache[2];
$this->indexInYear = (int)$cache[3];
$this->firstJulianDay = JulianDay::fromJulianDay((double)$cache[4]);
} else {
$currentYear = LunarYear::fromYear($year);
$currentLeapMonth = $currentYear->getLeapMonth();
if ($month == 0 || $month > 12 || $month < -12) {
throw new InvalidArgumentException(sprintf('illegal lunar month: %d', $month));
}
$leap = $month < 0;
$m = abs($month);
if ($leap && $m != $currentLeapMonth) {
throw new InvalidArgumentException(sprintf('illegal leap month %d in lunar year %d', $m, $year));
}

// 冬至
$dongZhi = SolarTerm::fromIndex($year, 0);
$dongZhiJd = $dongZhi->getCursoryJulianDay();
// 冬至
$dongZhi = SolarTerm::fromIndex($year, 0);
$dongZhiJd = $dongZhi->getCursoryJulianDay();

// 冬至前的初一,今年首朔的日月黄经差
$w = ShouXingUtil::calcShuo($dongZhiJd);
if ($w > $dongZhiJd) {
$w -= 29.53;
}
// 冬至前的初一,今年首朔的日月黄经差
$w = ShouXingUtil::calcShuo($dongZhiJd);
if ($w > $dongZhiJd) {
$w -= 29.53;
}

// 正常情况正月初一为第3个朔日,但有些特殊的
$offset = 2;
if ($year > 8 && $year < 24) {
$offset = 1;
} else if (LunarYear::fromYear($year - 1)->getLeapMonth() > 10 && $year != 239 && $year != 240) {
$offset = 3;
}
// 正常情况正月初一为第3个朔日,但有些特殊的
$offset = 2;
if ($year > 8 && $year < 24) {
$offset = 1;
} else if (LunarYear::fromYear($year - 1)->getLeapMonth() > 10 && $year != 239 && $year != 240) {
$offset = 3;
}

// 位于当年的索引
$index = $m - 1;
if ($leap || ($currentLeapMonth > 0 && $m > $currentLeapMonth)) {
$index += 1;
// 位于当年的索引
$index = $m - 1;
if ($leap || ($currentLeapMonth > 0 && $m > $currentLeapMonth)) {
$index += 1;
}
$this->indexInYear = $index;

// 本月初一
$w += 29.5306 * ($offset + $index);
$firstDay = ShouXingUtil::calcShuo($w);
$this->firstJulianDay = JulianDay::fromJulianDay(JulianDay::J2000 + $firstDay);
// 本月天数 = 下月初一 - 本月初一
$this->dayCount = (int)(ShouXingUtil::calcShuo($w + 29.5306) - $firstDay);
$this->year = $currentYear;
$this->month = $m;
$this->leap = $leap;
}
$this->indexInYear = $index;

// 本月初一
$w += 29.5306 * ($offset + $index);
$firstDay = ShouXingUtil::calcShuo($w);
$this->firstJulianDay = JulianDay::fromJulianDay(JulianDay::J2000 + $firstDay);
// 本月天数 = 下月初一 - 本月初一
$this->dayCount = (int)(ShouXingUtil::calcShuo($w + 29.5306) - $firstDay);
$this->year = $currentYear;
$this->month = $m;
$this->leap = $leap;
}

static function fromYm(int $year, int $month): static
{
return new static($year, $month);
$c = null;
$key = sprintf("%d%d", $year, $month);
if (!empty(static::$cache[$key])) {
$c = static::$cache[$key];
}
if (null != $c) {
$m = new static(0, 0, $c);
} else {
$m = new static($year, $month);
static::$cache[$key] = [
$m->getYear(),
$m->getMonthWithLeap(),
$m->getDayCount(),
$m->getIndexInYear(),
$m->getFirstJulianDay()->getDay()
];
}
return $m;
}

/**
Expand Down Expand Up @@ -233,18 +265,19 @@ function next(int $n): LunarMonth
$m = $this->indexInYear + 1 + $n;
$y = $this->year;
$leapMonth = $y->getLeapMonth();
$monthSize = 12 + ($leapMonth > 0 ? 1 : 0);
$forward = $n > 0;
$add = $forward ? 1 : -1;
while ($forward ? ($m > $monthSize) : ($m <= 0)) {
if ($forward) {
$m -= $monthSize;
if ($n > 0) {
$monthCount = $leapMonth > 0 ? 13 : 12;
while ($m > $monthCount) {
$m -= $monthCount;
$y = $y->next(1);
$leapMonth = $y->getLeapMonth();
$monthCount = $leapMonth > 0 ? 13 : 12;
}
$y = $y->next($add);
$leapMonth = $y->getLeapMonth();
$monthSize = 12 + ($leapMonth > 0 ? 1 : 0);
if (!$forward) {
$m += $monthSize;
} else {
while ($m <= 0) {
$y = $y->next(-1);
$leapMonth = $y->getLeapMonth();
$m += $leapMonth > 0 ? 13 : 12;
}
}
$leap = false;
Expand Down Expand Up @@ -335,13 +368,4 @@ function getFetus(): FetusMonth
{
return FetusMonth::fromLunarMonth($this);
}

function equals(mixed $o): bool
{
if (!($o instanceof LunarMonth)) {
return false;
}
return $this->getYear() == $o->getYear() && $this->getMonthWithLeap() == $o->getMonthWithLeap();
}

}
Loading

0 comments on commit c8d49c4

Please sign in to comment.