Como criar datas aleatórias no MySQL

Com o uso das funções CONCAT(), FLOOR() e RAND(), é possível criar datas aleatórias no MySQL. Como o comando UPDATE, você pode efetuar a substituição de todas as datas de uma tabela por outras completamente aleatórias.
Qualquer que seja o seu motivo, imagino que você queira ter controle sobre as datas geradas aleatoriamente — que os anos, os meses e, possivelmente, os dias estejam dentro de faixas especificas.
No exemplo, abaixo, vamos criar datas em que apenas os meses serão aleatórios, variando de 1 a 12:

SELECT CONCAT('2015-',FLOOR(1+RAND()*12),'-02');
+-----------------------------------------+
| CONCAT('2015-',FLOOR(1+RAND()*12),'-02') |
+-----------------------------------------+
|  2015-2-02                              |
+-----------------------------------------+

Agora, vamos usar o ano e o dia atuais, com a função CURDATE():

SELECT CONCAT(YEAR(CURDATE()),'-',FLOOR(1+RAND()*12),'-',DAY(CURDATE()));
+------------------------------------------------------------------+
| CONCAT(YEAR(CURDATE()),'-',FLOOR(1+RAND()*12),'-',DAY(CURDATE())) |
+------------------------------------------------------------------+
| 2015-5-15                                                        |
+------------------------------------------------------------------+

Altere as queries para que se encaixem às suas necessidades.
Embora sejam válidas, as datas dos exemplos acima, não se encaixam nos padrões ISO 8601 e não poderão ser corretamente gravadas dentro de campos date ou datetime.
Para tanto, as datas teriam que ser 2015-02-02 e 2015-05-15 — ou seja, 4 dígitos na seção do ano, 2 dígitos na seção do mês e 2 dígitos na seção do dia.
Para garantir que os números dos meses e dos dias satisfaçam estas condições, seguem os exemplos anteriores, reformulados, com a inclusão da função LPAD():

SELECT CONCAT('2015-',LPAD(FLOOR(1+RAND()*12),2,'0'),'-02');
+------------------------------------------------------+
| CONCAT('2015-',LPAD(FLOOR(1+RAND()*12),2,'0'),'-02') |
+------------------------------------------------------+
| 2015-02-02                                           |
+------------------------------------------------------+

… e no segundo exemplo:

SELECT CONCAT(YEAR(CURDATE()),'-',LPAD(FLOOR(1+RAND()*12),2,'0'),'-',DAY(CURDATE()));
+-------------------------------------------------------------------------------+
| CONCAT(YEAR(CURDATE()),'-',LPAD(FLOOR(1+RAND()*12),2,'0'),'-',DAY(CURDATE())) |
+-------------------------------------------------------------------------------+
| 2015-10-16                                                                    |
+-------------------------------------------------------------------------------+

Leia mais sobre o uso das funções CONCAT() e LPAD() em Como converter strings de data para padrão ISO 8601.

Como substituir as datas de uma coluna da tabela por novas datas aleatórias

Para mudar todas as datas de uma coluna, dentro da tabela, use o UPDATE:

UPDATE clientesEstaduais SET DataCadastro = CONCAT('2015-',LPAD(FLOOR(1+RAND()*12),2,'0'),'-02');

Substitua, no exemplo acima, ‘clientesEstaduais’ pelo nome da sua tabela e ‘DataCadastro’ pelo nome da coluna cujas informações serão alteradas.
Se você quiser, pode obter a tabela ‘clientesEstaduais’ aqui.
No próximo exemplo, todos os componentes da data serão atualizados aleatoriamente (ano, mês e dia) — obedecendo os seguintes parâmetros:

  • Os anos têm que estar entre 2014 e 2016
  • Os valores referentes aos meses têm que estar comprendidos entre 1 e 12
  • Os valores dos dias, para ter alguma segurança em relação a meses com quantidade de dias diferentes, ficam compreendidos entre 1 e 27 — o que garante que nenhum fique com data inválida (por exemplo: 2016-02-31)

Veja o código:

UPDATE clientesEstaduais SET DataCadastro = CONCAT(FLOOR(2014+RAND()*3),'-', LPAD(FLOOR(1+RAND()*12),2,'0'),'-', LPAD(FLOOR(1+RAND()*27),2,'0'));

