DateTime2与SQL Server中的DateTime

Mik*_*eon 726 sql t-sql sql-server datetime datetime2

哪一个:

是在SQL Server 2008+中存储日期和时间推荐方法吗?

我知道精度(和存储空间可能)的差异,但暂时忽略这些,是否有关于何时使用什么的最佳实践文档,或者我们应该只使用它datetime2

Ada*_*rad 610

datetime的MSDN文档建议使用datetime2.以下是他们的建议:

使用time,date,datetime2datetimeoffset数据类型的新工作.这些类型与SQL标准一致.它们更便携. time,datetime2datetimeoffset 提供更多的秒精度. datetimeoffset为全局部署的应用程序提供时区支持.

datetime2具有更大的日期范围,更大的默认小数精度和可选的用户指定精度.此外,根据用户指定的精度,它可能使用较少的存储空间.

  • 虽然datetime2的精度有所提高,但某些客户端不支持日期,时间或日期时间2,并强制您转换为字符串文字.如果您更关注兼容性而不是精度,请使用日期时间 (43认同)
  • DATETIMEOFFSET的时区支持是用词不当.它仅存储特定时刻的UTC偏移,而不是时区. (6认同)
  • 另一种选择是使用索引视图,将列转换为兼容日期时间.但是,您需要能够将应用指向视图. (4认同)
  • @Porad:由于是"SQL标准",在实践中获得"更便携"的好处究竟是什么呢?除此之外,你还要编写更多的代码,这些代码对于另一个RDBMS的"端口"的可读性/维护性要差得多可能永远不会在该代码的生命周期中发生.除了微软提供的SQL Server工具和驱动程序(如果是),是否有任何应用程序实际上依赖于`DateTime2`类型的特定位级表示(或任何其他的SQL Server类型)?请参阅下面的7/10/17答案中的缺点我为什么要问. (4认同)
  • @Adam Porad:此外,所有这些好处都可能是不必要的(在工程或科学应用程序之外),因此不值得损失多少,更有可能需要:更容易(甚至考虑变通办法)隐式/显式转换为一个浮点数字(天数包括,如果应用,自最小日期时间以来的小数天数)加法,减法,最小值,最大值和平均值.有关详细信息,请参阅下面的7/10/17答案中的缺点. (2认同)
  • 谁想到了这些函数名?任何其他体面的编程语言都不会接受在名称中添加“ 2”的较新版本。接下来是datetime3吗? (2认同)

mar*_*c_s 477

DATETIME2日期范围为" DATETIME0001/01/01 "至" 9999/12/31 ",而该类型仅支持1753-9999年.

此外,如果您需要,DATETIME2可以在时间上更精确; DATETIME限制在3 1/3毫秒,而DATETIME2精确到100ns.

两种类型都映射到System.DateTime.NET - 没有区别.

如果您有选择,我建议DATETIME2尽可能使用.我没有看到任何使用的好处DATETIME(向后兼容性除外) - 你会遇到更少的麻烦(日期超出范围和麻烦).

另外:如果您只需要日期(没有时间部分),请使用DATE - 它也一样好,DATETIME2并为您节省空间!:-)同样只限时间 - 使用TIME.这就是这些类型的用途!

  • 将.NET DateTime值作为参数添加到SqlCommand时要小心,因为它喜欢假设它是旧的日期时间类型,如果您尝试写入超出1753-9999年范围的DateTime值,您将收到错误除非您为SqlParameter明确指定类型为System.Data.SqlDbType.DateTime2.无论如何,datetime2很棒,因为它可以存储可以存储在.NET DateTime类型中的任何值. (154认同)
  • 大声笑,在我意识到这是我自己的评论(一年前制作)之前,我只是试图提出我自己的评论(上图).我仍然在处理.NET框架的愚蠢设计决策,在默认情况下作为SqlParameters传递TRUNCATE所有DateTime值,除非您明确地将其设置为更精确的SqlDbType.DateTime2.这么多用于自动推断正确的类型.实际上,他们应该使更改变得透明,取代不太精确,效率较低,有限范围的实现,并保留原始的"日期时间"类型名称.另请参见http://stackoverflow.com/q/8421332/88409 (69认同)
  • @marc_s - 这不是null的用途吗? (10认同)
  • @JohnFX - 这里有点晚了 - 但你不会将datetime设置为null.你会使用Nullable <datetime>或datetime?处理null就好了 - 并且在映射到proc时只会执行param.value = someDateTime ?? DBValue.Null不幸的是我们坚持使用带有数字的数据类型 - 只是看起来很'通用':) (8认同)
  • @marc_s那不是`Nullable <DateTime>`的用途吗? (5认同)
  • @Marc:*.*与.Net类型的映射存在差异:DateTime2与.Net DateTime类型同构,因此没有"超出范围"的错误,并且由于不需要转换,可能会有一些非常小的性能提升. (4认同)
  • @marc_s - 当其他条件相同时,不理解你更喜欢DATETIME2的观点.对于大多数应用来说,支持1-1752年的灵活性是否真的有利?我从来没有一个应用程序代表比1800年代晚期提前一年的应用程序,似乎它会鼓励像2011年错误编码一样的事故. (2认同)

