Сайт Романа ПарпалакаБлог20251106

Как правильно запрограммировать условие «по такое-то число»

6 ноября 2025 года, 22:51

Наверно, не будет преувеличением сказать, что я ни разу не видел, чтобы кто-то из коллег правильно программировал верхнюю границу диапазона дат. Эта типовая задача возникает, когда нужно вывести какие-то записи с такого-то по такое-то число.

Сейчас, в эпоху нейросетей, легко обобщить это наблюдение на всех программистов. Нейросети выдают как раз «усредненный» код. Так что рассмотрим фрагмент сгенерированного кода (дополнительный плюс в том, что на это некому обижаться, по крайней мере пока):

$dateFrom = $this->createDateTime($filters['dateFrom'], endOfDay: false);
if (null !== $dateFrom) {
    $queryBuilder
        ->andWhere('log.loggedAt >= :dateFrom')
        ->setParameter('dateFrom', $dateFrom)
    ;
}

$dateTo = $this->createDateTime($filters['dateTo'], endOfDay: true);
if (null !== $dateTo) {
    $queryBuilder
        ->andWhere('log.loggedAt <= :dateTo')
        ->setParameter('dateTo', $dateTo)
    ;
}

// ...

private function createDateTime(?string $value, bool $endOfDay): ?\DateTimeImmutable
{
    if (null === $value || '' === $value) {
        return null;
    }

    $date = \DateTimeImmutable::createFromFormat('Y-m-d', $value) ?: \DateTimeImmutable::createFromFormat(\DateTimeInterface::ATOM, $value);

    if (false === $date) {
        return null;
    }

    return $endOfDay ? $date->setTime(23, 59, 59) : $date->setTime(0, 0, 0);
}

Для простоты понимания перепишем этот код на чистом SQL для интервала, скажем, с 1 по 10 ноября:

SELECT *
FROM audit_logs
WHERE logged_at >= '2025-11-01'
AND loggged_at <= '2025-11-10 23:59:59'

Когда я вижу эти 23:59:59, у меня сразу возникает неприятное ощущение от того, насколько это неэстетичное решение. Некоторые не останавливаются на секундах, а добавляют еще и микросекунды, и время превращается в '2025-11-10 23:59:59.999999'. Условие становится более корректным, но еще менее эстетичным.

Правильный способ состоит в том, чтобы не приписывать финальной дате последний доступный момент времени, а заменить условие «по 10-е число» эквивалентным условием «до 11-го числа»:

SELECT *
FROM audit_logs
WHERE logged_at >= '2025-11-01'
AND loggged_at < '2025-11-11'

Стоит запомнить этот шаблон использования полуоткрытых интервалов, когда нижняя граница диапазона включается в условие, а верхняя исключается. Он пригождается чаще, чем может показаться на первый взгляд.

Поделиться

«Вежливый» ChatGPT Ctrl

Читайте также

Эксперименты и использование ChatGPT
По-немногу экспериментирую с ChatGPT. Решил поделиться результатами наблюдений и идеями по использованию.
2023

Комментарии

#1. 7 ноября 2025 года, 12:51. petr пишет:
Зависит от языка и предпочтений. Где-то удобно написать так:

```
created_at.between(some_date.start_of_day(), some_date.end_of_day())
```

Оставьте свой комментарий


Формулы на латехе: $$f(x) = x^2-\sqrt{x}$$ превратится в $$f(x) = x^2-\sqrt{x}$$.
Выделение текста: [i]курсивом[/i] или [b]жирным[/b].
Цитату оформляйте так: [q = имя автора]цитата[/q] или [q]еще цитата[/q].
Других команд или HTML-тегов здесь нет.

Записи