Desta vez, a gama de datas contidas na minha tabela, ficou bem mais variada:

SELECT DataCadastro FROM clientesEstaduais LIMIT 10;
+--------------+
| DataCadastro |
+--------------+
| 2016-11-07   |
| 2015-01-14   |
| 2015-09-04   |
| 2015-02-09   |
| 2014-04-07   |
| 2015-02-16   |
| 2015-05-16   |
| 2016-11-11   |
| 2014-10-07   |
| 2016-10-08   |
+--------------+

Como manipular valores de data e hora como números no MySQL

Transformar strings contendo valores temporais (de data e/ou hora) pode ser útil quando se deseja realizar operações aritméticas, envolvendo-os. Os valores podem ser convertidos de volta para data e/ou hora, com relativa facilidade.
O processo consiste, basicamente em adicionar o valor zero ou usar o valor temporal em um contexto numérico — o MySQL irá entender que aquele valor é um número.
Veja um exemplo:

SELECT CURRENT_DATE() AS Hoje, CURRENT_DATE()+0 AS "Hoje, como núm.";
+------------+------------------+
| Hoje       | Hoje, como núm.  |
+------------+------------------+
| 2015-07-14 |         20150714 |
+------------+------------------+

CURRENT_DATE() é a função responsável por retornar a data atual. Como você pode ver, no exemplo acima, ao adicionar 0 (zero), o valor passou de data para número.
Na condição de valor numérico, é possível realizar todas as operações aritméticas e, em seguida, voltar (nem sempre…) a valor temporal.
Veja outro exemplo:

SELECT DATE(DataCadastroCliente) AS Cadastro, DATE(DataCadastroCliente)+0 AS "Número", YEAR(DataCadastroCliente)+1 AS "Ano +1" FROM CadastroClientes LIMIT 10;
+------------+----------+--------+
| Cadastro   | Número   | Ano +1 |
+------------+----------+--------+
| 2016-03-29 | 20160329 |   2017 |
| 2015-06-20 | 20150620 |   2016 |
| 2013-03-29 | 20130329 |   2014 |
| 2015-11-29 | 20151129 |   2016 |
| 2016-06-11 | 20160611 |   2017 |
| 2014-06-14 | 20140614 |   2015 |
| 2015-08-31 | 20150831 |   2016 |
| 2012-08-28 | 20120828 |   2013 |
| 2013-05-29 | 20130529 |   2014 |
| 2013-06-03 | 20130603 |   2014 |
+------------+----------+--------+

mysql-convert-datetime-to-number
Fique atento.
Ao adicionar 0 (ou qualquer outro valor numérico) a um valor temporal, este deixa de ter valor temporal e passa a ser uma simples string numérica.
Essencialmente, você deve esperar, como resultado, uma string sem os delimitadores de data.
Mas apenas o primeiro componente da data ou da hora será interpretado como numérico, durante a conversão. Veja por si só:

SELECT '2016-01-01'+0, '2016-01-01 15:45:25'+0, '15:45:25'+0;
+----------------+-------------------------+--------------+
| '2016-01-01'+0 | '2016-01-01 15:45:25'+0 | '15:45:25'+0 |
+----------------+-------------------------+--------------+
|           2016 |                    2016 |           15 |
+----------------+-------------------------+--------------+

Para resolver isto, use as funções SEC_TO_TIME() e TIME_TO_SEC().

Como determinar quando um ano é bissexto no MySQL

Veja alguns meios eficazes de determinar se um ano é bissexto ou não no MySQL.
Sabemos que alguns cálculos envolvendo anos ou dias dos anos pode se tornar complicados em função de alguns anos terem um dia a mais.
Neste texto, vou mostrar como determinar se um ano é bissexto ou não.
O fato de que um mês pode ter um dia a mais em alguns anos, já pode servir de complicador para realizar algumas contas.
Para determinar se uma determinada data cai ou não em um ano bissexto você deva obter o componente de ano, com a função YEAR() e testar este resultado.
Há um regra geral de que os anos bissextos são todos divisíveis por 4. Isto pode ser testado com o uso do operador de módulo, assim:

