|
| 1 | +<?php |
| 2 | + |
| 3 | +declare(strict_types=1); |
| 4 | + |
| 5 | +namespace Gemini\Data; |
| 6 | + |
| 7 | +use DateTime; |
| 8 | +use InvalidArgumentException; |
| 9 | +use stdClass; |
| 10 | + |
| 11 | +/** |
| 12 | + * Represents a time interval, encoded as a Timestamp start (inclusive) and a Timestamp end (exclusive). |
| 13 | + * |
| 14 | + * The start must be less than or equal to the end. When the start equals the end, the interval is empty (matches no time). When both start and end are unspecified, the interval matches any time. |
| 15 | + * |
| 16 | + * https://ai.google.dev/api/caching#Interval |
| 17 | + */ |
| 18 | +final class Interval |
| 19 | +{ |
| 20 | + /** |
| 21 | + * @param ?string $startTime Optional. Inclusive start of the interval. If specified, a Timestamp matching this interval will have to be the same or after the start. Uses RFC 3339 format. Examples: "2014-10-02T15:01:23Z", "2014-10-02T15:01:23.045123456Z" or "2014-10-02T15:01:23+05:30". |
| 22 | + * @param ?string $endTime Optional. Exclusive end of the interval. If specified, a Timestamp matching this interval will have to be before the end. Uses RFC 3339 format. Examples: "2014-10-02T15:01:23Z", "2014-10-02T15:01:23.045123456Z" or "2014-10-02T15:01:23+05:30". |
| 23 | + * |
| 24 | + * @throws InvalidArgumentException When timestamp format is invalid or start time is after end time |
| 25 | + */ |
| 26 | + public function __construct( |
| 27 | + public readonly ?string $startTime, |
| 28 | + public readonly ?string $endTime, |
| 29 | + ) { |
| 30 | + if ($this->startTime !== null && ! $this->isValidTimestamp($this->startTime)) { |
| 31 | + throw new InvalidArgumentException('startTime must be in RFC 3339 timestamp format'); |
| 32 | + } |
| 33 | + |
| 34 | + if ($this->endTime !== null && ! $this->isValidTimestamp($this->endTime)) { |
| 35 | + throw new InvalidArgumentException('endTime must be in RFC 3339 timestamp format'); |
| 36 | + } |
| 37 | + |
| 38 | + if ($this->startTime !== null && $this->endTime !== null) { |
| 39 | + $startTimestamp = strtotime($this->startTime); |
| 40 | + $endTimestamp = strtotime($this->endTime); |
| 41 | + |
| 42 | + if ($startTimestamp === false || $endTimestamp === false) { |
| 43 | + throw new InvalidArgumentException('Invalid timestamp format'); |
| 44 | + } |
| 45 | + |
| 46 | + if ($startTimestamp > $endTimestamp) { |
| 47 | + throw new InvalidArgumentException('startTime must be less than or equal to endTime'); |
| 48 | + } |
| 49 | + } |
| 50 | + } |
| 51 | + |
| 52 | + /** |
| 53 | + * @param array{startTime?: ?string, endTime?: ?string} $attributes |
| 54 | + */ |
| 55 | + public static function from(array $attributes): self |
| 56 | + { |
| 57 | + return new self($attributes['startTime'] ?? null, $attributes['endTime'] ?? null); |
| 58 | + } |
| 59 | + |
| 60 | + /** |
| 61 | + * @return stdClass|array{startTime?: ?string, endTime?: ?string} |
| 62 | + */ |
| 63 | + public function toArray(): stdClass|array |
| 64 | + { |
| 65 | + $data = []; |
| 66 | + |
| 67 | + if ($this->startTime !== null) { |
| 68 | + $data['startTime'] = $this->startTime; |
| 69 | + } |
| 70 | + |
| 71 | + if ($this->endTime !== null) { |
| 72 | + $data['endTime'] = $this->endTime; |
| 73 | + } |
| 74 | + |
| 75 | + return empty($data) ? new stdClass : $data; |
| 76 | + } |
| 77 | + |
| 78 | + /** |
| 79 | + * Validates if a string is in RFC 3339 timestamp format |
| 80 | + */ |
| 81 | + private function isValidTimestamp(string $timestamp): bool |
| 82 | + { |
| 83 | + // RFC 3339 regex pattern |
| 84 | + $pattern = '/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,9})?(Z|[+-]\d{2}:\d{2})$/'; |
| 85 | + |
| 86 | + if (! preg_match($pattern, $timestamp)) { |
| 87 | + return false; |
| 88 | + } |
| 89 | + |
| 90 | + // Handle Z timezone suffix by converting to +00:00 |
| 91 | + $normalizedTimestamp = str_replace('Z', '+00:00', $timestamp); |
| 92 | + |
| 93 | + // Try with extended format first (includes microseconds) |
| 94 | + $dateTime = DateTime::createFromFormat(DateTime::RFC3339_EXTENDED, $normalizedTimestamp); |
| 95 | + if ($dateTime === false) { |
| 96 | + // Try with standard RFC3339 format |
| 97 | + $dateTime = DateTime::createFromFormat(DateTime::RFC3339, $normalizedTimestamp); |
| 98 | + } |
| 99 | + |
| 100 | + return $dateTime !== false; |
| 101 | + } |
| 102 | +} |
0 commit comments