format('Y-m-d')); $totalSec = $date->getTimestamp() - $baseDay->getTimestamp(); $min30 = intdiv($totalSec, 60 * 30); assert($min30 < 48); [$turnIdx, $minOffset, ] = static::$min30ToTurn[$min30]; $secOffset = $totalSec - 60 * 30 * $min30 + $minOffset * 60; return new static($baseDay, $turnIdx, $secOffset); } /// $b - $a 의 턴차 static function calcTurnDiff(\DateTimeInterface $a, \DateTimeInterface $b): int{ $aObj = static::fromDatetime($a); $bObj = static::fromDatetime($b); $resDays = $aObj->baseDay->diff($bObj->baseDay)->days; //놀랍게도 절대값 if($aObj->baseDay > $bObj->baseDay){ $resDays *= -1; } $res = $resDays * 24 + $bObj->turnIdx - $aObj->turnIdx; return $res; } function cutTurn($withFraction = true): array{ [$hour, $minOffset, $turnTerm] = static::$turnToHM[$this->turnIdx]; $date = $this->baseDay->add(TimeUtil::secondsToDateInterval(($hour * 60 + $minOffset) * 60)); return [TimeUtil::format($date, $withFraction), $turnTerm]; } function toDateStr($withFraction = true): string{ [$hour, $minOffset, ] = static::$turnToHM[$this->turnIdx]; $date = $this->baseDay->add(TimeUtil::secondsToDateInterval(($hour * 60 + $minOffset) * 60 + $this->secOffset)); return TimeUtil::format($date, $withFraction); } function cutDay($withFraction = true): array{ //고정 시간 기준 cutDay()의 이식 //상수 테이블이 이미 13:00에 1월이 되도록 맞춰져 있음. //다만 20:00인 경우 8월이 아니라 9월이 됨 ^^; $newMonth = ($this->turnIdx + static::MonthAdjustOffset) % 12 + 1; $yearPulled = $newMonth > 3; $obj = $yearPulled ? $this->addTurn(12): $this; [$date, ] = $obj->addTurn(-($newMonth - 1))->cutTurn($withFraction); return [$date, $yearPulled, $newMonth]; } function addTurn(int $moreTurn): self{ $dayDiff = intdiv($moreTurn, 24); $moreTurn %= 24; $nextTurnIdx = $this->turnIdx + $moreTurn; if($nextTurnIdx < 0){ $dayDiff -= 1; $nextTurnIdx += 24; } else if($nextTurnIdx >= 24){ $dayDiff += 1; $nextTurnIdx -= 24; } [, , $oldTurnTerm] = static::$turnToHM[$this->turnIdx]; [, , $nextTurnTerm] = static::$turnToHM[$nextTurnIdx]; $nextSecOffset = $this->secOffset; if($oldTurnTerm != $nextTurnTerm){ $nextSecOffset *= $nextTurnTerm; $nextSecOffset /= $oldTurnTerm; } if($dayDiff == 0){ return new static($this->baseDay, $nextTurnIdx, $nextSecOffset); } if($dayDiff > 0){ $nextBaseDay = $this->baseDay->add(new \DateInterval("P{$dayDiff}D")); } else{ $dayAbsDiff = abs($dayDiff); $nextBaseDay = $this->baseDay->sub(new \DateInterval("P{$dayAbsDiff}D")); } return new static($nextBaseDay, $nextTurnIdx, $nextSecOffset); } }