ValidityTimeType::class, 'fixed_starts_at' => 'datetime', 'fixed_expires_at' => 'datetime', ]; } /** @return HasMany */ public function attributeOptions(): HasMany { return $this->hasMany(AttributeOption::class); } /** @return HasOne */ public function eventDate(): HasOne { return $this->hasOne(EventDate::class); } public function startsAt( ?CarbonInterface $at = null, string $timezone = 'UTC', ): ?CarbonInterface { if ($this->type === ValidityTimeType::FixedWindow) { return $this->fixed_starts_at; } return $this->atCurrentDate($this->start_time, $at, $timezone); } public function expiresAt( ?CarbonInterface $at = null, string $timezone = 'UTC', ): ?CarbonInterface { if ($this->type === ValidityTimeType::FixedWindow) { return $this->fixed_expires_at; } return $this->atCurrentDate($this->end_time, $at, $timezone); } public function isValid( ?CarbonInterface $at = null, string $timezone = 'UTC', ): bool { $at ??= now(); $startsAt = $this->startsAt($at, $timezone); $expiresAt = $this->expiresAt($at, $timezone); if ($this->type === ValidityTimeType::TimeWindow && $startsAt !== null && $expiresAt !== null && $expiresAt->lessThanOrEqualTo($startsAt)) { if ($at->lessThan($expiresAt)) { $startsAt = $startsAt->subDay(); } else { $expiresAt = $expiresAt->addDay(); } } return ($startsAt === null || $startsAt->lessThanOrEqualTo($at)) && ($expiresAt === null || $expiresAt->greaterThan($at)); } private function atCurrentDate( ?string $time, ?CarbonInterface $at, string $timezone, ): ?CarbonInterface { if ($time === null) { return null; } $at ??= now(); $localDate = CarbonImmutable::instance($at) ->setTimezone($timezone) ->format('Y-m-d'); return CarbonImmutable::parse($localDate.' '.$time, $timezone); } }