utc(), Carbon::parse($periodEnd)->utc(), ]; } /** * @return array{0: string, 1: string} */ public static function boundStrings(string $periodStart, string $periodEnd): array { [$start, $end] = self::bounds($periodStart, $periodEnd); return [$start->toDateTimeString(), $end->toDateTimeString()]; } /** * 开账 API:支持 `Y-m-d` 或带时刻字符串;前者按站点业务时区扩界,后者按 UTC 解释。 * * @return array{0: string, 1: string} */ public static function normalizeInputBounds( string $periodStart, string $periodEnd, string $timezone = 'UTC', ): array { $startRaw = trim($periodStart); $endRaw = trim($periodEnd); if ($startRaw === '' || $endRaw === '') { throw ValidationException::withMessages([ 'period_start' => ['required'], ]); } $tz = AgentSettlementSiteTimezone::isValid($timezone) ? $timezone : 'UTC'; $startAt = self::isDateOnly($startRaw) ? Carbon::parse($startRaw.' 00:00:00', $tz)->utc() : Carbon::parse($startRaw)->utc(); $endAt = self::isDateOnly($endRaw) ? Carbon::parse($endRaw.' 23:59:59', $tz)->utc() : Carbon::parse($endRaw)->utc(); if ($endAt->lessThan($startAt)) { throw ValidationException::withMessages([ 'period_end' => ['after:period_start'], ]); } return [$startAt->toDateTimeString(), $endAt->toDateTimeString()]; } private static function isDateOnly(string $value): bool { return (bool) preg_match('/^\d{4}-\d{2}-\d{2}$/', $value); } }