Ima*_*idi 196

datetime2在大多数方面获胜,除了(旧应用程序兼容性)

  1. 更大范围的价值观
  2. 更好的准确性
  3. 较小的存储空间 (如果指定了可选的用户指定精度)

SQL日期和时间数据类型比较 -  datetime,datetime2,date,TIME

请注意以下几点

  • 句法
    • datetime2 [(小数秒精度=>查看低于存储空间大小)]
  • 精度,规模
    • 0到7位数,精度为100ns.
    • 默认精度为7位数.
  • 存储大小
    • 6个字节,精度小于3;
    • 7个字节用于精度3和4.
    • 所有其他精度需要8个字节.
  • DateTime2(3)具有与DateTime相同的位数,但使用7个字节的存储而不是8个字节(SQLHINTS- DateTime Vs DateTime2)
  • datetime2上查找更多内容(Transact-SQL MSDN文章)

图像源: MCTS Self-Paced Training Kit(考试70-432):Microsoft®SQLServer®2008 - 实施和维护 第3章:表格 - >第1课:创建表格 - >第66页

  • 感谢您为它显示统计+1,`datetime2`很棒(Winner) (7认同)
  • @Iman Abidi:根据 Oskar Berggren 于 2014 年 9 月 10 日下午 3:51 对您引用的“SQLHINTS-DateTime Vs DateTime2”文章发表的评论:“datetime2(3) 与 datetime 不同。它们将具有相同的数字位数,但 datetime 的精度为 3.33 毫秒,而 datetime2(3) 的精度为 1 毫秒。” (2认同)

EBa*_*arr 105

我同意@marc_s和@Adam_Poward - DateTime2是前进的首选方法.它具有更广泛的日期,更高的精度,并使用相同或更少的存储(取决于精度).

然而,讨论错过了一件事......
@Marc_s声明:Both types map to System.DateTime in .NET - no difference there.这是正确的,然而,反之则不正确 ......并且在进行日期范围搜索时很重要(例如"找到我在2010年5月5日修改的所有记录").

.NET的版本 Datetime具有类似的范围和精度DateTime2.当映射.NET Datetime下到老SQL DateTime出现隐含四舍五入.旧的SQL DateTime精确到3毫秒.这意味着11:59:59.997尽可能接近一天结束.任何更高的东西都会向上舍入到第二天.

试试这个 :

declare @d1 datetime   = '5/5/2010 23:59:59.999'
declare @d2 datetime2  = '5/5/2010 23:59:59.999'
declare @d3 datetime   = '5/5/2010 23:59:59.997'
select @d1 as 'IAmMay6BecauseOfRounding', @d2 'May5', @d3 'StillMay5Because2msEarlier'
Run Code Online (Sandbox Code Playgroud)

避免这种隐式舍入是转移到DateTime2的重要原因.隐含的日期舍入显然会引起混淆:

  • 你也可以通过不试图找到一天的"结束"来避免这种舍入.> = 5月5日和<5月6日更加安全,可以使用任何日期/时间类型(当然除了TIME).还建议避免像m/d/yyyy这样的区域性模糊格式. (13认同)
  • @AaronBertrand - 完全同意,但看看我们有问题的问题数量似乎值得描述. (2认同)
  • 你为什么从`20100505`切换到`5/5/2010`?前一种格式适用于 SQL Server 中的任何区域。后者会中断:`SET LANGUAGE French; SELECT Convert(datetime, '1/7/2015')` 哎呀:`2015-07-01 00:00:00.000` (2认同)

Tom*_*Tom 17

