A
TIME
os valores sempre foram armazenados em 3 bytes no MySQL. Mas o formato mudou na versão 5.6 .4
. Eu suspeito que esta não foi a primeira vez que mudou. Mas a outra mudança, se houve, aconteceu há muito tempo e não há evidência pública disso. O histórico do código-fonte do MySQL no GitHub começa com a versão 5.5 (o commit mais antigo é de maio de 2008), mas a mudança que estou procurando aconteceu por volta de 2001-2002 (o MySQL 4 foi lançado em 2003) O formato atual, conforme descrito na documentação, usa 6 bits por segundos (valores possíveis:
0
para 63
), 6 bits para minutos, 10 bits para horas (valores possíveis:0
para 1023
), 1 bit para sinal (somar os valores negativos dos intervalos já mencionados) e 1 bit não utilizado e rotulado como "reservado para futuras extensões". É otimizado para trabalhar com componentes de tempo (horas, minutos, segundos) e não desperdiça muito espaço. Usando este formato é possível armazenar valores entre
-1023:59:59
e +1023:59:59
. No entanto, o MySQL limita o número de horas para 838
, provavelmente para compatibilidade com aplicativos que foram escritos há algum tempo, quando acho que esse era o limite. Até a versão 5.6.4, o
TIME
os valores também foram armazenados em 3 bytes e os componentes foram empacotados como days * 24 * 3600 + hours * 3600 + minutes * 60 + seconds
. Esse formato foi otimizado para trabalhar com timestamps (porque era, na verdade, um timestamp). Usando este formato, seria possível armazenar valores no intervalo de cerca de -2330
para +2330
horas. Apesar de ter esse grande intervalo de valores disponível, o MySQL ainda estava limitando os valores a -838
para +838
horas. Houve bug #11655 no MySQL 4. Foi possível retornar
TIME
valores fora do -838..+838
intervalo usando SELECT
aninhado declarações. Não era um recurso, mas um bug e foi corrigido. A única razão para limitar os valores a esse intervalo e alterar ativamente qualquer parte do código que produz
TIME
valores fora dele era compatibilidade com versões anteriores. Suspeito que o MySQL 3 tenha usado um formato diferente que, devido à forma como os dados foram compactados, limitou os valores válidos ao intervalo
-838..+838
horas. Ao olhar para o atual código-fonte do MySQL Encontrei esta fórmula interessante:
#define TIME_MAX_VALUE (TIME_MAX_HOUR*10000 + TIME_MAX_MINUTE*100 + TIME_MAX_SECOND)
Vamos ignorar por enquanto o
MAX
parte dos nomes usados acima e vamos lembrar apenas que TIME_MAX_MINUTE
e TIME_MAX_SECOND
são números entre 00
e 59
. A fórmula apenas concatena as horas, minutos e segundos em um único número inteiro. Por exemplo, o valor 170:29:45
torna-se 1702945
. Esta fórmula levanta a seguinte questão:dado que o
TIME
os valores são armazenados em 3 bytes com sinal, qual é o valor máximo positivo que pode ser representado desta forma? O valor que estamos procurando é
0x7FFFFF
que em notação decimal é 8388607
. Desde os últimos quatro dígitos (8607
) deve ser lido como minutos (86
) e segundos (07
) e seus valores máximos válidos são 59
, o maior valor que pode ser armazenado em 3 bytes com sinal usando a fórmula acima é 8385959
. Que, como TIME
é +838:59:59
. Ta-da! Adivinha? O fragmento de
C
o código listado acima foi extraído disso:/* Limits for the TIME data type */
#define TIME_MAX_HOUR 838
#define TIME_MAX_MINUTE 59
#define TIME_MAX_SECOND 59
#define TIME_MAX_VALUE (TIME_MAX_HOUR*10000 + TIME_MAX_MINUTE*100 + TIME_MAX_SECOND)
Tenho certeza de que é assim que o MySQL 3 costumava manter o
TIME
valores internamente. Esse formato impôs a limitação do intervalo e o requisito de compatibilidade com versões anteriores nas versões subsequentes propagou a limitação até nossos dias.