Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BCrwHHnGCB5XH968Nxokqw
61 lines
1.7 KiB
PHP
61 lines
1.7 KiB
PHP
<?php
|
|
|
|
namespace App\Ingest;
|
|
|
|
use App\Enums\DueMode;
|
|
use App\Models\Event;
|
|
use Carbon\CarbonImmutable;
|
|
|
|
/** Разобранный due_at: tagged union по mode. */
|
|
final class ParsedDue
|
|
{
|
|
private function __construct(
|
|
public readonly DueMode $mode,
|
|
public readonly ?string $date,
|
|
public readonly ?string $time,
|
|
public readonly ?CarbonImmutable $instant,
|
|
) {}
|
|
|
|
public static function local(string $date, string $time): self
|
|
{
|
|
return new self(DueMode::Local, $date, $time, null);
|
|
}
|
|
|
|
public static function fixed(CarbonImmutable $instant): self
|
|
{
|
|
return new self(DueMode::Fixed, null, null, $instant->utc());
|
|
}
|
|
|
|
/** Календарный день срока в данном поясе, Y-m-d. */
|
|
public function dayFor(string $tz): string
|
|
{
|
|
return match ($this->mode) {
|
|
DueMode::Local => $this->date,
|
|
DueMode::Fixed => $this->instant->setTimezone($tz)->format('Y-m-d'),
|
|
};
|
|
}
|
|
|
|
public function equals(Event $event): bool
|
|
{
|
|
if ($event->due_mode !== $this->mode) {
|
|
return false;
|
|
}
|
|
|
|
return match ($this->mode) {
|
|
DueMode::Local => $event->due_date->format('Y-m-d') === $this->date && $event->due_time === $this->time,
|
|
DueMode::Fixed => $event->due_instant->eq($this->instant),
|
|
};
|
|
}
|
|
|
|
/** @return array<string, mixed> колонки events */
|
|
public function columns(): array
|
|
{
|
|
return [
|
|
'due_mode' => $this->mode,
|
|
'due_date' => $this->date,
|
|
'due_time' => $this->time,
|
|
'due_instant' => $this->instant,
|
|
];
|
|
}
|
|
}
|