SELECT YEAR(DataNascimentoCliente) AS "Anos", YEAR(DataNascimentoCliente)% 4=0 AS "Anos normais/bissextos" FROM CadastroClientes LIMIT 10;
+------+------------------------+
| Anos | Anos normais/bissextos |
+------+------------------------+
| 1984 |                      1 |
| 1984 |                      1 |
| 1981 |                      0 |
| 1983 |                      0 |
| 1969 |                      0 |
| 1979 |                      0 |
| 1976 |                      1 |
| 1975 |                      0 |
| 1983 |                      0 |
| 1978 |                      0 |
+------+------------------------+

Os anos ‘1’ são bissextos.
Esta abordagem não é perfeita, contudo. O ano 1900 é também divisível por 4 e… não é bissexto.
Portanto, para que um ano seja qualificado como bissexto, precisa satisfazer a estas 2 condições:

  • o ano tem que ser divisível por 4
  • não pode ser divisível por 100, a menos que seja também divisível por 400

Vamos a uma query que faça estas filtragens:

SELECT YEAR(DataNascimentoCliente) AS ANO, (YEAR(DataNascimentoCliente) %4 = 0) AND (YEAR(DataNascimentoCliente) % 100 != 0) OR (YEAR(DataNascimentoCliente) % 400 = 0) AS "Teste completo" FROM CadastroClientes LIMIT 10;
+------+----------------+
| ANO  | Teste completo |
+------+----------------+
| 1984 |              1 |
| 1984 |              1 |
| 1981 |              0 |
| 1983 |              0 |
| 1969 |              0 |
| 1979 |              0 |
| 1976 |              1 |
| 1975 |              0 |
| 1983 |              0 |
| 1978 |              0 |
+------+----------------+

Pronto. Este método é mais seguro que o anterior — mas pode ser desnecessário se o seu banco de dados não inclui a possibilidade de lidar com o ano 1900…

Como determinar o primeiro e o último dia do mês no MySQL

Dada uma data, você deseja determinar qual o primeiro dia da semana naquele mês ou qual o último dia do mês (28, 29, 30 ou 31).
Veja algumas abordagens para este problema — e use a que melhor lhe convier.
Se você conhece outra solução, dentro do MySQL, sinta-se à vontade para expôr nos comentários.
Logo MySQL - The Dolphin.
Abaixo, veja como resolver o problema usando uma combinação das funções DATE_SUB() e DAYOFMONTH(). Neste caso

SELECT '2016-07-19', DATE_SUB('2016-07-19', INTERVAL DAYOFMONTH('2016-07-19')-1 DAY) AS 'Primeiro dia do mês';
+------------+----------------------+
| 2016-07-19 | Primeiro dia do mês  |
+------------+----------------------+
| 2016-07-19 | 2016-07-01           |
+------------+----------------------+

Obviamente, o primeiro dia de um mês é sempre o dia 01.
Faz mais sentido determinar em que dia da semana cai o primeiro dia do mês. isto pode ser feito com o acréscimo da função DAYOFWEEK():

SELECT '2016-07-19', DAYOFWEEK(DATE_SUB('2016-07-19', INTERVAL DAYOFMONTH('2016-07-19')-1 DAY)) AS 'Primeiro dia do mês';
+------------+----------------------+
| 2016-07-19 | Primeiro dia do mês  |
+------------+----------------------+
| 2016-07-19 |                    6 |
+------------+----------------------+

Sabendo que Domingo é o dia 1, chega-se à conclusão de que o dia 6 é Sexta-feira.
Com a função DAYNAME() fica mais fácil obter esta informação, veja:

SELECT '2016-07-19', DAYNAME(DATE_SUB('2016-07-19', INTERVAL DAYOFMONTH('2016-07-19')-1 DAY)) AS 'Primeiro dia do mês';
+------------+----------------------+
| 2016-07-19 | Primeiro dia do mês  |
+------------+----------------------+
| 2016-07-19 | sexta                |
+------------+----------------------+

A abordagem, que vimos é um tanto complexa e serve apenas para demonstrar algumas funções de manipulação das informações de data do MySQL.
Veja, a seguir, algumas maneiras mais rápidas de obter suas respostas.

