Incorrect date comparison results in SQL Server 2008 R2











up vote
0
down vote

favorite












I have a LINQ 2 SQL query that's getting me a list of results for the month of February 2012. The resulting where clause is



DECLARE @p0 DateTime = '2012-02-01 00:00:00.000'
DECLARE @p1 DateTime = '2012-02-29 23:59:59.999'
....
WHERE (CONVERT(DATE, [t0].[DatePlaced]) >= @p0) AND (CONVERT(DATE, [t0].[DatePlaced]) <= @p1)


When this runs I'm getting results for 3/1/2012 showing up as well as all the results for 2/2012.



If I change the where clause to use BETWEEN then the results only contain dates for February.



WHERE [t0].[DatePlaced] BETWEEN @p0 AND @p1


I'm using .net 4 and SQL Server 2008 R2 with and without SP1.



Switching the dates to 3/1/2011 and my query's end date to '2011-02-28 23:59:59.999' yielded the same results.



Is there another way to get the results for just 2/2012 aside from using BETWEEN which LINQ 2 SQL doesn't support?










share|improve this question


























    up vote
    0
    down vote

    favorite












    I have a LINQ 2 SQL query that's getting me a list of results for the month of February 2012. The resulting where clause is



    DECLARE @p0 DateTime = '2012-02-01 00:00:00.000'
    DECLARE @p1 DateTime = '2012-02-29 23:59:59.999'
    ....
    WHERE (CONVERT(DATE, [t0].[DatePlaced]) >= @p0) AND (CONVERT(DATE, [t0].[DatePlaced]) <= @p1)


    When this runs I'm getting results for 3/1/2012 showing up as well as all the results for 2/2012.



    If I change the where clause to use BETWEEN then the results only contain dates for February.



    WHERE [t0].[DatePlaced] BETWEEN @p0 AND @p1


    I'm using .net 4 and SQL Server 2008 R2 with and without SP1.



    Switching the dates to 3/1/2011 and my query's end date to '2011-02-28 23:59:59.999' yielded the same results.



    Is there another way to get the results for just 2/2012 aside from using BETWEEN which LINQ 2 SQL doesn't support?










    share|improve this question
























      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      I have a LINQ 2 SQL query that's getting me a list of results for the month of February 2012. The resulting where clause is



      DECLARE @p0 DateTime = '2012-02-01 00:00:00.000'
      DECLARE @p1 DateTime = '2012-02-29 23:59:59.999'
      ....
      WHERE (CONVERT(DATE, [t0].[DatePlaced]) >= @p0) AND (CONVERT(DATE, [t0].[DatePlaced]) <= @p1)


      When this runs I'm getting results for 3/1/2012 showing up as well as all the results for 2/2012.



      If I change the where clause to use BETWEEN then the results only contain dates for February.



      WHERE [t0].[DatePlaced] BETWEEN @p0 AND @p1


      I'm using .net 4 and SQL Server 2008 R2 with and without SP1.



      Switching the dates to 3/1/2011 and my query's end date to '2011-02-28 23:59:59.999' yielded the same results.



      Is there another way to get the results for just 2/2012 aside from using BETWEEN which LINQ 2 SQL doesn't support?










      share|improve this question













      I have a LINQ 2 SQL query that's getting me a list of results for the month of February 2012. The resulting where clause is



      DECLARE @p0 DateTime = '2012-02-01 00:00:00.000'
      DECLARE @p1 DateTime = '2012-02-29 23:59:59.999'
      ....
      WHERE (CONVERT(DATE, [t0].[DatePlaced]) >= @p0) AND (CONVERT(DATE, [t0].[DatePlaced]) <= @p1)


      When this runs I'm getting results for 3/1/2012 showing up as well as all the results for 2/2012.



      If I change the where clause to use BETWEEN then the results only contain dates for February.



      WHERE [t0].[DatePlaced] BETWEEN @p0 AND @p1


      I'm using .net 4 and SQL Server 2008 R2 with and without SP1.



      Switching the dates to 3/1/2011 and my query's end date to '2011-02-28 23:59:59.999' yielded the same results.



      Is there another way to get the results for just 2/2012 aside from using BETWEEN which LINQ 2 SQL doesn't support?







      linq-to-sql datetime sql-server-2008-r2






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Mar 1 '12 at 21:06









      Brian Surowiec

      9,88063463




      9,88063463
























          3 Answers
          3






          active

          oldest

          votes

















          up vote
          4
          down vote



          accepted










          .999 rounds up to midnight of the next day. You can check this:



          DECLARE @p1 DateTime = '2012-02-29 23:59:59.999';
          SELECT @p1;


          What do you get?



          Instead of trying to figure out the last instant of today (which will be different depending on the data type and precision), what you want instead is an open-ended date range:



          DECLARE @p0 DATE = '2012-02-01',
          @p1 DATE = '2012-03-01';
          ....
          WHERE [t0].[DatePlaced] >= @p0
          AND [t0].[DatePlaced] < @p1


          Even easier would be to just pass in the starting date and say:



          DECLARE @p0 DATE = '2012-02-01';

          ....
          WHERE [t0].DatePlaced >= @p0
          AND [t0].DatePlaced < DATEADD(MONTH, 1, @p0)


          For some elaborate ideas about datetime best practices:




          • Bad habits to kick : mis-handling date / range queries


          For some info on why BETWEEN (and by extension >= AND <=) is evil:




          • What do BETWEEN and the devil have in common?






          share|improve this answer






























            up vote
            3
            down vote













            If you need to select by month often, you could consider adding two computed columns to your table - one for the month, one for the year:



            ALTER TABLE dbo.YourTable
            ADD DatePlacedYear AS YEAR(DatePlaced) PERSISTED

            ALTER TABLE dbo.YourTable
            ADD DatePlacedMonth AS MONTH(DatePlaced) PERSISTED


            Those two new columns are automatically computed by SQL Server, they're persisted (e.g. part of the table's storage), and you can even put an index on them, if that makes sense for you.



            With those in place, you could now use a query like:



            SELECT (columns)
            FROM dbo.YourTable
            WHERE DatePlacedYear = 2012 AND DatePlacedMonth = 2


            to get all data from February 2012.



            It's a classic space-vs-speed trade-off - by storing the two extra columns for each row, you need more space - but in return, querying gets easier and if you have an index on (DatePlacedYear, DatePlacedMonth), your queries should (ideally) be quite fast.






            share|improve this answer





















            • Instead of adding computed columns I simply compared against the Month and Year parts of the date. I'm sure there's a performance trade off but it's only for internal reporting so that's not much of an issue right now.
              – Brian Surowiec
              Mar 11 '12 at 4:47




















            up vote
            0
            down vote













            Instead of using AddMilliseconds(-1) try use AddMilliseconds(-3)



            See this question how SQL Server treats the milliseconds






            share|improve this answer



















            • 2




              Relying on milliseconds is problematic. What if the underlying data type is converted to SMALLDATETIME? Now your result rounds up again. What if it is converted to DATETIME2(>2)? Now the end of your range is actually before the end of the day, and you could theoretically miss data. An open-ended date range is really the only future-proof way to get a whole day's worth of data.
              – Aaron Bertrand
              Mar 2 '12 at 0:14













            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














             

            draft saved


            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f9524086%2fincorrect-date-comparison-results-in-sql-server-2008-r2%23new-answer', 'question_page');
            }
            );

            Post as a guest
































            3 Answers
            3






            active

            oldest

            votes








            3 Answers
            3






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            4
            down vote



            accepted










            .999 rounds up to midnight of the next day. You can check this:



            DECLARE @p1 DateTime = '2012-02-29 23:59:59.999';
            SELECT @p1;


            What do you get?



            Instead of trying to figure out the last instant of today (which will be different depending on the data type and precision), what you want instead is an open-ended date range:



            DECLARE @p0 DATE = '2012-02-01',
            @p1 DATE = '2012-03-01';
            ....
            WHERE [t0].[DatePlaced] >= @p0
            AND [t0].[DatePlaced] < @p1


            Even easier would be to just pass in the starting date and say:



            DECLARE @p0 DATE = '2012-02-01';

            ....
            WHERE [t0].DatePlaced >= @p0
            AND [t0].DatePlaced < DATEADD(MONTH, 1, @p0)


            For some elaborate ideas about datetime best practices:




            • Bad habits to kick : mis-handling date / range queries


            For some info on why BETWEEN (and by extension >= AND <=) is evil:




            • What do BETWEEN and the devil have in common?






            share|improve this answer



























              up vote
              4
              down vote



              accepted










              .999 rounds up to midnight of the next day. You can check this:



              DECLARE @p1 DateTime = '2012-02-29 23:59:59.999';
              SELECT @p1;


              What do you get?



              Instead of trying to figure out the last instant of today (which will be different depending on the data type and precision), what you want instead is an open-ended date range:



              DECLARE @p0 DATE = '2012-02-01',
              @p1 DATE = '2012-03-01';
              ....
              WHERE [t0].[DatePlaced] >= @p0
              AND [t0].[DatePlaced] < @p1


              Even easier would be to just pass in the starting date and say:



              DECLARE @p0 DATE = '2012-02-01';

              ....
              WHERE [t0].DatePlaced >= @p0
              AND [t0].DatePlaced < DATEADD(MONTH, 1, @p0)


              For some elaborate ideas about datetime best practices:




              • Bad habits to kick : mis-handling date / range queries


              For some info on why BETWEEN (and by extension >= AND <=) is evil:




              • What do BETWEEN and the devil have in common?






              share|improve this answer

























                up vote
                4
                down vote



                accepted







                up vote
                4
                down vote



                accepted






                .999 rounds up to midnight of the next day. You can check this:



                DECLARE @p1 DateTime = '2012-02-29 23:59:59.999';
                SELECT @p1;


                What do you get?



                Instead of trying to figure out the last instant of today (which will be different depending on the data type and precision), what you want instead is an open-ended date range:



                DECLARE @p0 DATE = '2012-02-01',
                @p1 DATE = '2012-03-01';
                ....
                WHERE [t0].[DatePlaced] >= @p0
                AND [t0].[DatePlaced] < @p1


                Even easier would be to just pass in the starting date and say:



                DECLARE @p0 DATE = '2012-02-01';

                ....
                WHERE [t0].DatePlaced >= @p0
                AND [t0].DatePlaced < DATEADD(MONTH, 1, @p0)


                For some elaborate ideas about datetime best practices:




                • Bad habits to kick : mis-handling date / range queries


                For some info on why BETWEEN (and by extension >= AND <=) is evil:




                • What do BETWEEN and the devil have in common?






                share|improve this answer














                .999 rounds up to midnight of the next day. You can check this:



                DECLARE @p1 DateTime = '2012-02-29 23:59:59.999';
                SELECT @p1;


                What do you get?



                Instead of trying to figure out the last instant of today (which will be different depending on the data type and precision), what you want instead is an open-ended date range:



                DECLARE @p0 DATE = '2012-02-01',
                @p1 DATE = '2012-03-01';
                ....
                WHERE [t0].[DatePlaced] >= @p0
                AND [t0].[DatePlaced] < @p1


                Even easier would be to just pass in the starting date and say:



                DECLARE @p0 DATE = '2012-02-01';

                ....
                WHERE [t0].DatePlaced >= @p0
                AND [t0].DatePlaced < DATEADD(MONTH, 1, @p0)


                For some elaborate ideas about datetime best practices:




                • Bad habits to kick : mis-handling date / range queries


                For some info on why BETWEEN (and by extension >= AND <=) is evil:




                • What do BETWEEN and the devil have in common?







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Nov 10 at 16:18

























                answered Mar 1 '12 at 21:31









                Aaron Bertrand

                205k27357401




                205k27357401
























                    up vote
                    3
                    down vote













                    If you need to select by month often, you could consider adding two computed columns to your table - one for the month, one for the year:



                    ALTER TABLE dbo.YourTable
                    ADD DatePlacedYear AS YEAR(DatePlaced) PERSISTED

                    ALTER TABLE dbo.YourTable
                    ADD DatePlacedMonth AS MONTH(DatePlaced) PERSISTED


                    Those two new columns are automatically computed by SQL Server, they're persisted (e.g. part of the table's storage), and you can even put an index on them, if that makes sense for you.



                    With those in place, you could now use a query like:



                    SELECT (columns)
                    FROM dbo.YourTable
                    WHERE DatePlacedYear = 2012 AND DatePlacedMonth = 2


                    to get all data from February 2012.



                    It's a classic space-vs-speed trade-off - by storing the two extra columns for each row, you need more space - but in return, querying gets easier and if you have an index on (DatePlacedYear, DatePlacedMonth), your queries should (ideally) be quite fast.






                    share|improve this answer





















                    • Instead of adding computed columns I simply compared against the Month and Year parts of the date. I'm sure there's a performance trade off but it's only for internal reporting so that's not much of an issue right now.
                      – Brian Surowiec
                      Mar 11 '12 at 4:47

















                    up vote
                    3
                    down vote













                    If you need to select by month often, you could consider adding two computed columns to your table - one for the month, one for the year:



                    ALTER TABLE dbo.YourTable
                    ADD DatePlacedYear AS YEAR(DatePlaced) PERSISTED

                    ALTER TABLE dbo.YourTable
                    ADD DatePlacedMonth AS MONTH(DatePlaced) PERSISTED


                    Those two new columns are automatically computed by SQL Server, they're persisted (e.g. part of the table's storage), and you can even put an index on them, if that makes sense for you.



                    With those in place, you could now use a query like:



                    SELECT (columns)
                    FROM dbo.YourTable
                    WHERE DatePlacedYear = 2012 AND DatePlacedMonth = 2


                    to get all data from February 2012.



                    It's a classic space-vs-speed trade-off - by storing the two extra columns for each row, you need more space - but in return, querying gets easier and if you have an index on (DatePlacedYear, DatePlacedMonth), your queries should (ideally) be quite fast.






                    share|improve this answer





















                    • Instead of adding computed columns I simply compared against the Month and Year parts of the date. I'm sure there's a performance trade off but it's only for internal reporting so that's not much of an issue right now.
                      – Brian Surowiec
                      Mar 11 '12 at 4:47















                    up vote
                    3
                    down vote










                    up vote
                    3
                    down vote









                    If you need to select by month often, you could consider adding two computed columns to your table - one for the month, one for the year:



                    ALTER TABLE dbo.YourTable
                    ADD DatePlacedYear AS YEAR(DatePlaced) PERSISTED

                    ALTER TABLE dbo.YourTable
                    ADD DatePlacedMonth AS MONTH(DatePlaced) PERSISTED


                    Those two new columns are automatically computed by SQL Server, they're persisted (e.g. part of the table's storage), and you can even put an index on them, if that makes sense for you.



                    With those in place, you could now use a query like:



                    SELECT (columns)
                    FROM dbo.YourTable
                    WHERE DatePlacedYear = 2012 AND DatePlacedMonth = 2


                    to get all data from February 2012.



                    It's a classic space-vs-speed trade-off - by storing the two extra columns for each row, you need more space - but in return, querying gets easier and if you have an index on (DatePlacedYear, DatePlacedMonth), your queries should (ideally) be quite fast.






                    share|improve this answer












                    If you need to select by month often, you could consider adding two computed columns to your table - one for the month, one for the year:



                    ALTER TABLE dbo.YourTable
                    ADD DatePlacedYear AS YEAR(DatePlaced) PERSISTED

                    ALTER TABLE dbo.YourTable
                    ADD DatePlacedMonth AS MONTH(DatePlaced) PERSISTED


                    Those two new columns are automatically computed by SQL Server, they're persisted (e.g. part of the table's storage), and you can even put an index on them, if that makes sense for you.



                    With those in place, you could now use a query like:



                    SELECT (columns)
                    FROM dbo.YourTable
                    WHERE DatePlacedYear = 2012 AND DatePlacedMonth = 2


                    to get all data from February 2012.



                    It's a classic space-vs-speed trade-off - by storing the two extra columns for each row, you need more space - but in return, querying gets easier and if you have an index on (DatePlacedYear, DatePlacedMonth), your queries should (ideally) be quite fast.







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Mar 1 '12 at 21:25









                    marc_s

                    564k12510891242




                    564k12510891242












                    • Instead of adding computed columns I simply compared against the Month and Year parts of the date. I'm sure there's a performance trade off but it's only for internal reporting so that's not much of an issue right now.
                      – Brian Surowiec
                      Mar 11 '12 at 4:47




















                    • Instead of adding computed columns I simply compared against the Month and Year parts of the date. I'm sure there's a performance trade off but it's only for internal reporting so that's not much of an issue right now.
                      – Brian Surowiec
                      Mar 11 '12 at 4:47


















                    Instead of adding computed columns I simply compared against the Month and Year parts of the date. I'm sure there's a performance trade off but it's only for internal reporting so that's not much of an issue right now.
                    – Brian Surowiec
                    Mar 11 '12 at 4:47






                    Instead of adding computed columns I simply compared against the Month and Year parts of the date. I'm sure there's a performance trade off but it's only for internal reporting so that's not much of an issue right now.
                    – Brian Surowiec
                    Mar 11 '12 at 4:47












                    up vote
                    0
                    down vote













                    Instead of using AddMilliseconds(-1) try use AddMilliseconds(-3)



                    See this question how SQL Server treats the milliseconds






                    share|improve this answer



















                    • 2




                      Relying on milliseconds is problematic. What if the underlying data type is converted to SMALLDATETIME? Now your result rounds up again. What if it is converted to DATETIME2(>2)? Now the end of your range is actually before the end of the day, and you could theoretically miss data. An open-ended date range is really the only future-proof way to get a whole day's worth of data.
                      – Aaron Bertrand
                      Mar 2 '12 at 0:14

















                    up vote
                    0
                    down vote













                    Instead of using AddMilliseconds(-1) try use AddMilliseconds(-3)



                    See this question how SQL Server treats the milliseconds






                    share|improve this answer



















                    • 2




                      Relying on milliseconds is problematic. What if the underlying data type is converted to SMALLDATETIME? Now your result rounds up again. What if it is converted to DATETIME2(>2)? Now the end of your range is actually before the end of the day, and you could theoretically miss data. An open-ended date range is really the only future-proof way to get a whole day's worth of data.
                      – Aaron Bertrand
                      Mar 2 '12 at 0:14















                    up vote
                    0
                    down vote










                    up vote
                    0
                    down vote









                    Instead of using AddMilliseconds(-1) try use AddMilliseconds(-3)



                    See this question how SQL Server treats the milliseconds






                    share|improve this answer














                    Instead of using AddMilliseconds(-1) try use AddMilliseconds(-3)



                    See this question how SQL Server treats the milliseconds







                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited May 23 '17 at 10:34









                    Community

                    11




                    11










                    answered Mar 1 '12 at 21:34









                    Adrian Iftode

                    13.3k23465




                    13.3k23465








                    • 2




                      Relying on milliseconds is problematic. What if the underlying data type is converted to SMALLDATETIME? Now your result rounds up again. What if it is converted to DATETIME2(>2)? Now the end of your range is actually before the end of the day, and you could theoretically miss data. An open-ended date range is really the only future-proof way to get a whole day's worth of data.
                      – Aaron Bertrand
                      Mar 2 '12 at 0:14
















                    • 2




                      Relying on milliseconds is problematic. What if the underlying data type is converted to SMALLDATETIME? Now your result rounds up again. What if it is converted to DATETIME2(>2)? Now the end of your range is actually before the end of the day, and you could theoretically miss data. An open-ended date range is really the only future-proof way to get a whole day's worth of data.
                      – Aaron Bertrand
                      Mar 2 '12 at 0:14










                    2




                    2




                    Relying on milliseconds is problematic. What if the underlying data type is converted to SMALLDATETIME? Now your result rounds up again. What if it is converted to DATETIME2(>2)? Now the end of your range is actually before the end of the day, and you could theoretically miss data. An open-ended date range is really the only future-proof way to get a whole day's worth of data.
                    – Aaron Bertrand
                    Mar 2 '12 at 0:14






                    Relying on milliseconds is problematic. What if the underlying data type is converted to SMALLDATETIME? Now your result rounds up again. What if it is converted to DATETIME2(>2)? Now the end of your range is actually before the end of the day, and you could theoretically miss data. An open-ended date range is really the only future-proof way to get a whole day's worth of data.
                    – Aaron Bertrand
                    Mar 2 '12 at 0:14




















                     

                    draft saved


                    draft discarded



















































                     


                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f9524086%2fincorrect-date-comparison-results-in-sql-server-2008-r2%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest




















































































                    Popular posts from this blog

                    Xamarin.iOS Cant Deploy on Iphone

                    Glorious Revolution

                    Dulmage-Mendelsohn matrix decomposition in Python