- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
233 lines
5.4 KiB
PHP
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;
|
|
}
|
|
}
|