169 lines
5.0 KiB
PHP
169 lines
5.0 KiB
PHP
<?php
|
||
|
||
namespace App\Services;
|
||
|
||
use App\Models\User;
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Support\Carbon;
|
||
|
||
class DateRangeService
|
||
{
|
||
/**
|
||
* Получить унифицированный объект диапазона дат
|
||
*/
|
||
public function getNormalizedDateRange(User $user, ?string $startAt = null, ?string $endAt = null): DateRange
|
||
{
|
||
[$startDate, $endDate] = $this->getDateRangeForUser($user, $startAt, $endAt);
|
||
|
||
$startCarbon = Carbon::parse($startDate)->setTimeZone('Asia/Yakutsk');
|
||
$endCarbon = Carbon::parse($endDate)->setTimeZone('Asia/Yakutsk');
|
||
|
||
return new DateRange(
|
||
startDate: $startCarbon,
|
||
endDate: $endCarbon,
|
||
startDateRaw: $startDate,
|
||
endDateRaw: $endDate,
|
||
isOneDay: $this->isRangeOneDay($startDate, $endDate)
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Получить диапазон дат из запроса
|
||
*/
|
||
public function getDateRangeFromRequest(Request $request, User $user): DateRange
|
||
{
|
||
return $this->getNormalizedDateRange(
|
||
$user,
|
||
$request->query('startAt', $request->get('startAt')),
|
||
$request->query('endAt', $request->get('endAt'))
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Получить диапазон дат для статистики (по умолчанию с начала года)
|
||
*/
|
||
public function getStatisticsDateRange(User $user, ?string $startAt = null, ?string $endAt = null): array
|
||
{
|
||
// Если даты переданы - используем их
|
||
if ($startAt && $endAt) {
|
||
return $this->getDateRangeForUser($user, $startAt, $endAt);
|
||
}
|
||
|
||
// По умолчанию: с начала года до сегодня
|
||
$startDate = Carbon::now('Asia/Yakutsk')
|
||
->startOfYear() // 1 января текущего года
|
||
->setTime(6, 0);
|
||
|
||
$endDate = Carbon::now('Asia/Yakutsk')
|
||
->setTime(6, 0);
|
||
|
||
return [
|
||
$startDate->format('Y-m-d H:i:s'),
|
||
$endDate->format('Y-m-d H:i:s')
|
||
];
|
||
}
|
||
|
||
public function getDateRangeForUser($user, $startAt = null, $endAt = null): array
|
||
{
|
||
if ($startAt && $endAt) {
|
||
return $this->getCustomDateRange($startAt, $endAt, $user);
|
||
}
|
||
|
||
return $this->getDefaultDateRange($user);
|
||
}
|
||
|
||
public function isRangeOneDay($startAt = null, $endAt = null): bool
|
||
{
|
||
if (!$startAt || !$endAt) return false;
|
||
|
||
$startDate = $this->parseDate($startAt);
|
||
$endDate = $this->parseDate($endAt);
|
||
|
||
return $startDate->diffInDays($endDate) === 1.0;
|
||
}
|
||
|
||
private function getCustomDateRange($startAt, $endAt, $user): array
|
||
{
|
||
$startDate = $this->parseDate($startAt);
|
||
$endDate = $this->parseDate($endAt);
|
||
|
||
if ($startDate->isSameDay($endDate)) {
|
||
$startDate = $startDate->subDay()->setTime(6, 0);
|
||
$endDate = $endDate->setTime(6, 0);
|
||
} else {
|
||
$startDate = $startDate->setTime(6, 0);
|
||
$endDate = $endDate->setTime(6, 0);
|
||
}
|
||
|
||
return [
|
||
$startDate->format('Y-m-d H:i:s'),
|
||
$endDate->format('Y-m-d H:i:s')
|
||
];
|
||
}
|
||
|
||
private function getDefaultDateRange($user): array
|
||
{
|
||
$startDate = Carbon::now('Asia/Yakutsk')
|
||
->subDay()
|
||
->setTime(6, 0);
|
||
|
||
$endDate = Carbon::now('Asia/Yakutsk')
|
||
->setTime(6, 0);
|
||
|
||
return [
|
||
$startDate->format('Y-m-d H:i:s'),
|
||
$endDate->format('Y-m-d H:i:s')
|
||
];
|
||
}
|
||
|
||
public function parseDate($dateInput): Carbon
|
||
{
|
||
if (is_numeric($dateInput)) {
|
||
return Carbon::createFromTimestampMs($dateInput)
|
||
->setTimezone('Asia/Yakutsk');
|
||
}
|
||
|
||
return Carbon::parse($dateInput, 'Asia/Yakutsk');
|
||
}
|
||
|
||
/**
|
||
* Конвертировать дату в Carbon объект
|
||
*/
|
||
public function toCarbon($date): Carbon
|
||
{
|
||
if ($date instanceof Carbon) {
|
||
return $date;
|
||
}
|
||
|
||
if (is_string($date)) {
|
||
return Carbon::parse($date, 'Asia/Yakutsk');
|
||
}
|
||
|
||
return Carbon::parse($date);
|
||
}
|
||
|
||
/**
|
||
* Получить дату в формате для SQL запроса
|
||
*/
|
||
public function toSqlFormat($date): string
|
||
{
|
||
return $this->toCarbon($date)->format('Y-m-d H:i:s');
|
||
}
|
||
|
||
public function createDateRangeForDate(Carbon $date, User $user): DateRange
|
||
{
|
||
// Для автоматического заполнения используем логику как для врача
|
||
// (вчера 06:00 - сегодня 06:00)
|
||
$startDate = $date->copy()->subDay()->setTime(6, 0);
|
||
$endDate = $date->copy()->setTime(6, 0);
|
||
|
||
return new DateRange(
|
||
startDate: $startDate,
|
||
endDate: $endDate,
|
||
startDateRaw: $startDate->format('Y-m-d H:i:s'),
|
||
endDateRaw: $endDate->format('Y-m-d H:i:s'),
|
||
isOneDay: true
|
||
);
|
||
}
|
||
}
|