attendance['timezone'])) { return (string) $schoolConfig->attendance['timezone']; } if (is_array($schoolConfig) && isset($schoolConfig['attendance']['timezone'])) { return (string) $schoolConfig['attendance']['timezone']; } return (string) (config('app.timezone') ?: 'UTC'); } public function serverTimezone(): string { return (string) (config('app.timezone') ?: 'UTC'); } public function nowUtc(): CarbonImmutable { return CarbonImmutable::now('UTC'); } public function nowLocal(?string $tz = null): CarbonImmutable { return CarbonImmutable::now($tz ?: $this->userTimezone()); } public function toUtc($value, ?string $fromTz = null, string $format = 'Y-m-d H:i:s'): ?string { $dt = $this->parse($value, $fromTz); if (!$dt) { return null; } return $dt->setTimezone('UTC')->format($format); } public function toLocal($value, ?string $sourceTz = null, ?string $targetTz = null, string $format = 'Y-m-d H:i:s'): ?string { $dt = $this->parse($value, $sourceTz); if (!$dt) { return null; } return $dt->setTimezone($targetTz ?: $this->userTimezone())->format($format); } public function formatLocal($value, string $format = 'Y-m-d', ?string $sourceTz = null): string { $dt = $this->parse($value, $sourceTz); if (!$dt) { return ''; } return $dt->setTimezone($this->userTimezone())->format($format); } private function parse($value, ?string $tz = null): ?CarbonImmutable { if ($value instanceof DateTimeInterface) { return CarbonImmutable::instance($value); } $raw = trim((string) $value); if ($raw === '') { return null; } try { return CarbonImmutable::parse($raw, $tz ?: $this->serverTimezone()); } catch (\Throwable $e) { return null; } } }