Files
core/hwe/sammo/VarTurn60.php
T
2025-10-29 15:40:20 +00:00

189 lines
5.7 KiB
PHP

<?php
namespace sammo;
class VarTurn60
{
const MonthAdjustOffset = 2;
static array $min30ToTurn = [
[0, 0, 120], //00:00 2
[0, 30, 120], //00:30
[0, 60, 120], //01:00
[0, 90, 120], //01:30
[1, 0, 120], //02:00 3
[1, 30, 120], //02:30
[1, 60, 120], //03:00
[1, 90, 120], //03:30
[2, 0, 120], //04:00 4
[2, 30, 120], //04:30
[2, 60, 120], //05:00
[2, 90, 120], //05:30
[3, 0, 60], //06:00 5
[3, 30, 60], //06:30
[4, 0, 60], //07:00 6
[4, 30, 60], //07:30
[5, 0, 60], //08:00 7
[5, 30, 60], //08:30
[6, 0, 60], //09:00 8
[6, 30, 60], //09:30
[7, 0, 60], //10:00 9
[7, 30, 60], //10:30
[8, 0, 60], //11:00 10
[8, 30, 60], //11:30
[9, 0, 60], //12:00 11
[9, 30, 60], //12:30
[10, 0, 60], //13:00 0(12)
[10, 30, 60], //13:30
[11, 0, 60], //14:00 1(13)
[11, 30, 60], //14:30
[12, 0, 60], //15:00 2(14)
[12, 30, 60], //15:30
[13, 0, 60], //16:00 3(15)
[13, 30, 60], //16:30
[14, 0, 60], //17:00 4(16)
[14, 30, 60], //17:30
[15, 0, 60], //18:00 5(17)
[15, 30, 60], //18:30
[16, 0, 30], //19:00 6(18)
[17, 0, 30], //19:30 7(19)
[18, 0, 30], //20:00 8(20)
[19, 0, 30], //20:30 9(21)
[20, 0, 30], //21:00 10(22)
[21, 0, 30], //21:30 11(23)
[22, 0, 60], //22:00 0
[22, 30, 60], //22:30
[23, 0, 60], //23:00 1
[23, 30, 60], //23:30
//[24, 0, 60], //24:00 2
];
static array $turnToHM = [
[0, 0, 120], //0
[2, 0, 120], //1
[4, 0, 120], //2
[6, 0, 60], //3
[7, 0, 60], //4
[8, 0, 60], //5
[9, 0, 60], //6
[10, 0, 60], //7
[11, 0, 60], //8
[12, 0, 60], //9
[13, 0, 60], //10
[14, 0, 60], //11
[15, 0, 60], //12
[16, 0, 60], //13
[17, 0, 60], //14
[18, 0, 60], //15
[19, 0, 30], //16
[19, 30, 30],//17
[20, 0, 30], //18
[20, 30, 30],//19
[21, 0, 30], //20
[21, 30, 30],//21
[22, 0, 60], //22
[23, 0, 60], //23
//[24, 0, 60], //24(?)
];
function __construct(
public \DateTimeImmutable $baseDay,
public int $turnIdx, //0~23
public float $secOffset, ///turnTerm에 따라 최대치가 30*60, 60*60, 120*60 가변
)
{
}
static function fromDatetime(\DateTimeInterface $date): self {
$baseDay = new \DateTimeImmutable($date->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;
[$date, ] = $this->cutTurn($withFraction);
$yearPulled = $newMonth > 3;
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);
}
}