Which one:
is the recommended way to store date and time in SQL Server 2008+?
I'm aware of differences in precision (and storage space probably), but ignoring those for now, is there a best practice document on when to use what, or maybe we should just use datetime2
only?
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 specifySystem.Data.SqlDbType.DateTime2
if you may be passing a value outside the SQL ServerDateTime
’s range and/or precision, because it defaults toSystem.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 computeage
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, theDateDiff
inDay
’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” inDay
’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 toDateTime
.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.blogspot.com/2015/08/how-to-translate-t-sql-datetime2-to.html “Of course, you could also
Cast
toDateTime
first (and if necessary back again toDateTime2
), but you'd lose the precision and range (all prior to year 1753) benefits ofDateTime2
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) theMin
,Avg
andMax
date-time stamps associated with that value.Here is an example that will show you the differences in storage size (bytes) and precision between smalldatetime, datetime, datetime2(0), and datetime2(7):
which returns
So if I want to store information down to the second - but not to the millisecond - I can save 2 bytes each if I use datetime2(0) instead of datetime or datetime2(7).
The above SQL won't work with a DateTime2 field. It returns and error "Operand type clash: datetime2 is incompatible with int"
Adding 1 to get the next day is something developers have been doing with dates for years. Now Microsoft have a super new datetime2 field that cannot handle this simple functionality.
"Let's use this new type that is worse than the old one", I don't think so!
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.
I concurr with @marc_s and @Adam_Poward -- DateTime2 is the preferred method moving forward. It has a wider range of dates, higher precision, and uses equal or less storage (depending on precision).
One thing the discussion missed, however...
@Marc_s states:
Both types map to System.DateTime in .NET - no difference there
. This is correct, however, the inverse is not true...and it matters when doing date range searches (e.g. "find me all records modified on 5/5/2010")..NET's version of
Datetime
has similar range and precision toDateTime2
. When mapping a .netDatetime
down to the old SQLDateTime
an implicit rounding occurs. The old SQLDateTime
is accurate to 3 milliseconds. This means that11:59:59.997
is as close as you can get to the end of the day. Anything higher is rounded up to the following day.Try this :
Avoiding this implicit rounding is a significant reason to move to DateTime2. Implicit rounding of dates clearly causes confusion:
DATETIME2
has a date range of "0001 / 01 / 01" through "9999 / 12 / 31" while theDATETIME
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, whileDATETIME2
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 usingDATETIME
(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 - useTIME
. That's what these types are there for!