几乎所有的答案和评论都是关于优点和重点的重点.以下是迄今为止所有优点和缺点的概述以及一些重要的缺点(下面的#2)我只看过一次或根本没有提到过.

  1. 优点:

1.1.更符合ISO标准(ISO 8601)(虽然我不知道这在实践中是如何发挥作用的).

1.2.更多范围(1/1/0001至12/31/9999对比1/1/1753-12/31/9999)(尽管额外的范围,所有在1753年之前,可能不会被使用,除了ex.,在历史,天文,地质等应用程序).

1.3.完全匹配.NET DateTime类型范围的范围(尽管如果值在目标类型的范围和精度范围内,除了Con#2.1之外,两者都来回转换没有特殊编码,否则将发生错误/舍入).

1.4.更精确(100纳秒又名0.000,000,1秒与3.33毫秒又名0.003,33秒)(虽然额外的精度可能不会被使用,除了ex.,在工程/科学应用程序中).

1.5.当配置为类似(如1毫秒不是"相同"(如3.33毫秒),如Iman Abidi所声称的)精度为DateTime,使用较少的空间(7对8字节),但当然,你将失去精确利益,这可能是最受欢迎的两个(另一个是范围)中的一个,虽然可能是不必要的好处).

  1. 缺点:

2.1.将参数传递给.NET时SqlCommand,必须指定System.Data.SqlDbType.DateTime2是否可以传递SQL Server DateTime范围和/或精度之外的值,因为它默认为System.Data.SqlDbType.DateTime.

2.2.无法使用数值和运算符在SQL Server表达式中隐式/轻松转换为浮点数字(自最小日期时间以来的天数)值,以便对其执行以下操作:

2.2.1.添加或减去天数或部分天数.注意:DateAdd当您需要考虑日期时间的多个(如果不是全部)部分时,使用函数作为变通方法并非易事.

2.2.2.为了"年龄"计算,取两个日期时间之间的差异.注意:您不能简单地使用SQL Server的DateDiff函数,因为age如果两个日期时间恰好跨越指定单位的日历/时钟日期 - 时间边界,即使对于一小部分,它也不像大多数人所期望的那样计算该单元的,它会返回差作为该单元与0的1例如,DateDiffDay"两个日期时间唯一1毫秒间隔将返回1对0(天)如果这些日期-时间在不同的日历日(即"1999-12-31 23:59:59.9999999"和"2000-01-01 00:00:00.0000000").相同的1毫秒差异日期 - 如果移动以便它们不跨越日历日,则将返回Day0的"天数"(日期)中的"DateDiff" .

2.2.3.Avg通过简单地转换为"Float"然后再转回到,来获取日期时间(在聚合查询中)DateTime.

注意:要转换DateTime2为数字,您必须执行类似下面的公式,仍然假设您的值不小于1970年(这意味着您将失去所有额外范围再加上217年.注意:您可以无法简单地调整公式以允许额外的范围,因为您可能会遇到数字溢出问题.

25567 + (DATEDIFF(SECOND, {d '1970-01-01'}, @Time) + DATEPART(nanosecond, @Time) / 1.0E + 9) / 86400.0- 来源:" https://siderite.blogspot.com/2015/08/how-to-translate-t-sql-datetime2-to.html "

当然,你也可以CastDateTime第一(如果必要,再次回到DateTime2),但你会失去(所有之前的1753年)的收益的精度和范围DateTime2DateTime它们prolly 2最大,也同时prolly当你失去隐式/简单转换为浮点数(天数)加/减/"年龄"(vs. DateDiff)/ Avg计算效益时,为什么最不可能需要这个问题.在我的经验中.

顺便说一句,Avg日期时间是(或至少应该是)一个重要的用例.a)除了用于获得平均持续时间时,日期时间(因为共同的基准日期时间)用于表示持续时间(通常的做法),b)获得关于平均日期的仪表板类型统计数据也是有用的 - time位于范围/行组的日期时间列中.c)标准(或至少应该是标准的)ad-hoc查询,用于监视/排除列中可能无效/不再有效和/或可能需要弃用的值,是为每个值列出事件计数和(如果可用)的Min,AvgMax与该值相关联的日期的时间标记.


小智 15

如果你是一个尝试将Now()写入相关字段的Access开发人员,DateTime2会造成严重破坏.刚刚进行了Access - > SQL 2008 R2迁移,它将所有日期时间字段都放在DateTime2中.使用Now()追加记录作为被轰炸的值.这是在2012年1月1日下午2:53:04没关系,但不是在2012年1月10日下午2:53:04.

