Precision required

  • Toreador (3/14/2013)


    Most disappointing. I was sure when I got to the thread I'd see several pages of identical replies saying that it gives an error about assigning variables in the declare statement. What is the world coming to?!

    I think most of us use SQL 2008 or later versions and are used to it by now. 🙂

    That said, this reminds me why I don't use smalldatetime for anything.

    Date - yes (just having dates is awesome!)

    Time - yes (just having times is also awesome!)

    Datetime - yes by default from old stuff (not the coolest, but it generally works)

    DateTimeOffset - default for new date/time columns (we have enough localization problems, storing the offset in the datetime helps us avoid new ones).



    --Mark Tassin
    MCITP - SQL Server DBA
    Proud member of the Anti-RBAR alliance.
    For help with Performance click this link[/url]
    For tips on how to post your problems[/url]

  • Nice question and correct answer (pity about the locale issue, though).

    Unfortunately, the explanation is rather wrong - not surprising, as the BOL page on smalldatetime also gets the rounding wrong.

    29.999 seconds is not rounded up to 1 minute in conversion to smalldatetime. What is happening in the code here is than 29.999 seconds is rounded up to 30.000 seconds in the conversion to datetime, and 30.000 seconds is rounded up to 1 minute in the conversion to smalldatetime. For conversion to smalldatetime, values less than or equal to 29.9999999 seconds are rounded down unless a prior conversion to datetime causes rounding up (which can only happen if the original value is greater than 29.99849999 seconds) and values 30.0000000 or more seconds are rounded up. The weirdness of the result here (where the smalldatetime appears to have been rounded in teh wrong direction) isn't caused by the difference between the precisions of smalldatetime and datetime but by the lack of precision in datetime.

    I imagine the BOL error is because whoever wrote it thought a string like '1999-09-19 10:00:30.999' was a some sort of datetime literal; well, it isn't, it's a string literal and casting string literals as small datetime invokes a two stage process: first convert to datetime, and then round to smalldatetime - - there is no one stage conversion from string literal to smalldatetime in SQL Server. I think that was a bad decision by the seigners, but they probably justified it on the grounds that it was best if a given string literal represented only one time, which with the two-stage process was sort of true until the introduction of datetime2 in SQL 2005.

    You can check that it works like this easily by declaring a datetime2 variable instead of a datetime variable, and converting to smalldatetime directly from that and also converting the datetime2 value to datetime and converting that to smalldatetime. For datetime values ending with values between 29.9985000 seconds and 29.9999999 seconds the two routes will deliver different smalldatetime values.

    edit: fix typos and omitted words

    Tom

  • L' Eomot Inversé (3/14/2013)


    Nice question and correct answer (pity about the locale issue, though).

    Unfortunately, the explanation is rather wrong - not surprising, as the BOL page on smalldatetime also gets the rounding wrong.

    29.999 seconds is not rounded up to 1 minute in conversion to smalldatetime. What is happening in the code here is than 29.999 seconds is rounded up to 30.000 seconds in the conversion to datetime, and 30.000 seconds is rounded up to 1 minute in the conversion to smalldatetime. For conversion to smalldatetime, values less than or equal to 29.9999999 seconds are rounded down unless a prior conversion to datetime causes rounding up (which can only happen if the original value is greater than 29.99849999 seconds) and values 30.0000000 or more seconds are rounded up. The weirdness of the result here (where the smalldatetime appears to have been rounded in teh wrong direction) isn't caused by the difference between the precisions of smalldatetime and datetime but by the lack of precision in datetime.

    I imagine the BOL error is because whoever wrote it thought a string like '1999-09-19 10:00:30.999' was a some sort of datetime literal; well, it isn't, it's a string literal and casting string literals as small datetime invokes a two stage process: first convert to datetime, and then round to smalldatetime - - there is no one stage conversion from string literal to smalldatetime in SQL Server. I think that was a bad decision by the seigners, but they probably justified it on the grounds that it was best if a given string literal represented only one time, which with the two-stage process was sort of true until the introduction of datetime2 in SQL 2005.

    You can check that it works like this easily by declaring a datetime2 variable instead of a datetime variable, and converting to smalldatetime directly from that and also converting the datetime2 value to datetime and converting that to smalldatetime. For datetime values ending with values between 29.9985000 seconds and 29.9999999 seconds the two routes will deliver different smalldatetime values.

    edit: fix typos and omitted words

    +1

    Thanks for the question and a great explanation by Tom

    ___________________________________________________________________
    If I can answer a question then anyone can answer it..trying to reverse the logic.. :hehe:

  • Plus one,thanx.

    “When I hear somebody sigh, ‘Life is hard,’ I am always tempted to ask, ‘Compared to what?’” - Sydney Harris

  • Richard Warr (3/14/2013)


    Interestingly, if I run the code, I get:

    Msg 242, Level 16, State 3, Line 1

    The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.

    But if I change the first line to DECLARE @Datetime datetime = '2013-02-24T23:59:30' then it works as expected.

    What do I have that is different (I'm in the UK if that helps)?

    Well...

    SET LANGUAGE British;

    -- The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.

    SELECT CAST('2013-02-24 23:59:30' AS DATETIME);

    SET LANGUAGE us_english;

    -- Success.

    SELECT CAST('2013-02-24 23:59:30' AS DATETIME);

  • demonfox (3/13/2013)


    an easy one for the day !!!

    thanks for the question

    +1

  • kapil_kk (3/14/2013)


    Richard Warr (3/14/2013)


    Hugo Kornelis (3/14/2013)


    Richard Warr (3/14/2013)


    What do I have that is different (I'm in the UK if that helps)?

    Locale settings.

    Contrary to popular belief, yyyy-mm-dd hh:mm:ss and yyyy-mm-dd are NOT a guaranteed safe date format. This can, in some locales, still be interpreted as yyyy-dd-mm.

    The only guaranteed safe formats for datetime are:

    * yyyymmdd for date only; no seperators.

    * yyyy-mm-ddThh:mm:ss or yyyy-mm-ddThh:mm:ss.ttt (where ttt is thousands of a second) for date and time; the dashes, uppercase T, colons (and dot in the second version) are all required seperators.

    For the date data type, rules have changed slightly. I know both yyyy-mm-dd and yyyymmdd are guaranteed for date. I don't know if there are more changes.

    Thank you Hugo. Pleased to say that I always use the "T" format (which I believe to be ISO) and encourage colleagues to do the same!

    I have never used this 'T' format :w00t:

    +1

    I should be careful... :w00t:

  • L' Eomot Inversé (3/14/2013)


    Nice question and correct answer (pity about the locale issue, though).

    Unfortunately, the explanation is rather wrong - not surprising, as the BOL page on smalldatetime also gets the rounding wrong.

    29.999 seconds is not rounded up to 1 minute in conversion to smalldatetime. What is happening in the code here is than 29.999 seconds is rounded up to 30.000 seconds in the conversion to datetime, and 30.000 seconds is rounded up to 1 minute in the conversion to smalldatetime. For conversion to smalldatetime, values less than or equal to 29.9999999 seconds are rounded down unless a prior conversion to datetime causes rounding up (which can only happen if the original value is greater than 29.99849999 seconds) and values 30.0000000 or more seconds are rounded up. The weirdness of the result here (where the smalldatetime appears to have been rounded in teh wrong direction) isn't caused by the difference between the precisions of smalldatetime and datetime but by the lack of precision in datetime.

    I imagine the BOL error is because whoever wrote it thought a string like '1999-09-19 10:00:30.999' was a some sort of datetime literal; well, it isn't, it's a string literal and casting string literals as small datetime invokes a two stage process: first convert to datetime, and then round to smalldatetime - - there is no one stage conversion from string literal to smalldatetime in SQL Server. I think that was a bad decision by the seigners, but they probably justified it on the grounds that it was best if a given string literal represented only one time, which with the two-stage process was sort of true until the introduction of datetime2 in SQL 2005.

    You can check that it works like this easily by declaring a datetime2 variable instead of a datetime variable, and converting to smalldatetime directly from that and also converting the datetime2 value to datetime and converting that to smalldatetime. For datetime values ending with values between 29.9985000 seconds and 29.9999999 seconds the two routes will deliver different smalldatetime values.

    Thanks for the gr8 explanation... its a new learning for me.

  • Hugo Kornelis (3/14/2013)


    Richard Warr (3/14/2013)


    What do I have that is different (I'm in the UK if that helps)?

    Locale settings.

    Contrary to popular belief, yyyy-mm-dd hh:mm:ss and yyyy-mm-dd are NOT a guaranteed safe date format. This can, in some locales, still be interpreted as yyyy-dd-mm.

    The only guaranteed safe formats for datetime are:

    * yyyymmdd for date only; no seperators.

    * yyyy-mm-ddThh:mm:ss or yyyy-mm-ddThh:mm:ss.ttt (where ttt is thousands of a second) for date and time; the dashes, uppercase T, colons (and dot in the second version) are all required seperators.

    For the date data type, rules have changed slightly. I know both yyyy-mm-dd and yyyymmdd are guaranteed for date. I don't know if there are more changes.

    Interesting, I would be one of the people who thought yyyy-mm-dd was a safe date format.

    Thanks Hugo, I'd better do a bit of reading.

  • Thank you, David for the question and Tom and Hugo for their brilliant explanations.

    Saludos,

    "El" Jerry.

    "A watt of Ottawa" - Gerardo Galvan

    To better understand your help request, please follow these best practices.[/url]

  • Thanks for an easy one!

  • Wow Tom. Epic yet fantastic explanation of the inner working off this qotd.

    Thanks very much for that. I thought it was interesting when I posted it but you really took it to the next level.

    Cheers

    Dave

    David Bridge
    David Bridge Technology Limited
    www.davidbridgetechnology.com

  • sestell1 (3/14/2013)


    Hugo Kornelis (3/14/2013)


    Richard Warr (3/14/2013)


    What do I have that is different (I'm in the UK if that helps)?

    Locale settings.

    Contrary to popular belief, yyyy-mm-dd hh:mm:ss and yyyy-mm-dd are NOT a guaranteed safe date format. This can, in some locales, still be interpreted as yyyy-dd-mm.

    The only guaranteed safe formats for datetime are:

    * yyyymmdd for date only; no seperators.

    * yyyy-mm-ddThh:mm:ss or yyyy-mm-ddThh:mm:ss.ttt (where ttt is thousands of a second) for date and time; the dashes, uppercase T, colons (and dot in the second version) are all required seperators.

    For the date data type, rules have changed slightly. I know both yyyy-mm-dd and yyyymmdd are guaranteed for date. I don't know if there are more changes.

    Interesting, I would be one of the people who thought yyyy-mm-dd was a safe date format.

    Thanks Hugo, I'd better do a bit of reading.

    I learned this a while ago playing with date values.

  • DavidBridgeTechnology.com (3/14/2013)


    Wow Tom. Epic yet fantastic explanation of the inner working off this qotd.

    Thanks very much for that. I thought it was interesting when I posted it but you really took it to the next level.

    Cheers

    Dave

    Thanks Dave. But remember that no-one will comment on questions unless someone poses them. You wrote a question that generated useful comments on the way string literal conversion to datetime depends on locale plus comments on how string conversion to smalldatetime works - that's a wider range of discussion than any of my questions ever provoked, which suggets to me that it was a better question than any of mine. Just remember that much of the credit for useful discussion on your question is yours, not anyone elses, and keep on producing good questions like this one.

    Tom

  • Interesting question, thanks.

    Need an answer? No, you need a question
    My blog at https://sqlkover.com.
    MCSE Business Intelligence - Microsoft Data Platform MVP

Viewing 15 posts - 16 through 30 (of 35 total)

You must be logged in to reply to this topic. Login to reply