Como estabelecer o último dia do mês no MySQL

A função LAST_DAY() pode dar este resultado num piscar de olhos. Sua sintaxe é simples e pede apenas uma data:

SELECT LAST_DAY('2016-02-15') AS 'Últ. dia do mês';
+-------------------+
| Últ. dia do mês   |
+-------------------+
| 2016-02-29        |
+-------------------+

Esta é uma maneira fácil de saber quantos dias o mẽs de Fevereiro terá em um determinado ano.
Você pode aninhar funções e descobrir um pouco mais — por exemplo, em qual dia da semana, cai esta data:

SELECT DAYNAME(LAST_DAY('2016-02-15')) AS 'Últ. dia do mês';
+-------------------+
| Últ. dia do mês   |
+-------------------+
| segunda           |
+-------------------+

A função LAST_DAY() também pode ser usada para determinar a extensão do mês ou o que falta para concluí-lo a partir de uma determinada data.

Como usar a função LAST_DAY para determinar qual o primeiro dia do mês

Ainda não existe a função FIRST_DAY(), no MySQL. E, de certa forma, ela é desnecessária.
O que varia, de mês para mês, é o último dia — que pode ser 28, 29, 30 ou 31.
O primeiro dia de cada mês, é sempre o dia 01 — mas o dia da semana varia, conforme demonstramos no começo deste artigo.
Tecnicamente, o primeiro dia de cada mês é sempre o dia posterior à data retornada por LAST_DAY(), referente ao mês anterior. Por exemplo: LAST_DAY('uma data do mẽs de Março')+1 = primeiro dia do mẽs de Abril.
Veja esta outra solução para determinar o primeiro dia de um determinado mẽs:

SELECT CURDATE( ) AS 'Hoje', ADDDATE(LAST_DAY(SUBDATE(CURDATE(), INTERVAL 1 MONTH)), 1) AS 'Primeiro dia do mês';
+------------+----------------------+
| Hoje       | Primeiro dia do mês  |
+------------+----------------------+
| 2015-07-12 | 2015-07-01           |
+------------+----------------------+

Veja o que fizemos no exemplo acima:

  • subtraímos um mês ao resultados de CURDATE() Para obter o mesmo dia do mês anterior
  • A partir daí usamos a função LAST_DAY() para estabelecer o último dia daquele mês
  • Finalmente, a função ADDDATE() é usada para adicionar um dia ao resultado — o que nos dá o primeiro dia do mẽs subsequente (que é o mês atual)

Este método pode ser usado, sem perigo de obter resultados indesejados, quando datas entre Dezembro e Janeiro de outro ano, estiverem envolvidas na conta.
Para determinar a que dia da semana pertence a data obtida, aninhe a query dentro da função DAYNAME():

SELECT CURDATE( ) AS 'Hoje', DAYNAME(ADDDATE(LAST_DAY(SUBDATE(CURDATE(), INTERVAL 1 MONTH)), 1)) AS 'Primeiro dia do mês';
+------------+----------------------+
| Hoje       | Primeiro dia do mês  |
+------------+----------------------+
| 2015-07-12 | quarta               |
+------------+----------------------+

Como configurar o fuso horário do MySQL por nomes.

Se você pretende usar time zones ou fusos horários no MySQL, pelo nome, é bom ter certeza de que as tabelas contendo estas informações estão atualizadas e povoadas — prontas para uso.
Se você não tem certeza de que os nomes das zonas de fusos horários estão disponíveis — tanto para a configuração do servidor, quanto para uso dos clientes (que pretendem ajustar seus próprios fusos), — faça o seguinte teste, dentro do console do cliente MySQL:

SELECT COUNT(*) FROM mysql.time_zone_name;
+----------+
| COUNT(*) |
+----------+
|        0 |
+----------+

No exemplo, acima, a função COUNT() retornou o valor 0 — o que indica a impossibilidade de se referenciar às zonas de fuso horário pelos seus nomes.
O segundo caso, do exemplo abaixo, fica evidenciado que a tabela de nomes de zonas de fusos horários está presente:

SELECT COUNT(*) FROM mysql.time_zone_name;
+----------+
| COUNT(*) |
+----------+
|     1790 |
+----------+