一旦角色有所作为.希望它对某人有帮助.


Bao*_*dad 15

下面是一个示例,它将向您展示smalldatetime,datetime,datetime2(0)和datetime2(7)之间存储大小(字节)和精度的差异:

DECLARE @temp TABLE (
    sdt smalldatetime,
    dt datetime,
    dt20 datetime2(0),
    dt27 datetime2(7)
)

INSERT @temp
SELECT getdate(),getdate(),getdate(),getdate()

SELECT sdt,DATALENGTH(sdt) as sdt_bytes,
    dt,DATALENGTH(dt) as dt_bytes,
    dt20,DATALENGTH(dt20) as dt20_bytes,
    dt27, DATALENGTH(dt27) as dt27_bytes FROM @temp
Run Code Online (Sandbox Code Playgroud)

返回

sdt                  sdt_bytes  dt                       dt_bytes  dt20                 dt20_bytes  dt27                         dt27_bytes
2015-09-11 11:26:00  4          2015-09-11 11:25:42.417  8         2015-09-11 11:25:42  6           2015-09-11 11:25:42.4170000  8
Run Code Online (Sandbox Code Playgroud)

因此,如果我想将信息存储到第二个 - 但不是毫秒 - 如果我使用datetime2(0)而不是datetime或datetime2(7),我可以每个节省2个字节.


Ric*_*ett 9

使用非美国设置时,将日期字符串解释为datetimedatetime2可以有所不同DATEFORMAT.例如

set dateformat dmy
declare @d datetime, @d2 datetime2
select @d = '2013-06-05', @d2 = '2013-06-05'
select @d, @d2
Run Code Online (Sandbox Code Playgroud)

这将返回2013-05-06(即5月6日)datetime2013-06-05(即6月5日)datetime2.但是,dateformat设置为mdy,both @d@d2return 2013-06-05.

datetime行为似乎与MSDN文档SET DATEFORMAT状态不一致:某些字符串格式(例如ISO 8601)的解释独立于DATEFORMAT设置.显然不是真的!

直到我被这个咬了,我总是认为yyyy-mm-dd只要处理日期,无论语言/语言环境设置如何.

  • 不。对于ISO 8601,我认为您的意思是YYYYMMDD(无破折号)。`设置语言法语;DECLARE @d DATETIME ='20130605'; SELECT @d;`再次使用破折号。 (2认同)
  • 我知道,但在 SQL Server 中只有 no-dash 语法是安全的。 (2认同)

Fis*_*ury 9

而有增加的精度DATETIME2,某些客户端不支持日期,时间,或DATETIME2和强迫你转换为一个字符串.特别是Microsoft提到这些数据类型的"低级"ODBC,OLE DB,JDBC和SqlClient问题,并且有一个图表显示每个数据类型的映射方式.

如果值兼容性超过精度,请使用datetime


MJ *_*han 8

旧问题......但是我想在这里添加一些尚未说明的东西......(注意:这是我自己的观察,所以不要求任何参考)

在过滤条件中使用时,Datetime2更快.

TLDR:

在SQL 2016中,我有一个包含十万行的表和一个日期时间列ENTRY_TIME,因为它需要存储最多几秒的确切时间.在执行具有许多连接和子查询的复杂查询时,当我使用where子句时:

WHERE ENTRY_TIME >= '2017-01-01 00:00:00' AND ENTRY_TIME < '2018-01-01 00:00:00'
Run Code Online (Sandbox Code Playgroud)

当有数百行时,查询很好,但当行数增加时,查询开始出现此错误:

Execution Timeout Expired. The timeout period elapsed prior
to completion of the operation or the server is not responding.
Run Code Online (Sandbox Code Playgroud)

我删除了where子句,并且意外地,查询在1秒内​​运行,尽管现在获取了所有日期的所有行.我用where子句运行内部查询,花了85秒,没有where子句花了0.01秒.

我在这里遇到了很多关于这个问题的线程作为日期时间过滤性能

我优化了一下查询.但我得到的真正速度是将datetime列更改为datetime2.

现在,先前超时的同一查询只需不到一秒钟.

干杯


jKl*_*aus 6

根据本文的介绍,如果您希望使用DateTime2获得与DateTime相同的精度,则只需使用DateTime2(3)。这应该给您相同的精度,减少一个字节,并提供更大的范围。