Работаем с датами в MySQL

Unix-время и TIMESTAMP, prepared statements mysqli, разница дат и группировка звонков по календарным дням и месяцам. Таблица спецификаторов DATE_FORMAT.

Вычитание даты от текущей

Разницу между текущей датой и date_start таблицы tbl_sites в календарных днях можно получить так:

SELECT TO_DAYS(CURDATE()) - TO_DAYS(date_start) AS days_passed
FROM tbl_sites;

Более короткая запись: DATEDIFF(CURDATE(), date_start). Обе операции сравнивают даты, не количество полных интервалов по 24 часа.

Добавление текущей даты и времени при вставке записи

Для Unix-времени в секундах используйте поле BIGINT; тип TIME хранит время суток или интервал, поэтому не подходит для time(). Подключение $mysqli — из примера PHP и MySQL.

$first = 'string1';
$second = 'string2';
$third = 'string3';
$created = time();
$stmt = $mysqli->prepare(
    'INSERT INTO my_table (pole1, pole2, pole3, time) VALUES (?, ?, ?, ?)'
);
$stmt->bind_param('sssi', $first, $second, $third, $created);
$stmt->execute();
$stmt->close();

Для поля TIMESTAMP текущая дата и время задаются CURRENT_TIMESTAMP:

$stmt = $mysqli->prepare(
    'INSERT INTO my_table (pole1, pole2, pole3, time) VALUES (?, ?, ?, CURRENT_TIMESTAMP)'
);
$stmt->bind_param('sss', $first, $second, $third);
$stmt->execute();
$stmt->close();

TIMESTAMP преобразуется между UTC и часовым поясом сессии MySQL. Для однозначного преобразования в Unix-время задайте сессии UTC, а PHP укажите тот же пояс явно. Строка «2013-09-17 15:00:00» из старого примера сама по себе не содержит часового пояса.

$mysqli->query("SET time_zone = '+00:00'");
$id = 1;
$stmt = $mysqli->prepare('SELECT time FROM my_table WHERE id = ? LIMIT 1');
$stmt->bind_param('i', $id);
$stmt->execute();
$stmt->bind_result($myTime);
if ($stmt->fetch()) {
    $created = new DateTimeImmutable($myTime, new DateTimeZone('UTC'));
    echo $created->getTimestamp();
    $timeOffset = time() - $created->getTimestamp();
}
$stmt->close();

Для strtotime() также учитывайте часовой пояс и проверяйте результат на false. Unix-время — число: $my_time() было бы попыткой вызвать функцию.

Группировка записей по дням и месяцам

Если одна запись tbl_calls соответствует звонку, выборка считает звонки за 30 календарных дней, включая сегодняшний день:

SELECT DATE(date_time) AS call_day, COUNT(*) AS calls
FROM tbl_calls
WHERE date_time >= CURDATE() - INTERVAL 29 DAY
  AND date_time < CURDATE() + INTERVAL 1 DAY
GROUP BY DATE(date_time)
ORDER BY call_day DESC;

LIMIT 30 ограничивает число строк результата, но не фильтрует последние 30 дней. Дни без звонков здесь отсутствуют; для непрерывного ряда понадобится календарная таблица.

Для группировки по месяцам и хронологической сортировки:

SELECT DATE_FORMAT(date_time, '%Y-%m') AS call_month, COUNT(*) AS calls
FROM tbl_calls
GROUP BY DATE_FORMAT(date_time, '%Y-%m')
ORDER BY call_month;

Для подписи можно использовать %m.%Y или %d.%m.%Y. Неагрегатные выражения включены в GROUP BY, поэтому запросы совместимы с ONLY_FULL_GROUP_BY.

Формат дат для функции DATE_FORMAT()

Названия месяцев и дней зависят от lc_time_names. Нулевые месяцы и дни в таблице относятся к неполным датам, допустимость которых зависит от SQL mode.

%a Сокращенное название дня недели на латинице (Sun to Sat)
%b Сокращенное название месяца на латинице (Jan to Dec)
%c Месяц числом (0 to 12)
%D День месяца в виде числового значения, за которым следует суффикс на латинице (1st, 2nd, 3rd, ...)
%d День месяца в виде числового значения (00 to 31)
%e День месяца в виде числового значения (0 to 31)
%f Микросекунды (000000 to 999999)
%H Часы (00 to 23)
%h Час (01 to 12)
%I Час (01 to 12)
%i Минуты (00 to 59)
%j Нумерация дня в году (001 to 366)
%k Час (0 to 23)
%l Час (1 to 12)
%M Полное название месяца на латинице (January - December)
%m Месяц числом (от 00 до 12)
%p AM или PM
%r Время в 12-часовом формате AM или PM (hh:mm:ss AM/PM)
%S Секунды (00 to 59)
%s Секунды (00 to 59)
%T Время в 24-часовом формате (hh:mm:ss)
%U Неделя, где воскресенье-первый день недели (с 00 до 53)
%u Неделя, где понедельник-первый день недели (с 00 до 53)
%V Неделя, где воскресенье-первый день недели (с 01 по 53). Используется с %X
%v Неделя, где понедельник-первый день недели (с 01 по 53). Используется с %x
%W Название дня недели полностью на латинице (Sunday - Saturday)
%w День недели, где воскресенье=0 и суббота=6
%X Год для недели, где воскресенье является первым днем недели. Используется с %V
%x Год для недели, где понедельник является первым днем недели. Используется с %v
%Y Год как числовое, 4-значное значение
%y Год как числовое, 2-значное значение

Проверенные источники

dev.mysql.com, www.php.net. Проверено 10 октября 2026 года.

Все материалы раздела «Программирование»Каталог инструментов