SqlDateTime.MinValue不等于DateTime.MinValue,为什么?

70

我想知道为什么SqlDateTime.MinValue不同于DateTime.MinValue?

5个回答

132
我认为SQL和.NET的日期数据类型之间的差异源于SQL Server的datetime数据类型,它的最小值、最大值和精度比.NET的DateTime数据类型早得多。随着.NET的出现,团队决定DateTime数据类型应该有一个更自然的最小值,而01/01/0001似乎是一个相当合理的选择,从编程语言的角度而言,而不是数据库的角度,这个值更自然。顺便说一下,在SQL Server 2008中,有许多基于日期的新数据类型(DateTimeDateTime2DateTimeOffset),实际上提供了增加的范围和精度,并且与.NET中的DateTime数据类型密切匹配。例如,DateTime2数据类型的日期范围为0001-01-01到9999-12-31。SQL Server的标准"datetime"数据类型始终具有01/01/1753的最小值(事实上仍然如此!)。我必须承认,我也很好奇这个值的意义,所以进行了一些挖掘...我发现如下内容:
公元1年至今,西方世界使用了两种主要的日历:朱利叶斯·凯撒的儒略日历和教皇格里高利十三世的公历。这两种日历只有一个规则不同:闰年的确定方法。在儒略日历中,所有能被4整除的年份都是闰年。在公历中,所有能被4整除的年份都是闰年,但是能被100整除而不能被400整除的年份不是闰年。因此,1700年、1800年和1900年是儒略日历中的闰年,但不是公历中的闰年,而1600年和2000年都是两种日历中的闰年。
当格里高利十三世在1582年引入他的日历时,他还指示应跳过10月4日至10月15日之间的日期——也就是说,他说10月4日的下一天应该是10月15日。然而,许多国家推迟了转换时间。英国及其殖民地直到1752年才从儒略日历转换为公历,因此对于他们来说,跳过的日期是1752年9月4日至9月14日。其他国家在不同时期转换,但对于我们正在讨论的数据库管理系统来说,1582年和1752年是相关的日期。
因此,当向前回溯多年时,会出现两个日期算术问题。第一个是,应根据儒略日历还是公历规则计算转换之前的闰年?第二个问题是,如何处理跳过的日期以及何时处理?
这就是大型八大数据库管理系统(DBMS)处理这些问题的方式:1.假装没有转换发生。这似乎是SQL标准所要求的,尽管标准文件不清楚:它只说日期“受使用公历自然规则的限制”——无论“自然规则”是什么。这是DB2选择的选项。当假装单一日历规则始终适用于没有人听说过该日历的时间时,技术术语是强制性日历。例如,我们可以说DB2遵循强制性公历日历。
2.完全避免问题。Microsoft和Sybase将其最小日期值设置为1753年1月1日,安全地超过了美国转换日历的时间。这是可辩解的,但不时会出现投诉,称这两个DBMS缺乏其他DBMS具有且SQL标准要求的有用功能。
3.选择1582年。这是Oracle的做法。Oracle用户会发现,日期算术表达式1582年10月15日减去1582年10月4日的值为1天(因为10月5日至14日不存在),而1300年2月29日是有效的(因为儒略历闰年规则适用)。为什么Oracle要进行额外的努力,而SQL标准似乎并不要求呢?答案是用户可能需要它。历史学家和天文学家使用这种混合系统,而不是强制性公历日历。(这也是Sun在为Java实现GregorianCalendar类时选择的默认选项——尽管名称为GregorianCalendar,但它是一种混合日历。)
这句引言摘自以下链接:

SQL性能调优:SQL中的日期


2
不要依赖于 i18n 中的所有 SQL Server DatTime 值始终为格里高利历。俄罗斯和中国(以及其他东欧国家)在20世纪从儒略历转变为格里高利历。 - Richard
1
@Richard - 同意。首先应该对这些事情进行广泛的检查。全世界从朱利安历转换到格里高利历的整个过程是历史上一个不清晰的时期,我怀疑单一的明确规则在每种情况下都能被应用。 - CraigTP
1
我想知道哪些应用程序需要使用19世纪甚至1960年代之前的日期——也许是考古学?但这将限制使用SQL Server的考古学家到1753年,或者使用Oracle到1582年。 - Chris S
5
持有遗嘱和契约信息的应用程序通常会保存旧信息。 - MartW

12

因为在 SQL Server 中 datetime 字段可以存储的最小日期(1753/1/1),与 DateTime .NET 数据类型的 MinValue(0001/1/1)不相等。


1
是的,这是正确的答案。如果您尝试将DateTime.MinValue存储到SqlServer中,您会收到一个错误。 - Stefan Steinegger
9
我不确定这个回答是否完全回答了提问者的问题。他问为什么它们不相同。这个回答只是简单地说“是的,它们不相同”。Craig的回答在潜在问题上更加直接。 - NotMe

11

1753年是格里高利日历的第一个采用者的日期(英国)。为什么选择它而不是01/01/0001 - 这无疑是因为SQL Server在1990年代还是Sybase时所遗留下来的。他们一定早就做出了设计决策,微软SQL团队没有看到改变它的理由。

随着.NET的爆发和它与Sql Server的整合,现在有DateTime2对象供兼容使用。如果你是NHibernate用户,你可以在类型映射中提供此类型以避免DateTime.Min问题。

.NET日期支持除公历外的其他日历:

  • Calendar
    • 中国农历历
    • 东亚农历历
    • 格里高利历
    • 希伯来历
    • 伊斯兰历
    • 日本历
    • 日本农历历
    • 儒略历
    • 韩国历
    • 韩国农历历
    • 波斯历
    • 台湾历
    • 台湾农历历
    • 泰国佛教历
    • 乌姆盖垢拉历

事实上,儒略历比DateTime.MinValue还要早。


嗯,你回答了其他问题。问题是“为什么”,而不是“我该如何解决它”。 - Gabriel Magana

7

两个不同的团体决定了对于日期/时间,“最小值”是什么意思。


1
我认为这是确切的答案。(没有讽刺) - nothrow
1
哥们,如果你被踩了,那是因为你给出了一个愚蠢的回答……“因为我这么说”并不算作一个回答,当提问者已经超过10岁时(我这里还算宽容)。但是我没有给你踩哦 :-) - Gabriel Magana

5

SQL使用不同的内部表示方式来处理日期时间数据。


6
那对 OP 的问题有什么帮助呢? - ANeves
1
@ANeves 这非常有帮助。考虑到.NET和MSSQL相隔超过10年的计算机演进,这意味着它们不太可能具有不同的最小日期。 - Contango
1
@Contango它并不意味着任何东西。它们可以有不同的DateTime内部表示,并且仍然具有相同的任意最小值(例如,为了兼容性或实现给定的标准)。此外,取决于内部表示的最小值将是实现泄漏到规范中,这在我看来是一件非常糟糕的事情™。 - ANeves

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接