我自己也遇到了这个限制,但尽管网上有很多闲聊,但我从未见过对为什么时间数据类型的上限和下限是这样的解释。http://dev.mysql.com/doc/refman/5.7/en/time.html的官方推荐信说
时间值可以从'-838:59:59‘到'838:59:59’之间。时间部分可能很大,因为时间类型不仅可以用来表示一天中的时间(必须小于24小时),而且可以用来表示经过的时间或两个事件之间的时间间隔(可能远远大于24小时,甚至是负的)。
但我并不想知道为什么时间部分被允许“那么大”,而是为什么它被切断了它所在的位置。那么多小时的日子似乎没有任何意义,或者,如果我试着想象有多少秒可以作为一个整数存储的话。那为什么是靶场?
发布于 2016-09-01 21:48:06
TIME值总是存储在MySQL中的3个字节上。但是格式在5.6.4版上发生了变化。我怀疑这不是第一次发生变化。但另一个变化,如果有一个,发生在很久以前,没有公开的证据证明它。MySQL在GitHub上的源代码历史从版本5.5开始(最早的提交是从2008年5月开始),但我正在寻找的更改发生在2001-2002年前后(MySQL 4是在2003年启动的)。
如文档中所述,当前格式使用6位秒(可能值:0到63)、6位(分钟)、10位(可能值:0到1023)、1位表示符号(添加前面提到的间隔的负值),1位未使用并标记为“为未来扩展保留”。
它为处理时间组件(小时、分钟、秒)进行了优化,并且不会浪费太多空间。使用这种格式,可以在-1023:59:59和+1023:59:59之间存储值。然而,MySQL将时间限制在838上,可能是为了与不久前编写的应用程序进行向后兼容性,而我认为这是限制。
在5.6.4版本之前,TIME值也存储在3个字节上,组件被打包为days * 24 * 3600 + hours * 3600 + minutes * 60 + seconds。这种格式是为使用时间戳而优化的(因为它实际上是一个时间戳)。使用这种格式,可以将值存储在关于-2330到+2330小时的范围内。虽然有这么大范围的值可用,但MySQL仍然将-838的值限制为+838小时。
在bug #11655 4上有MySQL,可以使用嵌套的SELECT语句返回-838..+838范围之外的TIME值。这不是一个特性,而是一个bug,而且它是固定的。
将值限制在此范围内并主动更改任何在其外部生成TIME值的代码的唯一原因是向后兼容性。
我怀疑MySQL 3使用了一种不同的格式,由于数据打包的方式,它将有效值限制在-838..+838小时范围内。
通过查看当前的MySQL源代码,我发现了一个有趣的公式:
#define TIME_MAX_VALUE (TIME_MAX_HOUR*10000 + TIME_MAX_MINUTE*100 + TIME_MAX_SECOND)让我们暂时忽略上面使用的名称的MAX部分,只记住TIME_MAX_MINUTE和TIME_MAX_SECOND是00和59之间的数字。该公式只是将小时、分钟和秒串联成一个整数。例如,值170:29:45变为1702945。
这个公式引发了以下问题:假设TIME值存储在带符号的3个字节上,那么以这种方式表示的最大正值是多少?
我们正在寻找的值是0x7FFFFF,它在十进制表示法中是8388607。由于最后四个数字(8607)应该被读取为分钟(86)和秒(07),并且它们的最大有效值是59,所以使用上面的公式可以存储在带符号的3个字节上的最大值是8385959。就像TIME是+838:59:59。塔-达!
你猜怎么着?上面列出的C代码片段是从以下内容提取的:
/* 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)我确信这就是MySQL 3在内部保存TIME值的方式。这种格式限制了范围,而对后续版本的向后兼容性要求将这种限制传播到了我们的时代。
发布于 2016-09-01 00:31:44
DATETIME是基于10的基数存储的,请参阅日期和时间数据类型表示
日期时间:8个字节:一个4字节的整数用于数据打包为YYYY×10000 + MM×100 + DD,一个4字节的整数用于时间打包为HH×10000 + MM×100 + SS。
由于方便和其他原因,(旧的)时间格式以同样的方式编码,使用3个字节:
Hours * 10000 + Minutes * 100 + Seconds这意味着:
3 bytes = 2^24 = 16.777.216
with sign: 2^23 = 8.388.608使用编码,这表示神奇的838小时。还有麦克斯。8608秒的分钟和秒(无溢出),这将导致最大的有效时间838:59:59。有一点是很好的,那就是那个时候的整数表示,8385959,很容易被人读到。但是这种编码当然会留下空白,无效的(未使用的)整数值(如8309999)。
从MySQL 5.6.4开始,time格式将其编码更改为
1位符号(1=非负,0=负)1位未使用(为未来扩展保留) 10位时(0-838) 6位分钟(0-59) 6位秒(0-59)
尽管它现在可以存储更多的时间,但为了兼容性,它仍然只允许838个小时。
发布于 2016-08-31 23:19:00
显然,如果不得到数据库设计者的直接反馈,就很难回答这些类型的问题。
但是有一些关于如何在内部存储不同数据类型的文档,在某种程度上,它可以帮助我们理解这一点。
例如,对于TIME数据类型,请注意如何根据文档在内部存储
非分数部分的
TIME编码: 1位符号(1=非负,0=负)1位未使用(为未来扩展保留) 10位时(0-838) 6位分钟(0-59) 6位秒(0-59)
因此,正如您所看到的,目标是将信息拟合在3个字节内。而且,在这3个字节中,10位是为hours保留的,这几乎决定了整个范围。
也就是说,10位允许的值可以达到1023,所以我想,从技术上讲,如果不改变存储大小,范围可能是-1023:59:59到1023:59:59。为什么他们不这么做,他们选择838作为截止,我不知道。
https://stackoverflow.com/questions/39259910
复制相似问题