Database
 sql >> Base de Dados >  >> RDS >> Database

Qual é o problema do ano 2038?


O problema do ano 2038 (também conhecido como bug Y2K38) refere-se a um problema que alguns sistemas de computador podem encontrar ao lidar com tempos passados ​​2038-01-19 03:14:07.

Muitos sistemas de computador, como sistemas baseados em Unix e Unix, não calculam o tempo usando o calendário gregoriano. Eles calculam o tempo como o número de segundos desde 1º de janeiro de 1970. Portanto, nesses sistemas, o tempo é representado como um número grande (ou seja, o número de segundos passados ​​desde 1970-01-01 00:00:00). Normalmente, isso é chamado de hora Epoch, hora Unix, hora Unix Epoch ou hora POSIX. Enquanto escrevo isso, o tempo Unix é 1560913841. E enquanto escrevo esta próxima linha, o tempo Unix aumentou para 1560913879.



O problema de 2038 é causado pelo fato de muitos sistemas armazenarem esse número como um inteiro binário de 32 bits assinado. O intervalo de um inteiro de 32 bits com sinal é -2.147.483.648 a 2.147.483.647. Isso significa que o último horário Epoch que pode ser representado é 2147483647. Isso ocorrerá às 03:14:07 de terça-feira, 19 de janeiro de 2038.

Depois disso, o resultado dependerá em grande parte do sistema. Em muitos sistemas, ocorrerá um estouro de número inteiro, e qualquer momento posterior será agrupado e armazenado internamente como um número negativo. O resultado é que um segundo depois, a hora será interpretada como sendo 13 de dezembro de 1901 em vez de 19 de janeiro de 2038.

No entanto, você também pode acabar com resultados variados, dependendo do aplicativo em uso. Mesmo que seu sistema operacional não tenha problemas, seu próprio código ainda pode ter problemas. Por exemplo, se você escreveu um código personalizado para retornar a hora do Unix e armazená-lo em um inteiro de 4 bytes assinado, você terá problemas. Nesses casos, reescrever o código para usar um inteiro de 8 bytes pode ser tudo o que você precisa fazer.

Visto que este site é sobre bancos de dados, aqui estão alguns exemplos de banco de dados.

Exemplo 1 – MySQL


No MySQL, o TIMESTAMP tipo de dados suporta datas/horas de '1970-01-01 00:00:01.000000' UTC a '2038-01-19 03:14:07.999999'. Portanto, você poderia dizer que qualquer banco de dados usando esse tipo de dados tem um bug Y2K38.

MySQL também tem uma função embutida chamada UNIX_TIMESTAMP() que, como você pode esperar, retorna o timestamp Unix.

O UNIX_TIMESTAMP() A função aceita um argumento opcional que permite especificar uma data a ser usada para a hora Unix (ou seja, o número de segundos de '1970-01-01 00:00:00' UTC até a hora que você especificar). O intervalo válido de valores de argumento é o mesmo do TIMESTAMP tipo de dados, que é '1970-01-01 00:00:01.000000' UTC a '2038-01-19 03:14:07.999999' UTC. Se você passar uma data fora do intervalo para esta função, ela retornará 0 .

Aqui está o que acontece se você tentar usar esta função para retornar a hora do Unix de uma data anterior a '2038-01-19 03:14:07.999999':
SELECT UNIX_TIMESTAMP('2038-01-20') Result;

Resultado:
+--------+
| Result |
+--------+
|      0 |
+--------+

Obtemos 0 porque o argumento de data está fora do intervalo suportado.

Um relatório de bug relacionado foi levantado para a equipe do MySQL em 2005 (embora alguns dos detalhes pareçam ser diferentes), e até o momento em que este artigo foi escrito, ainda não foi abordado.

Um problema semelhante também foi levantado para resolver as limitações com o TIMESTAMP tipo de dados, que também ainda não foi abordado.

Exemplo 2 – SQL Server


Atualmente, o SQL Server não possui um equivalente do UNIX_TIMESTAMP do MySQL função. Portanto, se você precisar retornar o horário da Epoch, precisará fazer algo assim:
SELECT DATEDIFF(SECOND,'1970-01-01', GETUTCDATE());

Isso é bom para datas anteriores ao problema de 2038. Após essa data, você terá problemas, porque o DATEDIFF() função retorna o resultado como um int tipo de dados. O int tipo de dados tem um intervalo de -2^31 (-2.147.483.648) a 2^31-1 (2.147.483.647).

Aqui está o que acontece se eu tentar retornar o horário Epoch depois de '2038-01-19 03:14:07':
SELECT DATEDIFF(SECOND,'1970-01-01', '2038-01-19 03:14:08') AS 'Result';

Resultado:
The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart.

Felizmente, há também um DATEDIFF_BIG() função, que faz exatamente a mesma coisa, exceto que retorna o resultado como um bigint tipo de dados.

Assim, podemos reescrever o exemplo anterior para o seguinte para superar esse problema:
SELECT DATEDIFF_BIG(SECOND,'1970-01-01 00:00:00', '2038-01-19 03:14:08') AS 'Result';

Resultado:
+------------+
| Result     |
|------------|
| 2147483648 |
+------------+

O grande tipo de dados usa 8 bytes (em oposição a 4 bytes para um int ), então você precisará decidir se quer ou não mudar para DATEDIFF_BIG() agora ou depois. Se o seu aplicativo lida com datas futuras, pode ser prudente fazê-lo mais cedo ou mais tarde.