Which one:
is the recommended way to store date and time in SQL Server 2008+?
I\'m aware of differ
The MSDN documentation for datetime recommends using datetime2. Here is their recommendation:
Use the
time
,date
,datetime2
anddatetimeoffset
data types for new work. These types align with the SQL Standard. They are more portable.time
,datetime2
anddatetimeoffset
provide more seconds precision.datetimeoffset
provides time zone support for globally deployed applications.
datetime2 has larger date range, a larger default fractional precision, and optional user-specified precision. Also depending on the user-specified precision it may use less storage.
I think DATETIME2
is the better way to store the date
, because it has more efficiency than
the DATETIME
. In SQL Server 2008
you can use DATETIME2
, it stores a date and time, takes 6-8 bytes
to store and has a precision of 100 nanoseconds
. So anyone who needs greater time precision will want DATETIME2
.
According to this article, if you would like to have the same precision of DateTime using DateTime2 you simply have to use DateTime2(3). This should give you the same precision, take up one fewer bytes, and provide an expanded range.
I just stumbled across one more advantage for DATETIME2
: it avoids a bug in the Python adodbapi
module, which blows up if a standard library datetime
value is passed which has non-zero microseconds for a DATETIME
column but works fine if the column is defined as DATETIME2
.
DATETIME2
has a date range of "0001 / 01 / 01" through "9999 / 12 / 31" while the DATETIME
type only supports year 1753-9999.
Also, if you need to, DATETIME2
can be more precise in terms of time; DATETIME is limited to 3 1/3 milliseconds, while DATETIME2
can be accurate down to 100ns.
Both types map to System.DateTime
in .NET - no difference there.
If you have the choice, I would recommend using DATETIME2
whenever possible. I don't see any benefits using DATETIME
(except for backward compatibility) - you'll have less trouble (with dates being out of range and hassle like that).
Plus: if you only need the date (without time part), use DATE - it's just as good as DATETIME2
and saves you space, too! :-) Same goes for time only - use TIME
. That's what these types are there for!
Almost all the Answers and Comments have been heavy on the Pros and light on the Cons. Here's a recap of all Pros and Cons so far plus some crucial Cons (in #2 below) I've only seen mentioned once or not at all.
1.1. More ISO compliant (ISO 8601) (although I don’t know how this comes into play in practice).
1.2. More range (1/1/0001 to 12/31/9999 vs. 1/1/1753-12/31/9999) (although the extra range, all prior to year 1753, will likely not be used except for ex., in historical, astronomical, geologic, etc. apps).
1.3. Exactly matches the range of .NET’s DateTime
Type’s range (although both convert back and forth with no special coding if values are within the target type’s range and precision except for Con # 2.1 below else error / rounding will occur).
1.4. More precision (100 nanosecond aka 0.000,000,1 sec. vs. 3.33 millisecond aka 0.003,33 sec.) (although the extra precision will likely not be used except for ex., in engineering / scientific apps).
1.5. When configured for similar (as in 1 millisec not "same" (as in 3.33 millisec) as Iman Abidi has claimed) precision as DateTime
, uses less space (7 vs. 8 bytes), but then of course, you’d be losing the precision benefit which is likely one of the two (the other being range) most touted albeit likely unneeded benefits).
2.1. When passing a Parameter to a .NET SqlCommand
, you must specify System.Data.SqlDbType.DateTime2
if you may be passing a value outside the SQL Server DateTime
’s range and/or precision, because it defaults to System.Data.SqlDbType.DateTime
.
2.2. Cannot be implicitly / easily converted to a floating-point numeric (# of days since min date-time) value to do the following to / with it in SQL Server expressions using numeric values and operators:
2.2.1. add or subtract # of days or partial days. Note: Using DateAdd
Function as a workaround is not trivial when you're needing to consider multiple if not all parts of the date-time.
2.2.2. take the difference between two date-times for purposes of “age” calculation. Note: You cannot simply use SQL Server’s DateDiff
Function instead, because it does not compute age
as most people would expect in that if the two date-times happens to cross a calendar / clock date-time boundary of the units specified if even for a tiny fraction of that unit, it’ll return the difference as 1 of that unit vs. 0. For example, the DateDiff
in Day
’s of two date-times only 1 millisecond apart will return 1 vs. 0 (days) if those date-times are on different calendar days (i.e. “1999-12-31 23:59:59.9999999” and “2000-01-01 00:00:00.0000000”). The same 1 millisecond difference date-times if moved so that they don’t cross a calendar day, will return a “DateDiff” in Day
’s of 0 (days).
2.2.3. take the Avg
of date-times (in an Aggregate Query) by simply converting to “Float” first and then back again to DateTime
.
NOTE: To convert DateTime2
to a numeric, you have to do something like the following formula which still assumes your values are not less than the year 1970 (which means you’re losing all of the extra range plus another 217 years. Note: You may not be able to simply adjust the formula to allow for extra range because you may run into numeric overflow issues.
25567 + (DATEDIFF(SECOND, {d '1970-01-01'}, @Time) + DATEPART(nanosecond, @Time) / 1.0E + 9) / 86400.0
– Source: “ https://siderite.dev/blog/how-to-translate-t-sql-datetime2-to.html “
Of course, you could also Cast
to DateTime
first (and if necessary back again to DateTime2
), but you'd lose the precision and range (all prior to year 1753) benefits of DateTime2
vs. DateTime
which are prolly the 2 biggest and also at the same time prolly the 2 least likely needed which begs the question why use it when you lose the implicit / easy conversions to floating-point numeric (# of days) for addition / subtraction / "age" (vs. DateDiff
) / Avg
calcs benefit which is a big one in my experience.
Btw, the Avg
of date-times is (or at least should be) an important use case. a) Besides use in getting average duration when date-times (since a common base date-time) are used to represent duration (a common practice), b) it’s also useful to get a dashboard-type statistic on what the average date-time is in the date-time column of a range / group of Rows. c) A standard (or at least should be standard) ad-hoc Query to monitor / troubleshoot values in a Column that may not be valid ever / any longer and / or may need to be deprecated is to list for each value the occurrence count and (if available) the Min
, Avg
and Max
date-time stamps associated with that value.