chore: complete update
This commit is contained in:
59
src/Framework/DateTime/Clock.php
Normal file
59
src/Framework/DateTime/Clock.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace App\Framework\DateTime;
|
||||
|
||||
use App\Framework\DateTime\Exceptions\InvalidDateTimeException;
|
||||
use App\Framework\DateTime\Exceptions\InvalidTimezoneException;
|
||||
use DateTimeImmutable;
|
||||
use Exception;
|
||||
|
||||
interface Clock
|
||||
{
|
||||
/**
|
||||
* Gibt die aktuelle Zeit zurück.
|
||||
*
|
||||
* @return DateTimeImmutable
|
||||
*/
|
||||
public function now(): DateTimeImmutable;
|
||||
|
||||
/**
|
||||
* Erzeugt ein DateTimeImmutable-Objekt aus einem Zeitstempel.
|
||||
*
|
||||
* @param int $timestamp UNIX-Zeitstempel
|
||||
* @return DateTimeImmutable
|
||||
*/
|
||||
public function fromTimestamp(int $timestamp): DateTimeImmutable;
|
||||
|
||||
/**
|
||||
* Erzeugt ein DateTimeImmutable-Objekt aus einem String im angegebenen Format.
|
||||
*
|
||||
* @param string $dateTime Der zu parsende Zeitstring
|
||||
* @param string|null $format Optionales Format für die Analyse
|
||||
* @return DateTimeImmutable
|
||||
* @throws InvalidDateTimeException wenn das Parsen fehlschlägt
|
||||
* @throws InvalidTimezoneException wenn eine angegebene Zeitzone ungültig ist
|
||||
*/
|
||||
public function fromString(string $dateTime, ?string $format = null): DateTimeImmutable;
|
||||
|
||||
public function today(): DateTimeImmutable;
|
||||
|
||||
public function yesterday(): DateTimeImmutable;
|
||||
|
||||
public function tomorrow(): DateTimeImmutable;
|
||||
|
||||
|
||||
/**
|
||||
* Gibt den aktuellen UNIX-Zeitstempel zurück.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function time(): int;
|
||||
|
||||
/**
|
||||
* Gibt den aktuellen Zeitstempel mit Mikrosekunden zurück.
|
||||
*
|
||||
* @param bool $asFloat Wenn true, wird ein float zurückgegeben, sonst ein Array
|
||||
* @return float|array{float, int}
|
||||
*/
|
||||
public function microtime(bool $asFloat = false): float|array;
|
||||
}
|
||||
32
src/Framework/DateTime/ClockInitializer.php
Normal file
32
src/Framework/DateTime/ClockInitializer.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\DateTime;
|
||||
|
||||
use App\Framework\Config\AppConfig;
|
||||
use App\Framework\DI\Initializer;
|
||||
use DateTimeZone;
|
||||
|
||||
final readonly class ClockInitializer
|
||||
{
|
||||
public function __construct(
|
||||
private AppConfig $config
|
||||
) {}
|
||||
|
||||
#[Initializer]
|
||||
public function __invoke(): Clock
|
||||
{
|
||||
$timezone = $this->config->timezone;
|
||||
|
||||
$timezone = new DateTimeZone($timezone->value);
|
||||
|
||||
return new SystemClock($timezone);
|
||||
}
|
||||
|
||||
#[Initializer]
|
||||
public function initTimer(): Timer
|
||||
{
|
||||
return new SystemTimer();
|
||||
}
|
||||
}
|
||||
129
src/Framework/DateTime/DateRange.php
Normal file
129
src/Framework/DateTime/DateRange.php
Normal file
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace App\Framework\DateTime;
|
||||
|
||||
use App\Framework\DateTime\Exceptions\InvalidDateTimeException;
|
||||
use App\Framework\DateTime\Exceptions\InvalidTimezoneException;
|
||||
use DateInterval;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeInterface;
|
||||
use DateTimeZone;
|
||||
use InvalidArgumentException;
|
||||
|
||||
final readonly class DateRange
|
||||
{
|
||||
/**
|
||||
* @param DateTimeImmutable $start Startdatum des Bereichs
|
||||
* @param DateTimeImmutable $end Enddatum des Bereichs
|
||||
* @throws InvalidArgumentException wenn das Enddatum vor dem Startdatum liegt
|
||||
*/
|
||||
public function __construct(
|
||||
private DateTimeImmutable $start,
|
||||
private DateTimeImmutable $end
|
||||
) {
|
||||
if ($end < $start) {
|
||||
throw new InvalidArgumentException(
|
||||
'Enddatum kann nicht vor dem Startdatum liegen.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Erzeugt einen DateRange aus zwei Datumsstrings.
|
||||
*
|
||||
* @param string $start Startdatum als String
|
||||
* @param string $end Enddatum als String
|
||||
* @param DateTimeZone|string|null $timezone Optionale Zeitzone (Standard: UTC)
|
||||
* @return self
|
||||
* @throws InvalidTimezoneException
|
||||
* @throws InvalidDateTimeException
|
||||
*/
|
||||
public static function fromStrings(
|
||||
string $start,
|
||||
string $end,
|
||||
DateTimeZone|string|null $timezone = null
|
||||
): self {
|
||||
if (is_string($timezone)) {
|
||||
$timezone = DateTime::createTimezone($timezone);
|
||||
}
|
||||
|
||||
$tz = $timezone ?? DateTime::createTimezone('UTC');
|
||||
$startDate = DateTime::fromString($start, $tz);
|
||||
$endDate = DateTime::fromString($end, $tz);
|
||||
|
||||
return new self($startDate, $endDate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt das Startdatum zurück.
|
||||
*
|
||||
* @return DateTimeImmutable
|
||||
*/
|
||||
public function getStart(): DateTimeImmutable
|
||||
{
|
||||
return $this->start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt das Enddatum zurück.
|
||||
*
|
||||
* @return DateTimeImmutable
|
||||
*/
|
||||
public function getEnd(): DateTimeImmutable
|
||||
{
|
||||
return $this->end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Überprüft, ob ein bestimmtes Datum im Bereich liegt.
|
||||
*
|
||||
* @param DateTimeInterface $date Das zu überprüfende Datum
|
||||
* @return bool
|
||||
*/
|
||||
public function contains(DateTimeInterface $date): bool
|
||||
{
|
||||
return ($date >= $this->start && $date <= $this->end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Überprüft, ob ein anderer Bereich vollständig in diesem Bereich enthalten ist.
|
||||
*
|
||||
* @param DateRange $range Der zu überprüfende Bereich
|
||||
* @return bool
|
||||
*/
|
||||
public function containsRange(DateRange $range): bool
|
||||
{
|
||||
return ($range->getStart() >= $this->start && $range->getEnd() <= $this->end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Überprüft, ob sich dieser Bereich mit einem anderen überschneidet.
|
||||
*
|
||||
* @param DateRange $range Der zu überprüfende Bereich
|
||||
* @return bool
|
||||
*/
|
||||
public function overlaps(DateRange $range): bool
|
||||
{
|
||||
return ($this->start <= $range->getEnd() && $this->end >= $range->getStart());
|
||||
}
|
||||
|
||||
/**
|
||||
* Berechnet die Dauer dieses Bereichs.
|
||||
*
|
||||
* @return DateInterval
|
||||
*/
|
||||
public function getDuration(): DateInterval
|
||||
{
|
||||
return $this->start->diff($this->end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt die Dauer in Sekunden zurück.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getDurationInSeconds(): int
|
||||
{
|
||||
return $this->end->getTimestamp() - $this->start->getTimestamp();
|
||||
}
|
||||
}
|
||||
171
src/Framework/DateTime/DateTime.php
Normal file
171
src/Framework/DateTime/DateTime.php
Normal file
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\DateTime;
|
||||
|
||||
use App\Framework\DateTime\Exceptions\InvalidDateTimeException;
|
||||
use App\Framework\DateTime\Exceptions\InvalidTimezoneException;
|
||||
use DateInterval;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeInterface;
|
||||
use DateTimeZone;
|
||||
|
||||
final class DateTime
|
||||
{
|
||||
private static ?DateTimeZone $defaultTimezone = null;
|
||||
|
||||
/**
|
||||
* Erstellt ein DateTimeImmutable-Objekt aus einem Zeitstempel.
|
||||
*
|
||||
* @param int $timestamp UNIX-Zeitstempel
|
||||
* @param DateTimeZone|string|null $timezone Optionale Zeitzone (verwendet Standard-Zeitzone wenn null)
|
||||
* @return DateTimeImmutable
|
||||
* @throws InvalidTimezoneException|InvalidDateTimeException wenn die Zeitzone ungültig ist
|
||||
*/
|
||||
public static function fromTimestamp(int $timestamp, DateTimeZone|string|null $timezone = null): DateTimeImmutable
|
||||
{
|
||||
$tz = $timezone !== null ? self::createTimezone($timezone) : self::getDefaultTimezone();
|
||||
|
||||
try {
|
||||
return new DateTimeImmutable('@' . $timestamp)->setTimezone($tz);
|
||||
} catch (\Exception $e) {
|
||||
throw new InvalidDateTimeException((string)$timestamp, 'timestamp', $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt ein DateTimeImmutable-Objekt aus einem String.
|
||||
*
|
||||
* @param string $dateTime Der zu parsende Zeitstring
|
||||
* @param DateTimeZone|string|null $timezone Optionale Zeitzone (verwendet Standard-Zeitzone wenn null)
|
||||
* @return DateTimeImmutable
|
||||
* @throws InvalidDateTimeException wenn das Parsen fehlschlägt
|
||||
* @throws InvalidTimezoneException wenn die Zeitzone ungültig ist
|
||||
*/
|
||||
public static function fromString(string $dateTime, DateTimeZone|string|null $timezone = null): DateTimeImmutable
|
||||
{
|
||||
$tz = $timezone !== null ? self::createTimezone($timezone) : self::getDefaultTimezone();
|
||||
|
||||
try {
|
||||
return new DateTimeImmutable($dateTime, $tz);
|
||||
} catch (\Exception $e) {
|
||||
throw new InvalidDateTimeException($dateTime, null, $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt ein DateTimeImmutable-Objekt aus einem String mit spezifischem Format.
|
||||
*
|
||||
* @param string $dateTime Der zu parsende Zeitstring
|
||||
* @param string $format Das erwartete Format
|
||||
* @param DateTimeZone|string|null $timezone Optionale Zeitzone (verwendet Standard-Zeitzone wenn null)
|
||||
* @return DateTimeImmutable
|
||||
* @throws InvalidDateTimeException wenn das Parsen fehlschlägt
|
||||
* @throws InvalidTimezoneException wenn die Zeitzone ungültig ist
|
||||
*/
|
||||
public static function fromFormat(string $dateTime, string $format, DateTimeZone|string|null $timezone = null): DateTimeImmutable
|
||||
{
|
||||
$tz = $timezone !== null ? self::createTimezone($timezone) : self::getDefaultTimezone();
|
||||
|
||||
try {
|
||||
$date = DateTimeImmutable::createFromFormat($format, $dateTime, $tz);
|
||||
|
||||
if ($date === false) {
|
||||
throw new InvalidDateTimeException($dateTime, $format);
|
||||
}
|
||||
|
||||
return $date;
|
||||
} catch (\Exception $e) {
|
||||
if ($e instanceof InvalidDateTimeException) {
|
||||
throw $e;
|
||||
}
|
||||
throw new InvalidDateTimeException($dateTime, $format, $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt ein DateTimeImmutable-Objekt aus einem anderen DateTimeInterface.
|
||||
*
|
||||
* @param DateTimeInterface $dateTime Das zu konvertierende DateTime
|
||||
* @param DateTimeZone|string|null $timezone Optionale neue Zeitzone
|
||||
* @return DateTimeImmutable
|
||||
* @throws InvalidDateTimeException wenn die Zeitzone ungültig ist
|
||||
*/
|
||||
public static function fromDateTime(DateTimeInterface $dateTime, DateTimeZone|string|null $timezone = null): DateTimeImmutable
|
||||
{
|
||||
try {
|
||||
if ($dateTime instanceof DateTimeImmutable) {
|
||||
$result = $dateTime;
|
||||
} else {
|
||||
$result = DateTimeImmutable::createFromInterface($dateTime);
|
||||
}
|
||||
|
||||
if ($timezone !== null) {
|
||||
$tz = self::createTimezone($timezone);
|
||||
$result = $result->setTimezone($tz);
|
||||
}
|
||||
|
||||
return $result;
|
||||
} catch (\Exception $e) {
|
||||
throw new InvalidDateTimeException($dateTime->format('c'), null, $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt ein DateInterval-Objekt.
|
||||
*
|
||||
* @param string $interval Das Interval im ISO 8601 Format (z.B. 'P1D', 'PT1H')
|
||||
* @return DateInterval
|
||||
* @throws InvalidDateTimeException wenn das Interval ungültig ist
|
||||
*/
|
||||
public static function createInterval(string $interval): DateInterval
|
||||
{
|
||||
try {
|
||||
return new DateInterval($interval);
|
||||
} catch (\Exception $e) {
|
||||
throw new InvalidDateTimeException($interval, 'DateInterval', $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt eine DateTimeZone.
|
||||
*
|
||||
* @param DateTimeZone|string $timezone Die Zeitzone
|
||||
* @return DateTimeZone
|
||||
* @throws InvalidTimezoneException wenn die Zeitzone ungültig ist
|
||||
*/
|
||||
public static function createTimezone(DateTimeZone|string $timezone): DateTimeZone
|
||||
{
|
||||
if ($timezone instanceof DateTimeZone) {
|
||||
return $timezone;
|
||||
}
|
||||
|
||||
try {
|
||||
return new DateTimeZone($timezone);
|
||||
} catch (\Exception $e) {
|
||||
throw new InvalidTimezoneException($timezone, $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt die Standard-Zeitzone zurück.
|
||||
*
|
||||
* @return DateTimeZone
|
||||
*/
|
||||
public static function getDefaultTimezone(): DateTimeZone
|
||||
{
|
||||
return self::$defaultTimezone ?? new DateTimeZone('Europa/Berlin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Setzt eine neue Standard-Zeitzone.
|
||||
*
|
||||
* @param DateTimeZone|string $timezone Die neue Standard-Zeitzone
|
||||
* @throws InvalidTimezoneException wenn die Zeitzone ungültig ist
|
||||
*/
|
||||
public static function setDefaultTimezone(DateTimeZone|string $timezone): void
|
||||
{
|
||||
self::$defaultTimezone = self::createTimezone($timezone);
|
||||
}
|
||||
}
|
||||
133
src/Framework/DateTime/DateTimeFormatter.php
Normal file
133
src/Framework/DateTime/DateTimeFormatter.php
Normal file
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
namespace App\Framework\DateTime;
|
||||
|
||||
use DateInvalidTimeZoneException;
|
||||
use DateMalformedStringException;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeInterface;
|
||||
use DateTimeZone;
|
||||
|
||||
class DateTimeFormatter
|
||||
{
|
||||
/**
|
||||
* Standard-Zeitzone für Formatierungen
|
||||
*/
|
||||
private DateTimeZone $timezone;
|
||||
|
||||
/**
|
||||
* @param DateTimeZone|string|null $timezone Die zu verwendende Zeitzone (Standard: UTC)
|
||||
* @throws DateInvalidTimeZoneException
|
||||
*/
|
||||
public function __construct(DateTimeZone|string|null $timezone = null)
|
||||
{
|
||||
if (is_string($timezone)) {
|
||||
$timezone = new DateTimeZone($timezone);
|
||||
}
|
||||
|
||||
$this->timezone = $timezone ?? new DateTimeZone('Europe/Berlin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatiert ein DateTime im ISO8601-Format.
|
||||
*
|
||||
* @param DateTimeInterface $dateTime Das zu formatierende DateTime
|
||||
* @return string
|
||||
* @throws DateMalformedStringException
|
||||
*/
|
||||
public function formatIso8601(DateTimeInterface $dateTime): string
|
||||
{
|
||||
return $this->format($dateTime, DateTimeInterface::ATOM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatiert ein DateTime im SQL-Datetime-Format.
|
||||
*
|
||||
* @param DateTimeInterface $dateTime Das zu formatierende DateTime
|
||||
* @return string
|
||||
* @throws DateMalformedStringException
|
||||
*/
|
||||
public function formatSql(DateTimeInterface $dateTime): string
|
||||
{
|
||||
return $this->format($dateTime, 'Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatiert ein DateTime nur als Datum.
|
||||
*
|
||||
* @param DateTimeInterface $dateTime Das zu formatierende DateTime
|
||||
* @return string
|
||||
* @throws DateMalformedStringException
|
||||
*/
|
||||
public function formatDate(DateTimeInterface $dateTime): string
|
||||
{
|
||||
#return $this->format($dateTime, 'Y-m-d');
|
||||
|
||||
return $this->format($dateTime, 'd.m.Y');
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatiert ein DateTime nur als Zeit.
|
||||
*
|
||||
* @param DateTimeInterface $dateTime Das zu formatierende DateTime
|
||||
* @return string
|
||||
* @throws DateMalformedStringException
|
||||
*/
|
||||
public function formatTime(DateTimeInterface $dateTime): string
|
||||
{
|
||||
return $this->format($dateTime, 'H:i:s');
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatiert ein DateTime in einem benutzerdefinierten Format.
|
||||
*
|
||||
* @param DateTimeInterface $dateTime Das zu formatierende DateTime
|
||||
* @param string $format Das Format-Pattern
|
||||
* @return string
|
||||
* @throws DateMalformedStringException
|
||||
*/
|
||||
public function format(DateTimeInterface $dateTime, string $format): string
|
||||
{
|
||||
// Stelle sicher, dass die Zeitzone korrekt ist
|
||||
$dateInCorrectTimezone = $this->ensureTimezone($dateTime);
|
||||
|
||||
return $dateInCorrectTimezone->format($format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stellt sicher, dass ein DateTime die korrekte Zeitzone hat.
|
||||
*
|
||||
* @param DateTimeInterface $dateTime Das zu überprüfende DateTime
|
||||
* @return DateTimeImmutable
|
||||
* @throws DateMalformedStringException
|
||||
*/
|
||||
private function ensureTimezone(DateTimeInterface $dateTime): DateTimeImmutable
|
||||
{
|
||||
if ($dateTime->getTimezone()->getName() !== $this->timezone->getName()) {
|
||||
if ($dateTime instanceof DateTimeImmutable) {
|
||||
return $dateTime->setTimezone($this->timezone);
|
||||
}
|
||||
|
||||
// Konvertiere DateTime zu DateTimeImmutable mit der richtigen Zeitzone
|
||||
return new DateTimeImmutable('@' . $dateTime->getTimestamp())
|
||||
->setTimezone($this->timezone);
|
||||
}
|
||||
|
||||
if ($dateTime instanceof DateTimeImmutable) {
|
||||
return $dateTime;
|
||||
}
|
||||
|
||||
// Konvertiere DateTime zu DateTimeImmutable
|
||||
return DateTimeImmutable::createFromInterface($dateTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt die verwendete Zeitzone zurück.
|
||||
*
|
||||
* @return DateTimeZone
|
||||
*/
|
||||
public function getTimezone(): DateTimeZone
|
||||
{
|
||||
return $this->timezone;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\DateTime\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class InvalidDateTimeException extends Exception
|
||||
{
|
||||
public function __construct(string $dateTime, ?string $format = null, ?\Throwable $previous = null)
|
||||
{
|
||||
$message = $format !== null
|
||||
? sprintf('Konnte DateTime nicht aus "%s" mit Format "%s" erstellen', $dateTime, $format)
|
||||
: sprintf('Ungültiges DateTime-Format: "%s"', $dateTime);
|
||||
|
||||
parent::__construct($message, 0, $previous);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\DateTime\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class InvalidTimezoneException extends Exception
|
||||
{
|
||||
public function __construct(string $timezone, ?\Throwable $previous = null)
|
||||
{
|
||||
parent::__construct(
|
||||
sprintf('Ungültige Zeitzone: "%s"', $timezone),
|
||||
0,
|
||||
$previous
|
||||
);
|
||||
}
|
||||
}
|
||||
162
src/Framework/DateTime/FrozenClock.php
Normal file
162
src/Framework/DateTime/FrozenClock.php
Normal file
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
namespace App\Framework\DateTime;
|
||||
|
||||
use App\Framework\DateTime\Exceptions\InvalidDateTimeException;
|
||||
use App\Framework\DateTime\Exceptions\InvalidTimezoneException;
|
||||
use DateInvalidOperationException;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeZone;
|
||||
|
||||
final class FrozenClock implements Clock
|
||||
{
|
||||
private DateTimeImmutable $frozenTime;
|
||||
private DateTimeZone $timezone;
|
||||
|
||||
/**
|
||||
* @param DateTimeImmutable|string|null $time Die fixierte Zeit (Standard: aktuelle Zeit über SystemClock)
|
||||
* @param DateTimeZone|string|null $timezone Die zu verwendende Zeitzone (Standard: UTC)
|
||||
* @throws InvalidDateTimeException wenn die Zeit ungültig ist
|
||||
* @throws InvalidTimezoneException wenn die Zeitzone ungültig ist
|
||||
*/
|
||||
public function __construct(
|
||||
DateTimeImmutable|string|null $time = null,
|
||||
DateTimeZone|string|null $timezone = null
|
||||
) {
|
||||
$this->timezone = $timezone !== null
|
||||
? DateTime::createTimezone($timezone)
|
||||
: DateTime::getDefaultTimezone();
|
||||
|
||||
if ($time === null) {
|
||||
// Verwende SystemClock für die initiale Zeit
|
||||
$systemClock = new SystemClock($this->timezone);
|
||||
$this->frozenTime = $systemClock->now();
|
||||
} elseif (is_string($time)) {
|
||||
$this->frozenTime = DateTime::fromString($time, $this->timezone);
|
||||
} else {
|
||||
$this->frozenTime = DateTime::fromDateTime($time, $this->timezone);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function now(): DateTimeImmutable
|
||||
{
|
||||
return $this->frozenTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws InvalidTimezoneException
|
||||
*/
|
||||
public function fromTimestamp(int $timestamp): DateTimeImmutable
|
||||
{
|
||||
return DateTime::fromTimestamp($timestamp, $this->timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function fromString(string $dateTime, ?string $format = null): DateTimeImmutable
|
||||
{
|
||||
if ($format === null) {
|
||||
return DateTime::fromString($dateTime, $this->timezone);
|
||||
}
|
||||
|
||||
return DateTime::fromFormat($dateTime, $format, $this->timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt ein Today-Datum (00:00:00) basierend auf der gefrorenen Zeit.
|
||||
*
|
||||
* @return DateTimeImmutable
|
||||
*/
|
||||
public function today(): DateTimeImmutable
|
||||
{
|
||||
return $this->frozenTime->setTime(0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt ein Tomorrow-Datum (00:00:00) basierend auf der gefrorenen Zeit.
|
||||
*
|
||||
* @return DateTimeImmutable
|
||||
*/
|
||||
public function tomorrow(): DateTimeImmutable
|
||||
{
|
||||
return $this->frozenTime->modify('+1 day')->setTime(0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt ein Yesterday-Datum (00:00:00) basierend auf der gefrorenen Zeit.
|
||||
*
|
||||
* @return DateTimeImmutable
|
||||
*/
|
||||
public function yesterday(): DateTimeImmutable
|
||||
{
|
||||
return $this->frozenTime->modify('-1 day')->setTime(0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setzt die fixierte Zeit auf einen neuen Wert.
|
||||
*
|
||||
* @param DateTimeImmutable|string $time Die neue fixierte Zeit
|
||||
* @return self
|
||||
* @throws InvalidDateTimeException|InvalidTimezoneException wenn die Zeit ungültig ist
|
||||
*/
|
||||
public function setTo(DateTimeImmutable|string $time): self
|
||||
{
|
||||
if (is_string($time)) {
|
||||
$this->frozenTime = DateTime::fromString($time, $this->timezone);
|
||||
} else {
|
||||
$this->frozenTime = DateTime::fromDateTime($time, $this->timezone);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bewegt die fixierte Zeit um eine bestimmte Zeit vorwärts.
|
||||
*
|
||||
* @param string $interval Eine DateInterval-kompatible Zeichenfolge (z.B. 'PT1H' für eine Stunde)
|
||||
* @return self
|
||||
* @throws InvalidDateTimeException wenn das Interval ungültig ist
|
||||
*/
|
||||
public function moveForward(string $interval): self
|
||||
{
|
||||
$dateInterval = DateTime::createInterval($interval);
|
||||
$this->frozenTime = $this->frozenTime->add($dateInterval);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bewegt die fixierte Zeit um eine bestimmte Zeit zurück.
|
||||
*
|
||||
* @param string $interval Eine DateInterval-kompatible Zeichenfolge (z.B. 'PT1H' für eine Stunde)
|
||||
* @return self
|
||||
* @throws InvalidDateTimeException|DateInvalidOperationException wenn das Interval ungültig ist
|
||||
*/
|
||||
public function moveBackward(string $interval): self
|
||||
{
|
||||
$dateInterval = DateTime::createInterval($interval);
|
||||
$this->frozenTime = $this->frozenTime->sub($dateInterval);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function time(): int
|
||||
{
|
||||
return $this->now()->getTimestamp();
|
||||
}
|
||||
|
||||
public function microtime(bool $asFloat = false): float|array
|
||||
{
|
||||
$timestamp = $this->now()->getTimestamp();
|
||||
$microseconds = 0; // In FrozenClock haben wir keine Mikrosekunden-Präzision
|
||||
|
||||
if ($asFloat) {
|
||||
return (float)$timestamp;
|
||||
}
|
||||
|
||||
return [(float)$timestamp, $microseconds];
|
||||
}
|
||||
}
|
||||
100
src/Framework/DateTime/SystemClock.php
Normal file
100
src/Framework/DateTime/SystemClock.php
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace App\Framework\DateTime;
|
||||
|
||||
use App\Framework\DateTime\Exceptions\InvalidDateTimeException;
|
||||
use App\Framework\DateTime\Exceptions\InvalidTimezoneException;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeZone;
|
||||
use function microtime;
|
||||
use function time;
|
||||
|
||||
final readonly class SystemClock implements Clock
|
||||
{
|
||||
private DateTimeZone $timezone;
|
||||
|
||||
/**
|
||||
* @param DateTimeZone|string|null $timezone Die zu verwendende Zeitzone (Standard: UTC)
|
||||
* @throws InvalidTimezoneException wenn die Zeitzone ungültig ist
|
||||
*/
|
||||
public function __construct(DateTimeZone|string|null $timezone = null)
|
||||
{
|
||||
$this->timezone = $timezone !== null
|
||||
? DateTime::createTimezone($timezone)
|
||||
: DateTime::getDefaultTimezone();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws InvalidDateTimeException
|
||||
*/
|
||||
public function now(): DateTimeImmutable
|
||||
{
|
||||
try {
|
||||
return new DateTimeImmutable('now', $this->timezone);
|
||||
} catch (\Exception $e) {
|
||||
throw new InvalidDateTimeException('now', null, $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws InvalidTimezoneException|InvalidDateTimeException
|
||||
*/
|
||||
public function fromTimestamp(int $timestamp): DateTimeImmutable
|
||||
{
|
||||
return DateTime::fromTimestamp($timestamp, $this->timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function fromString(string $dateTime, ?string $format = null): DateTimeImmutable
|
||||
{
|
||||
if ($format === null) {
|
||||
return DateTime::fromString($dateTime, $this->timezone);
|
||||
}
|
||||
|
||||
return DateTime::fromFormat($dateTime, $format, $this->timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt ein Today-Datum (00:00:00).
|
||||
*
|
||||
* @return DateTimeImmutable
|
||||
*/
|
||||
public function today(): DateTimeImmutable
|
||||
{
|
||||
return DateTime::fromString('today', $this->timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt ein Tomorrow-Datum (00:00:00).
|
||||
*
|
||||
* @return DateTimeImmutable
|
||||
*/
|
||||
public function tomorrow(): DateTimeImmutable
|
||||
{
|
||||
return DateTime::fromString('tomorrow', $this->timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt ein Yesterday-Datum (00:00:00).
|
||||
*
|
||||
* @return DateTimeImmutable
|
||||
*/
|
||||
public function yesterday(): DateTimeImmutable
|
||||
{
|
||||
return DateTime::fromString('yesterday', $this->timezone);
|
||||
}
|
||||
|
||||
public function time(): int
|
||||
{
|
||||
return time();
|
||||
}
|
||||
|
||||
public function microtime(bool $asFloat = false): float|array
|
||||
{
|
||||
return microtime($asFloat);
|
||||
}
|
||||
}
|
||||
26
src/Framework/DateTime/SystemTimer.php
Normal file
26
src/Framework/DateTime/SystemTimer.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\DateTime;
|
||||
|
||||
use function sleep;
|
||||
use function usleep;
|
||||
|
||||
final readonly class SystemTimer implements Timer
|
||||
{
|
||||
|
||||
public function sleep(int $seconds): void
|
||||
{
|
||||
sleep($seconds);
|
||||
}
|
||||
|
||||
public function usleep(int $microseconds): void
|
||||
{
|
||||
usleep($microseconds);
|
||||
}
|
||||
|
||||
public function msleep(int $milliseconds): void
|
||||
{
|
||||
usleep($milliseconds * 1000);
|
||||
}
|
||||
}
|
||||
28
src/Framework/DateTime/Timer.php
Normal file
28
src/Framework/DateTime/Timer.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\DateTime;
|
||||
|
||||
interface Timer
|
||||
{
|
||||
/**
|
||||
* Pausiert die Ausführung für die angegebene Anzahl von Sekunden.
|
||||
*
|
||||
* @param int $seconds Anzahl der Sekunden
|
||||
*/
|
||||
public function sleep(int $seconds): void;
|
||||
|
||||
/**
|
||||
* Pausiert die Ausführung für die angegebene Anzahl von Mikrosekunden.
|
||||
*
|
||||
* @param int $microseconds Anzahl der Mikrosekunden
|
||||
*/
|
||||
public function usleep(int $microseconds): void;
|
||||
|
||||
/**
|
||||
* Pausiert die Ausführung für die angegebene Anzahl von Millisekunden.
|
||||
*
|
||||
* @param int $milliseconds Anzahl der Millisekunden
|
||||
*/
|
||||
public function msleep(int $milliseconds): void;
|
||||
}
|
||||
9
src/Framework/DateTime/Timezone.php
Normal file
9
src/Framework/DateTime/Timezone.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace App\Framework\DateTime;
|
||||
|
||||
enum Timezone: string
|
||||
{
|
||||
case UTC = 'UTC';
|
||||
case EuropeBerlin = 'Europe/Berlin';
|
||||
}
|
||||
Reference in New Issue
Block a user