Files
michaelschiemer/src/Framework/Core/ValueObjects/Timezone.php
Michael Schiemer 55a330b223 Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug
- Add DISCOVERY_SHOW_PROGRESS=true
- Temporary changes for debugging InitializerProcessor fixes on production
2025-08-11 20:13:26 +02:00

233 lines
5.4 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Framework\Core\ValueObjects;
use DateTimeZone;
use InvalidArgumentException;
/**
* Timezone value object
*/
final readonly class Timezone
{
public function __construct(
public string $value
) {
$this->validate();
}
/**
* Create from timezone string
*/
public static function fromString(string $timezone): self
{
return new self($timezone);
}
/**
* Create UTC timezone
*/
public static function utc(): self
{
return new self('UTC');
}
/**
* Create timezone for Europe/Berlin
*/
public static function berlin(): self
{
return new self('Europe/Berlin');
}
/**
* Create timezone for America/New_York
*/
public static function newYork(): self
{
return new self('America/New_York');
}
/**
* Create timezone for Asia/Tokyo
*/
public static function tokyo(): self
{
return new self('Asia/Tokyo');
}
/**
* Get DateTimeZone object
*/
public function toDateTimeZone(): DateTimeZone
{
return new DateTimeZone($this->value);
}
/**
* Get timezone offset in seconds from UTC
*/
public function getOffsetFromUtc(): int
{
$timezone = $this->toDateTimeZone();
$now = new \DateTime('now', $timezone);
return $timezone->getOffset($now);
}
/**
* Get timezone offset as string (+/-HH:MM)
*/
public function getOffsetString(): string
{
$offset = $this->getOffsetFromUtc();
$hours = intval($offset / 3600);
$minutes = abs(intval(($offset % 3600) / 60));
return sprintf('%+03d:%02d', $hours, $minutes);
}
/**
* Check if timezone is UTC
*/
public function isUtc(): bool
{
return $this->value === 'UTC';
}
/**
* Check if timezone uses daylight saving time
*/
public function usesDaylightSaving(): bool
{
$timezone = $this->toDateTimeZone();
$transitions = $timezone->getTransitions();
// If there are transitions, it likely uses DST
return count($transitions) > 1;
}
/**
* Get timezone name
*/
public function getName(): string
{
return $this->value;
}
/**
* Get timezone abbreviation
*/
public function getAbbreviation(): string
{
$timezone = $this->toDateTimeZone();
$now = new \DateTime('now', $timezone);
return $now->format('T');
}
/**
* Get continent
*/
public function getContinent(): ?string
{
$parts = explode('/', $this->value);
return $parts[0] ?? null;
}
/**
* Get city/region
*/
public function getCity(): ?string
{
$parts = explode('/', $this->value);
return $parts[1] ?? null;
}
/**
* Check if this is a valid timezone for geographic region
*/
public function isValidForCountry(CountryCode $countryCode): bool
{
$countryTimezones = [
'DE' => ['Europe/Berlin'],
'US' => [
'America/New_York', 'America/Chicago', 'America/Denver',
'America/Los_Angeles', 'America/Anchorage', 'Pacific/Honolulu',
],
'GB' => ['Europe/London'],
'FR' => ['Europe/Paris'],
'JP' => ['Asia/Tokyo'],
'CN' => ['Asia/Shanghai'],
'IN' => ['Asia/Kolkata'],
'RU' => [
'Europe/Moscow', 'Asia/Yekaterinburg', 'Asia/Novosibirsk',
'Asia/Krasnoyarsk', 'Asia/Irkutsk', 'Asia/Yakutsk',
'Asia/Vladivostok', 'Asia/Magadan', 'Asia/Kamchatka',
],
'AU' => [
'Australia/Sydney', 'Australia/Melbourne', 'Australia/Brisbane',
'Australia/Perth', 'Australia/Adelaide', 'Australia/Darwin',
],
'BR' => [
'America/Sao_Paulo', 'America/Manaus', 'America/Fortaleza',
'America/Recife', 'America/Bahia',
],
'CA' => [
'America/Toronto', 'America/Vancouver', 'America/Montreal',
'America/Calgary', 'America/Edmonton', 'America/Winnipeg',
],
];
$validTimezones = $countryTimezones[$countryCode->value] ?? [];
return in_array($this->value, $validTimezones, true);
}
/**
* Convert to array
*/
public function toArray(): array
{
return [
'timezone' => $this->value,
'offset' => $this->getOffsetString(),
'offset_seconds' => $this->getOffsetFromUtc(),
'abbreviation' => $this->getAbbreviation(),
'continent' => $this->getContinent(),
'city' => $this->getCity(),
'is_utc' => $this->isUtc(),
'uses_daylight_saving' => $this->usesDaylightSaving(),
];
}
/**
* String representation
*/
public function toString(): string
{
return $this->value;
}
/**
* Validate timezone
*/
private function validate(): void
{
try {
new DateTimeZone($this->value);
} catch (\Exception $e) {
throw new InvalidArgumentException("Invalid timezone: {$this->value}");
}
}
public function __toString(): string
{
return $this->value;
}
}