В этой статье рассмотрим несколько вариантов получения случайной даты в MySQL. Для чего это нужно? Ну к примеру для генерации фикстур и прочих тестовых данных, чтобы были похожи на реальные.
Самый простой вариант – совершенно случайная дата:
mysql> SELECT FROM_UNIXTIME(RAND() * 2147483647) AS `rand`; +---------------------+ | rand | +---------------------+ | 1998-04-01 21:42:48 | +---------------------+ 1 ROW IN SET (0.00 sec) |
Попробуем ещё раз?
mysql> SELECT FROM_UNIXTIME(RAND() * 2147483647) AS `rand`; +---------------------+ | rand | +---------------------+ | 2028-03-21 22:44:43 | +---------------------+ 1 ROW IN SET (0.00 sec) |
Окей, зачем умножать на 2147483647? (ещё не догадались?! 🙂 Ну тут всё просто, как 2 копейки: 2147483647 это самый большой SIGNED INT32 и по совместительству писарчук самый последний распоследний таймштамп. Проверяется это так (ежели не верите):
Так ещё работает:
mysql> SELECT FROM_UNIXTIME(2147483647) AS `rand`; +---------------------+ | rand | +---------------------+ | 2038-01-18 19:14:07 | +---------------------+ 1 ROW IN SET (0.00 sec) |
А если добавим хоть секундочку (2147483648) – уже работать не будет:
mysql> SELECT FROM_UNIXTIME(2147483648) AS `rand`; +------+ | rand | +------+ | NULL | +------+ 1 ROW IN SET (0.01 sec) |
Таким образом, функция RAND()
даёт нам случайное значение в диапазоне от 0 до 1 и умножая его на максимально возможный таймштамп мы получим случайную дату в диапазоне от 1969 до 2038 гг. Но что же нам делать, если требуется дата в некотором строго определённом периоде?
Случайная дата 2011го года
Получается вот так:
mysql> SELECT FROM_UNIXTIME(RAND() * (1325275200 - 1293825600) + 1293825600) AS `the_date`; +---------------------+ | the_date | +---------------------+ | 2011-04-27 05:01:04 | +---------------------+ 1 ROW IN SET (0.00 sec) |
Так круто, что хочется попробовать ещё раз 😉
mysql> SELECT FROM_UNIXTIME(RAND() * (1325275200 - 1293825600) + 1293825600) AS `the_date`; +---------------------+ | the_date | +---------------------+ | 2011-08-15 12:54:51 | +---------------------+ 1 ROW IN SET (0.01 sec) |
А чо энто было то?
Когда нам нужно зафиксировать диапазон, между start
и end
датами, и мы имеем случайное значение от 0 до 1 – требуется вычесть из конечного таймштампа начальный end - start
, что даст искомый интервал в секундах и “двинуть” интервал в начало периода. Т.о. наша супер-формула выглядит вот так:
(end - start) * RAND + start
Ну и для того чтобы высвободить вам побольше времени для Angry Birds (или чего-то подобного), а также не морщить лоб, пытаясь в уме переводить DATETIME в TIMESTAMP – мы воспользуемся функцией UNIX_TIMESTAMP:
mysql> SELECT -> UNIX_TIMESTAMP('2011-01-01') AS START, -> UNIX_TIMESTAMP('2011-12-31') AS END; +------------+------------+ | START | END | +------------+------------+ | 1293825600 | 1325275200 | +------------+------------+ 1 ROW IN SET (0.00 sec) |
Оригинал для перевода взял тут: http://www.phpied.com/random-mysql-date/
Мм, классно. А я строку конкатил из рандомных величин.
MySQL он такой )) нельзя знать его слишком хорошо
От себя добавлю, что пользоваться функцией RAND в условиях репликации беззопасно при ROW-based репликации.
В данном случае RAND это просто способ получить случайную дату, к примеру для того чтобы заполнить тестовыми данными таблицу. Репликация тут вроде как бы и не нужна… Или нужна?