Neste texto, vamos nos debruçar sobre uma solução para o primeiro caso.
Fusos horários no MySQL

O processo de instalação do MySQL cria as tabelas de fusos horários (time zone tables), mas não carrega os valores para dentro delas — ou seja, não as povoa. Você precisa fazer isto manualmente, caso queira se referir aos fusos horários por nome.


  • Sistemas operacionais, como Linux, FreeBSD, Solaris e OSX têm sua própria base de dados zoneinfo, que consiste em um conjunto de arquivos descritores dos fusos horários. Neste caso, você pode usar o utilitário mysql_tzinfo_to_sql para preencher as tabelas de zonas de fusos.
    Para usuários Windows, é possível fazer o download do pacote de banco de dados de zonas de fusos horários para MySQL em http://dev.mysql.com/downloads/timezones.html.
    Neste texto, uso como exemplo, o sistema operacional GNU/Linux Ubuntu 14.04 LTS — portanto, o procedimento deve ser o mesmo para qualquer sistema baseado no Debian.

No Ubuntu 14.04 os arquivos zoneinfo, pode ser encontrados em /usr/share/zoneinfo/:

ls /usr/share/zoneinfo/
Africa      Chile    Factory    Iceland      MET       posix       UCT
America     CST6CDT  GB         Indian       Mexico    posixrules  Universal
Antarctica  Cuba     GB-Eire    Iran         MST       PRC         US
Arctic      EET      GMT        iso3166.tab  MST7MDT   PST8PDT     UTC
Asia        Egypt    GMT0       Israel       Navajo    right       WET
Atlantic    Eire     GMT-0      Jamaica      NZ        ROC         W-SU
Australia   EST      GMT+0      Japan        NZ-CHAT   ROK         zone.tab
Brazil      EST5EDT  Greenwich  Kwajalein    Pacific   Singapore   Zulu
Canada      Etc      Hongkong   Libya        Poland    SystemV
CET         Europe   HST        localtime    Portugal  Turkey

Veja, a seguir, como trabalhar com estes arquivos.

Como povoar o banco de dados usando o mysql_tzinfo_to_sql

Este processo é muito simples e rápido. Use a seguinte linha de comando:

mysql_tzinfo_to_sql /usr/share/zoneinfo/ | mysql -u root -p mysql

O que o comando acima faz é “jogar” todos os arquivos do diretório /usr/share/zoneinfo/ (pode variar de acordo com o seu sistema), bem como de seus subdiretórios, dentro do banco de dados mysql, nas tabelas apropriadas.
Uma vez feito este procedimento, já é possível se referir aos fusos horários, dentro do MySQL, por seus nomes.

A documentação oficial do MySQL (link ao final do tópico), adverte para não baixar e usar pacotes, caso seu sistema operacional já tenha um banco de dados zoneinfo. Use o aplicativo utilitário mysql_tzinfo_to_sql.

Após a execução do comando mysql_tzinfo_to_sql, é recomendável reiniciar o servidor de banco de dados, para evitar que ele use dados de fusos horários contidos na cache:

sudo service mysql restart

Como ajustar o fuso horário no MySQL

Veja como é possível ajustar o fuso, referindo-se ao nome:

SELECT * FROM mysql.time_zone_name WHERE Name LIKE '%Fortaleza%';
_
+-------------------------+--------------+
| Name                    | Time_zone_id |
+-------------------------+--------------+
| America/Fortaleza       |          113 |
| posix/America/Fortaleza |          710 |
| right/America/Fortaleza |         1307 |
+-------------------------+--------------+
3 rows in set (0.00 sec)
SET time_zone='America/Fortaleza';
Query OK, 0 rows affected (0.00 sec)

SELECT @@time_zone;
_
+-------------------+
| @@time_zone       |
+-------------------+
| America/Fortaleza |
+-------------------+
1 row in set (0.00 sec)

No artigo Como ajustar o fuso horário ou a timezone no MySQL, você pode encontrar uma relação completa de fusos horários do Brasil e de outros países de língua portuguesa — além disto, há outros exemplos de uso e ajuste dos fusos horários no MySQL.

Referências: https://dev.mysql.com/doc/refman/5.7/en/time-zone-support.html#time-zone-installation.