What is the best way to rebuild a date from integer inputs?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP












7















I've got a bunch of financial reports, and we want to be able to pass them two inputs (year and quarter) as variables.



I'm doing it this way, but I really don't like it:



 declare @quarter int,
@year int,
@date date

set @quarter = 4
set @year = 2018


set @date = cast(@year as varchar(4)) + '-01-01'
set @date = dateadd(quarter, @quarter - 1, @date)


print @date


Question What is the best way to reconstruct a date from integer inputs?



desired result:



 2018-10-01









share|improve this question




























    7















    I've got a bunch of financial reports, and we want to be able to pass them two inputs (year and quarter) as variables.



    I'm doing it this way, but I really don't like it:



     declare @quarter int,
    @year int,
    @date date

    set @quarter = 4
    set @year = 2018


    set @date = cast(@year as varchar(4)) + '-01-01'
    set @date = dateadd(quarter, @quarter - 1, @date)


    print @date


    Question What is the best way to reconstruct a date from integer inputs?



    desired result:



     2018-10-01









    share|improve this question


























      7












      7








      7


      1






      I've got a bunch of financial reports, and we want to be able to pass them two inputs (year and quarter) as variables.



      I'm doing it this way, but I really don't like it:



       declare @quarter int,
      @year int,
      @date date

      set @quarter = 4
      set @year = 2018


      set @date = cast(@year as varchar(4)) + '-01-01'
      set @date = dateadd(quarter, @quarter - 1, @date)


      print @date


      Question What is the best way to reconstruct a date from integer inputs?



      desired result:



       2018-10-01









      share|improve this question
















      I've got a bunch of financial reports, and we want to be able to pass them two inputs (year and quarter) as variables.



      I'm doing it this way, but I really don't like it:



       declare @quarter int,
      @year int,
      @date date

      set @quarter = 4
      set @year = 2018


      set @date = cast(@year as varchar(4)) + '-01-01'
      set @date = dateadd(quarter, @quarter - 1, @date)


      print @date


      Question What is the best way to reconstruct a date from integer inputs?



      desired result:



       2018-10-01






      sql-server-2008-r2






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Jan 10 at 21:47







      James

















      asked Jan 10 at 21:39









      JamesJames

      1,069728




      1,069728




















          4 Answers
          4






          active

          oldest

          votes


















          11














          How about



          declare @quarter int = 4
          declare @year int = 2018

          select datefromparts(@year,(@quarter-1)*3+1,1)


          or if you're still using SQL 2008:



          select dateadd(month,(@quarter-1)*3,dateadd(year, @year-2018,'20180101'))





          share|improve this answer






























            9














            Let me suggest to NOT use a date separator like '-' or '/', it deppends on regional settings, use YYYYMMDD format.



            declare @quarter int,
            @year int,
            @date date

            set @quarter = 4
            set @year = 2018


            set @date = cast(@year as varchar(4)) + '0101'
            set @date = dateadd(quarter, 1 - 1, @date)
            print @date

            set @date = cast(@year as varchar(4)) + '0101'
            set @date = dateadd(quarter, 2 - 1, @date)
            print @date

            set @date = cast(@year as varchar(4)) + '0101'
            set @date = dateadd(quarter, 3 - 1, @date)
            print @date

            set @date = cast(@year as varchar(4)) + '0101'
            set @date = dateadd(quarter, 4 - 1, @date)
            print @date




            2018-01-01
            2018-04-01
            2018-07-01
            2018-10-01


            db<>fiddle here






            share|improve this answer


















            • 3





              My understanding was, that '2018-10-01' is independent of regional settings and will always be parsed correctly by SQL Server. Isn't that true?

              – a_horse_with_no_name
              Jan 11 at 7:03











            • @a_horse_with_no_name it should due it is ISO 8601, but at least in my company where we use a mixed-language installation of SQL servers (English, Spanish) I ended using the less unambiguous format YYYYMMDD HH:MM:SS to avoid date conversion issues.

              – McNets
              Jan 11 at 8:24






            • 5





              @a_horse_with_no_name - This is correct for the newer temporal datatypes (e.g. date and datetime2) but not for the legacy datetime type. So as the questioner is casting to date the format is fine in this case

              – Martin Smith
              Jan 11 at 11:17






            • 1





              @MartinSmith: thanks for the clarification

              – a_horse_with_no_name
              Jan 11 at 11:42











            • "2001-08-12" isn't always interpreted in the way you would expect. I never worked out how but in our development environment it would interpret it as yyyy-dd-mm, and throw an out of range error for "2001-08-13". I try to avoid string-to-date conversion at all, and where it is necessary I make sure to use a month name - "12 aug 2001" is unambiguous.

              – IanF1
              Jan 19 at 18:47


















            4














            You could Create a date dimension or calendar table in SQL Server and query it



            --demo setup 
            drop table if exists #dim
            DECLARE @StartDate DATE = '20000101', @NumberOfYears INT = 30;

            -- prevent set or regional settings from interfering with
            -- interpretation of dates / literals

            SET DATEFIRST 7;
            SET DATEFORMAT mdy;
            SET LANGUAGE US_ENGLISH;

            DECLARE @CutoffDate DATE = DATEADD(YEAR, @NumberOfYears, @StartDate);

            -- this is just a holding table for intermediate calculations:

            CREATE TABLE #dim
            (
            [date] DATE PRIMARY KEY,
            [day] AS DATEPART(DAY, [date]),
            [month] AS DATEPART(MONTH, [date]),
            FirstOfMonth AS CONVERT(DATE, DATEADD(MONTH, DATEDIFF(MONTH, 0, [date]), 0)),
            [MonthName] AS DATENAME(MONTH, [date]),
            [week] AS DATEPART(WEEK, [date]),
            [ISOweek] AS DATEPART(ISO_WEEK, [date]),
            [DayOfWeek] AS DATEPART(WEEKDAY, [date]),
            [quarter] AS DATEPART(QUARTER, [date]),
            [year] AS DATEPART(YEAR, [date]),
            FirstOfYear AS CONVERT(DATE, DATEADD(YEAR, DATEDIFF(YEAR, 0, [date]), 0)),
            Style112 AS CONVERT(CHAR(8), [date], 112),
            Style101 AS CONVERT(CHAR(10), [date], 101)
            );

            -- use the catalog views to generate as many rows as we need

            INSERT #dim([date])
            SELECT d
            FROM
            (
            SELECT d = DATEADD(DAY, rn - 1, @StartDate)
            FROM
            (
            SELECT TOP (DATEDIFF(DAY, @StartDate, @CutoffDate))
            rn = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
            FROM sys.all_objects AS s1
            CROSS JOIN sys.all_objects AS s2
            -- on my system this would support > 5 million days
            ORDER BY s1.[object_id]
            ) AS x
            ) AS y;

            drop table if exists dbo.DateDimension

            CREATE TABLE dbo.DateDimension
            (
            --DateKey INT NOT NULL PRIMARY KEY,
            [Date] DATE NOT NULL,
            [Day] TINYINT NOT NULL,
            DaySuffix CHAR(2) NOT NULL,
            [Weekday] TINYINT NOT NULL,
            WeekDayName VARCHAR(10) NOT NULL,
            IsWeekend BIT NOT NULL,
            IsHoliday BIT NOT NULL,
            HolidayText VARCHAR(64) SPARSE,
            DOWInMonth TINYINT NOT NULL,
            [DayOfYear] SMALLINT NOT NULL,
            WeekOfMonth TINYINT NOT NULL,
            WeekOfYear TINYINT NOT NULL,
            ISOWeekOfYear TINYINT NOT NULL,
            [Month] TINYINT NOT NULL,
            [MonthName] VARCHAR(10) NOT NULL,
            [Quarter] TINYINT NOT NULL,
            QuarterName VARCHAR(6) NOT NULL,
            [Year] INT NOT NULL,
            MMYYYY CHAR(6) NOT NULL,
            MonthYear CHAR(7) NOT NULL,
            FirstDayOfMonth DATE NOT NULL,
            LastDayOfMonth DATE NOT NULL,
            FirstDayOfQuarter DATE NOT NULL,
            LastDayOfQuarter DATE NOT NULL,
            FirstDayOfYear DATE NOT NULL,
            LastDayOfYear DATE NOT NULL,
            FirstDayOfNextMonth DATE NOT NULL,
            FirstDayOfNextYear DATE NOT NULL
            );
            INSERT dbo.DateDimension WITH (TABLOCKX)
            SELECT
            --DateKey = CONVERT(INT, Style112),
            [Date] = [date],
            [Day] = CONVERT(TINYINT, [day]),
            DaySuffix = CONVERT(CHAR(2), CASE WHEN [day] / 10 = 1 THEN 'th' ELSE
            CASE RIGHT([day], 1) WHEN '1' THEN 'st' WHEN '2' THEN 'nd'
            WHEN '3' THEN 'rd' ELSE 'th' END END),
            [Weekday] = CONVERT(TINYINT, [DayOfWeek]),
            [WeekDayName] = CONVERT(VARCHAR(10), DATENAME(WEEKDAY, [date])),
            [IsWeekend] = CONVERT(BIT, CASE WHEN [DayOfWeek] IN (1,7) THEN 1 ELSE 0 END),
            [IsHoliday] = CONVERT(BIT, 0),
            HolidayText = CONVERT(VARCHAR(64), NULL),
            [DOWInMonth] = CONVERT(TINYINT, ROW_NUMBER() OVER
            (PARTITION BY FirstOfMonth, [DayOfWeek] ORDER BY [date])),
            [DayOfYear] = CONVERT(SMALLINT, DATEPART(DAYOFYEAR, [date])),
            WeekOfMonth = CONVERT(TINYINT, DENSE_RANK() OVER
            (PARTITION BY [year], [month] ORDER BY [week])),
            WeekOfYear = CONVERT(TINYINT, [week]),
            ISOWeekOfYear = CONVERT(TINYINT, ISOWeek),
            [Month] = CONVERT(TINYINT, [month]),
            [MonthName] = CONVERT(VARCHAR(10), [MonthName]),
            [Quarter] = CONVERT(TINYINT, [quarter]),
            QuarterName = CONVERT(VARCHAR(6), CASE [quarter] WHEN 1 THEN 'First'
            WHEN 2 THEN 'Second' WHEN 3 THEN 'Third' WHEN 4 THEN 'Fourth' END),
            [Year] = [year],
            MMYYYY = CONVERT(CHAR(6), LEFT(Style101, 2) + LEFT(Style112, 4)),
            MonthYear = CONVERT(CHAR(7), LEFT([MonthName], 3) + LEFT(Style112, 4)),
            FirstDayOfMonth = FirstOfMonth,
            LastDayOfMonth = MAX([date]) OVER (PARTITION BY [year], [month]),
            FirstDayOfQuarter = MIN([date]) OVER (PARTITION BY [year], [quarter]),
            LastDayOfQuarter = MAX([date]) OVER (PARTITION BY [year], [quarter]),
            FirstDayOfYear = FirstOfYear,
            LastDayOfYear = MAX([date]) OVER (PARTITION BY [year]),
            FirstDayOfNextMonth = DATEADD(MONTH, 1, FirstOfMonth),
            FirstDayOfNextYear = DATEADD(YEAR, 1, FirstOfYear)
            FROM #dim
            OPTION (MAXDOP 1);



            --solution
            SELECT min(Date)
            FROM [Test].[dbo].[DateDimension]
            where [year] = 2018 and [Quarter]=4



            | Date |
            |------------|
            | 2018-10-01 |





            share|improve this answer


















            • 1





              This is the right way to do it - this way we can index the date parts, so it will be a bazillion times faster to join to DateDimension than to put a function on a column in the where clause.

              – James
              Jan 11 at 15:41


















            3














            I would avoid using strings at all but use date arithmetic combined with a known (or even unknown!) zero epoch.



            DECLARE @epoch DATE = CONVERT(DATETIME, 0);
            /* for some reason SQL Server let's you cast int to datetime but not to date, the above casts via datetime (second cast implicit) */

            SET @date = DATEADD(MONTH, (@quarter-1)*3, DATEADD(YEAR, @year - YEAR(@epoch), @epoch));


            This avoids string to date comparison which is messy, culture-dependent and expensive.






            share|improve this answer
























              Your Answer








              StackExchange.ready(function()
              var channelOptions =
              tags: "".split(" "),
              id: "182"
              ;
              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',
              autoActivateHeartbeat: false,
              convertImagesToLinks: false,
              noModals: true,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: null,
              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%2fdba.stackexchange.com%2fquestions%2f226838%2fwhat-is-the-best-way-to-rebuild-a-date-from-integer-inputs%23new-answer', 'question_page');

              );

              Post as a guest















              Required, but never shown

























              4 Answers
              4






              active

              oldest

              votes








              4 Answers
              4






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes









              11














              How about



              declare @quarter int = 4
              declare @year int = 2018

              select datefromparts(@year,(@quarter-1)*3+1,1)


              or if you're still using SQL 2008:



              select dateadd(month,(@quarter-1)*3,dateadd(year, @year-2018,'20180101'))





              share|improve this answer



























                11














                How about



                declare @quarter int = 4
                declare @year int = 2018

                select datefromparts(@year,(@quarter-1)*3+1,1)


                or if you're still using SQL 2008:



                select dateadd(month,(@quarter-1)*3,dateadd(year, @year-2018,'20180101'))





                share|improve this answer

























                  11












                  11








                  11







                  How about



                  declare @quarter int = 4
                  declare @year int = 2018

                  select datefromparts(@year,(@quarter-1)*3+1,1)


                  or if you're still using SQL 2008:



                  select dateadd(month,(@quarter-1)*3,dateadd(year, @year-2018,'20180101'))





                  share|improve this answer













                  How about



                  declare @quarter int = 4
                  declare @year int = 2018

                  select datefromparts(@year,(@quarter-1)*3+1,1)


                  or if you're still using SQL 2008:



                  select dateadd(month,(@quarter-1)*3,dateadd(year, @year-2018,'20180101'))






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Jan 10 at 21:49









                  David Browne - MicrosoftDavid Browne - Microsoft

                  10.9k728




                  10.9k728























                      9














                      Let me suggest to NOT use a date separator like '-' or '/', it deppends on regional settings, use YYYYMMDD format.



                      declare @quarter int,
                      @year int,
                      @date date

                      set @quarter = 4
                      set @year = 2018


                      set @date = cast(@year as varchar(4)) + '0101'
                      set @date = dateadd(quarter, 1 - 1, @date)
                      print @date

                      set @date = cast(@year as varchar(4)) + '0101'
                      set @date = dateadd(quarter, 2 - 1, @date)
                      print @date

                      set @date = cast(@year as varchar(4)) + '0101'
                      set @date = dateadd(quarter, 3 - 1, @date)
                      print @date

                      set @date = cast(@year as varchar(4)) + '0101'
                      set @date = dateadd(quarter, 4 - 1, @date)
                      print @date




                      2018-01-01
                      2018-04-01
                      2018-07-01
                      2018-10-01


                      db<>fiddle here






                      share|improve this answer


















                      • 3





                        My understanding was, that '2018-10-01' is independent of regional settings and will always be parsed correctly by SQL Server. Isn't that true?

                        – a_horse_with_no_name
                        Jan 11 at 7:03











                      • @a_horse_with_no_name it should due it is ISO 8601, but at least in my company where we use a mixed-language installation of SQL servers (English, Spanish) I ended using the less unambiguous format YYYYMMDD HH:MM:SS to avoid date conversion issues.

                        – McNets
                        Jan 11 at 8:24






                      • 5





                        @a_horse_with_no_name - This is correct for the newer temporal datatypes (e.g. date and datetime2) but not for the legacy datetime type. So as the questioner is casting to date the format is fine in this case

                        – Martin Smith
                        Jan 11 at 11:17






                      • 1





                        @MartinSmith: thanks for the clarification

                        – a_horse_with_no_name
                        Jan 11 at 11:42











                      • "2001-08-12" isn't always interpreted in the way you would expect. I never worked out how but in our development environment it would interpret it as yyyy-dd-mm, and throw an out of range error for "2001-08-13". I try to avoid string-to-date conversion at all, and where it is necessary I make sure to use a month name - "12 aug 2001" is unambiguous.

                        – IanF1
                        Jan 19 at 18:47















                      9














                      Let me suggest to NOT use a date separator like '-' or '/', it deppends on regional settings, use YYYYMMDD format.



                      declare @quarter int,
                      @year int,
                      @date date

                      set @quarter = 4
                      set @year = 2018


                      set @date = cast(@year as varchar(4)) + '0101'
                      set @date = dateadd(quarter, 1 - 1, @date)
                      print @date

                      set @date = cast(@year as varchar(4)) + '0101'
                      set @date = dateadd(quarter, 2 - 1, @date)
                      print @date

                      set @date = cast(@year as varchar(4)) + '0101'
                      set @date = dateadd(quarter, 3 - 1, @date)
                      print @date

                      set @date = cast(@year as varchar(4)) + '0101'
                      set @date = dateadd(quarter, 4 - 1, @date)
                      print @date




                      2018-01-01
                      2018-04-01
                      2018-07-01
                      2018-10-01


                      db<>fiddle here






                      share|improve this answer


















                      • 3





                        My understanding was, that '2018-10-01' is independent of regional settings and will always be parsed correctly by SQL Server. Isn't that true?

                        – a_horse_with_no_name
                        Jan 11 at 7:03











                      • @a_horse_with_no_name it should due it is ISO 8601, but at least in my company where we use a mixed-language installation of SQL servers (English, Spanish) I ended using the less unambiguous format YYYYMMDD HH:MM:SS to avoid date conversion issues.

                        – McNets
                        Jan 11 at 8:24






                      • 5





                        @a_horse_with_no_name - This is correct for the newer temporal datatypes (e.g. date and datetime2) but not for the legacy datetime type. So as the questioner is casting to date the format is fine in this case

                        – Martin Smith
                        Jan 11 at 11:17






                      • 1





                        @MartinSmith: thanks for the clarification

                        – a_horse_with_no_name
                        Jan 11 at 11:42











                      • "2001-08-12" isn't always interpreted in the way you would expect. I never worked out how but in our development environment it would interpret it as yyyy-dd-mm, and throw an out of range error for "2001-08-13". I try to avoid string-to-date conversion at all, and where it is necessary I make sure to use a month name - "12 aug 2001" is unambiguous.

                        – IanF1
                        Jan 19 at 18:47













                      9












                      9








                      9







                      Let me suggest to NOT use a date separator like '-' or '/', it deppends on regional settings, use YYYYMMDD format.



                      declare @quarter int,
                      @year int,
                      @date date

                      set @quarter = 4
                      set @year = 2018


                      set @date = cast(@year as varchar(4)) + '0101'
                      set @date = dateadd(quarter, 1 - 1, @date)
                      print @date

                      set @date = cast(@year as varchar(4)) + '0101'
                      set @date = dateadd(quarter, 2 - 1, @date)
                      print @date

                      set @date = cast(@year as varchar(4)) + '0101'
                      set @date = dateadd(quarter, 3 - 1, @date)
                      print @date

                      set @date = cast(@year as varchar(4)) + '0101'
                      set @date = dateadd(quarter, 4 - 1, @date)
                      print @date




                      2018-01-01
                      2018-04-01
                      2018-07-01
                      2018-10-01


                      db<>fiddle here






                      share|improve this answer













                      Let me suggest to NOT use a date separator like '-' or '/', it deppends on regional settings, use YYYYMMDD format.



                      declare @quarter int,
                      @year int,
                      @date date

                      set @quarter = 4
                      set @year = 2018


                      set @date = cast(@year as varchar(4)) + '0101'
                      set @date = dateadd(quarter, 1 - 1, @date)
                      print @date

                      set @date = cast(@year as varchar(4)) + '0101'
                      set @date = dateadd(quarter, 2 - 1, @date)
                      print @date

                      set @date = cast(@year as varchar(4)) + '0101'
                      set @date = dateadd(quarter, 3 - 1, @date)
                      print @date

                      set @date = cast(@year as varchar(4)) + '0101'
                      set @date = dateadd(quarter, 4 - 1, @date)
                      print @date




                      2018-01-01
                      2018-04-01
                      2018-07-01
                      2018-10-01


                      db<>fiddle here







                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered Jan 10 at 21:45









                      McNetsMcNets

                      15.5k41958




                      15.5k41958







                      • 3





                        My understanding was, that '2018-10-01' is independent of regional settings and will always be parsed correctly by SQL Server. Isn't that true?

                        – a_horse_with_no_name
                        Jan 11 at 7:03











                      • @a_horse_with_no_name it should due it is ISO 8601, but at least in my company where we use a mixed-language installation of SQL servers (English, Spanish) I ended using the less unambiguous format YYYYMMDD HH:MM:SS to avoid date conversion issues.

                        – McNets
                        Jan 11 at 8:24






                      • 5





                        @a_horse_with_no_name - This is correct for the newer temporal datatypes (e.g. date and datetime2) but not for the legacy datetime type. So as the questioner is casting to date the format is fine in this case

                        – Martin Smith
                        Jan 11 at 11:17






                      • 1





                        @MartinSmith: thanks for the clarification

                        – a_horse_with_no_name
                        Jan 11 at 11:42











                      • "2001-08-12" isn't always interpreted in the way you would expect. I never worked out how but in our development environment it would interpret it as yyyy-dd-mm, and throw an out of range error for "2001-08-13". I try to avoid string-to-date conversion at all, and where it is necessary I make sure to use a month name - "12 aug 2001" is unambiguous.

                        – IanF1
                        Jan 19 at 18:47












                      • 3





                        My understanding was, that '2018-10-01' is independent of regional settings and will always be parsed correctly by SQL Server. Isn't that true?

                        – a_horse_with_no_name
                        Jan 11 at 7:03











                      • @a_horse_with_no_name it should due it is ISO 8601, but at least in my company where we use a mixed-language installation of SQL servers (English, Spanish) I ended using the less unambiguous format YYYYMMDD HH:MM:SS to avoid date conversion issues.

                        – McNets
                        Jan 11 at 8:24






                      • 5





                        @a_horse_with_no_name - This is correct for the newer temporal datatypes (e.g. date and datetime2) but not for the legacy datetime type. So as the questioner is casting to date the format is fine in this case

                        – Martin Smith
                        Jan 11 at 11:17






                      • 1





                        @MartinSmith: thanks for the clarification

                        – a_horse_with_no_name
                        Jan 11 at 11:42











                      • "2001-08-12" isn't always interpreted in the way you would expect. I never worked out how but in our development environment it would interpret it as yyyy-dd-mm, and throw an out of range error for "2001-08-13". I try to avoid string-to-date conversion at all, and where it is necessary I make sure to use a month name - "12 aug 2001" is unambiguous.

                        – IanF1
                        Jan 19 at 18:47







                      3




                      3





                      My understanding was, that '2018-10-01' is independent of regional settings and will always be parsed correctly by SQL Server. Isn't that true?

                      – a_horse_with_no_name
                      Jan 11 at 7:03





                      My understanding was, that '2018-10-01' is independent of regional settings and will always be parsed correctly by SQL Server. Isn't that true?

                      – a_horse_with_no_name
                      Jan 11 at 7:03













                      @a_horse_with_no_name it should due it is ISO 8601, but at least in my company where we use a mixed-language installation of SQL servers (English, Spanish) I ended using the less unambiguous format YYYYMMDD HH:MM:SS to avoid date conversion issues.

                      – McNets
                      Jan 11 at 8:24





                      @a_horse_with_no_name it should due it is ISO 8601, but at least in my company where we use a mixed-language installation of SQL servers (English, Spanish) I ended using the less unambiguous format YYYYMMDD HH:MM:SS to avoid date conversion issues.

                      – McNets
                      Jan 11 at 8:24




                      5




                      5





                      @a_horse_with_no_name - This is correct for the newer temporal datatypes (e.g. date and datetime2) but not for the legacy datetime type. So as the questioner is casting to date the format is fine in this case

                      – Martin Smith
                      Jan 11 at 11:17





                      @a_horse_with_no_name - This is correct for the newer temporal datatypes (e.g. date and datetime2) but not for the legacy datetime type. So as the questioner is casting to date the format is fine in this case

                      – Martin Smith
                      Jan 11 at 11:17




                      1




                      1





                      @MartinSmith: thanks for the clarification

                      – a_horse_with_no_name
                      Jan 11 at 11:42





                      @MartinSmith: thanks for the clarification

                      – a_horse_with_no_name
                      Jan 11 at 11:42













                      "2001-08-12" isn't always interpreted in the way you would expect. I never worked out how but in our development environment it would interpret it as yyyy-dd-mm, and throw an out of range error for "2001-08-13". I try to avoid string-to-date conversion at all, and where it is necessary I make sure to use a month name - "12 aug 2001" is unambiguous.

                      – IanF1
                      Jan 19 at 18:47





                      "2001-08-12" isn't always interpreted in the way you would expect. I never worked out how but in our development environment it would interpret it as yyyy-dd-mm, and throw an out of range error for "2001-08-13". I try to avoid string-to-date conversion at all, and where it is necessary I make sure to use a month name - "12 aug 2001" is unambiguous.

                      – IanF1
                      Jan 19 at 18:47











                      4














                      You could Create a date dimension or calendar table in SQL Server and query it



                      --demo setup 
                      drop table if exists #dim
                      DECLARE @StartDate DATE = '20000101', @NumberOfYears INT = 30;

                      -- prevent set or regional settings from interfering with
                      -- interpretation of dates / literals

                      SET DATEFIRST 7;
                      SET DATEFORMAT mdy;
                      SET LANGUAGE US_ENGLISH;

                      DECLARE @CutoffDate DATE = DATEADD(YEAR, @NumberOfYears, @StartDate);

                      -- this is just a holding table for intermediate calculations:

                      CREATE TABLE #dim
                      (
                      [date] DATE PRIMARY KEY,
                      [day] AS DATEPART(DAY, [date]),
                      [month] AS DATEPART(MONTH, [date]),
                      FirstOfMonth AS CONVERT(DATE, DATEADD(MONTH, DATEDIFF(MONTH, 0, [date]), 0)),
                      [MonthName] AS DATENAME(MONTH, [date]),
                      [week] AS DATEPART(WEEK, [date]),
                      [ISOweek] AS DATEPART(ISO_WEEK, [date]),
                      [DayOfWeek] AS DATEPART(WEEKDAY, [date]),
                      [quarter] AS DATEPART(QUARTER, [date]),
                      [year] AS DATEPART(YEAR, [date]),
                      FirstOfYear AS CONVERT(DATE, DATEADD(YEAR, DATEDIFF(YEAR, 0, [date]), 0)),
                      Style112 AS CONVERT(CHAR(8), [date], 112),
                      Style101 AS CONVERT(CHAR(10), [date], 101)
                      );

                      -- use the catalog views to generate as many rows as we need

                      INSERT #dim([date])
                      SELECT d
                      FROM
                      (
                      SELECT d = DATEADD(DAY, rn - 1, @StartDate)
                      FROM
                      (
                      SELECT TOP (DATEDIFF(DAY, @StartDate, @CutoffDate))
                      rn = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
                      FROM sys.all_objects AS s1
                      CROSS JOIN sys.all_objects AS s2
                      -- on my system this would support > 5 million days
                      ORDER BY s1.[object_id]
                      ) AS x
                      ) AS y;

                      drop table if exists dbo.DateDimension

                      CREATE TABLE dbo.DateDimension
                      (
                      --DateKey INT NOT NULL PRIMARY KEY,
                      [Date] DATE NOT NULL,
                      [Day] TINYINT NOT NULL,
                      DaySuffix CHAR(2) NOT NULL,
                      [Weekday] TINYINT NOT NULL,
                      WeekDayName VARCHAR(10) NOT NULL,
                      IsWeekend BIT NOT NULL,
                      IsHoliday BIT NOT NULL,
                      HolidayText VARCHAR(64) SPARSE,
                      DOWInMonth TINYINT NOT NULL,
                      [DayOfYear] SMALLINT NOT NULL,
                      WeekOfMonth TINYINT NOT NULL,
                      WeekOfYear TINYINT NOT NULL,
                      ISOWeekOfYear TINYINT NOT NULL,
                      [Month] TINYINT NOT NULL,
                      [MonthName] VARCHAR(10) NOT NULL,
                      [Quarter] TINYINT NOT NULL,
                      QuarterName VARCHAR(6) NOT NULL,
                      [Year] INT NOT NULL,
                      MMYYYY CHAR(6) NOT NULL,
                      MonthYear CHAR(7) NOT NULL,
                      FirstDayOfMonth DATE NOT NULL,
                      LastDayOfMonth DATE NOT NULL,
                      FirstDayOfQuarter DATE NOT NULL,
                      LastDayOfQuarter DATE NOT NULL,
                      FirstDayOfYear DATE NOT NULL,
                      LastDayOfYear DATE NOT NULL,
                      FirstDayOfNextMonth DATE NOT NULL,
                      FirstDayOfNextYear DATE NOT NULL
                      );
                      INSERT dbo.DateDimension WITH (TABLOCKX)
                      SELECT
                      --DateKey = CONVERT(INT, Style112),
                      [Date] = [date],
                      [Day] = CONVERT(TINYINT, [day]),
                      DaySuffix = CONVERT(CHAR(2), CASE WHEN [day] / 10 = 1 THEN 'th' ELSE
                      CASE RIGHT([day], 1) WHEN '1' THEN 'st' WHEN '2' THEN 'nd'
                      WHEN '3' THEN 'rd' ELSE 'th' END END),
                      [Weekday] = CONVERT(TINYINT, [DayOfWeek]),
                      [WeekDayName] = CONVERT(VARCHAR(10), DATENAME(WEEKDAY, [date])),
                      [IsWeekend] = CONVERT(BIT, CASE WHEN [DayOfWeek] IN (1,7) THEN 1 ELSE 0 END),
                      [IsHoliday] = CONVERT(BIT, 0),
                      HolidayText = CONVERT(VARCHAR(64), NULL),
                      [DOWInMonth] = CONVERT(TINYINT, ROW_NUMBER() OVER
                      (PARTITION BY FirstOfMonth, [DayOfWeek] ORDER BY [date])),
                      [DayOfYear] = CONVERT(SMALLINT, DATEPART(DAYOFYEAR, [date])),
                      WeekOfMonth = CONVERT(TINYINT, DENSE_RANK() OVER
                      (PARTITION BY [year], [month] ORDER BY [week])),
                      WeekOfYear = CONVERT(TINYINT, [week]),
                      ISOWeekOfYear = CONVERT(TINYINT, ISOWeek),
                      [Month] = CONVERT(TINYINT, [month]),
                      [MonthName] = CONVERT(VARCHAR(10), [MonthName]),
                      [Quarter] = CONVERT(TINYINT, [quarter]),
                      QuarterName = CONVERT(VARCHAR(6), CASE [quarter] WHEN 1 THEN 'First'
                      WHEN 2 THEN 'Second' WHEN 3 THEN 'Third' WHEN 4 THEN 'Fourth' END),
                      [Year] = [year],
                      MMYYYY = CONVERT(CHAR(6), LEFT(Style101, 2) + LEFT(Style112, 4)),
                      MonthYear = CONVERT(CHAR(7), LEFT([MonthName], 3) + LEFT(Style112, 4)),
                      FirstDayOfMonth = FirstOfMonth,
                      LastDayOfMonth = MAX([date]) OVER (PARTITION BY [year], [month]),
                      FirstDayOfQuarter = MIN([date]) OVER (PARTITION BY [year], [quarter]),
                      LastDayOfQuarter = MAX([date]) OVER (PARTITION BY [year], [quarter]),
                      FirstDayOfYear = FirstOfYear,
                      LastDayOfYear = MAX([date]) OVER (PARTITION BY [year]),
                      FirstDayOfNextMonth = DATEADD(MONTH, 1, FirstOfMonth),
                      FirstDayOfNextYear = DATEADD(YEAR, 1, FirstOfYear)
                      FROM #dim
                      OPTION (MAXDOP 1);



                      --solution
                      SELECT min(Date)
                      FROM [Test].[dbo].[DateDimension]
                      where [year] = 2018 and [Quarter]=4



                      | Date |
                      |------------|
                      | 2018-10-01 |





                      share|improve this answer


















                      • 1





                        This is the right way to do it - this way we can index the date parts, so it will be a bazillion times faster to join to DateDimension than to put a function on a column in the where clause.

                        – James
                        Jan 11 at 15:41















                      4














                      You could Create a date dimension or calendar table in SQL Server and query it



                      --demo setup 
                      drop table if exists #dim
                      DECLARE @StartDate DATE = '20000101', @NumberOfYears INT = 30;

                      -- prevent set or regional settings from interfering with
                      -- interpretation of dates / literals

                      SET DATEFIRST 7;
                      SET DATEFORMAT mdy;
                      SET LANGUAGE US_ENGLISH;

                      DECLARE @CutoffDate DATE = DATEADD(YEAR, @NumberOfYears, @StartDate);

                      -- this is just a holding table for intermediate calculations:

                      CREATE TABLE #dim
                      (
                      [date] DATE PRIMARY KEY,
                      [day] AS DATEPART(DAY, [date]),
                      [month] AS DATEPART(MONTH, [date]),
                      FirstOfMonth AS CONVERT(DATE, DATEADD(MONTH, DATEDIFF(MONTH, 0, [date]), 0)),
                      [MonthName] AS DATENAME(MONTH, [date]),
                      [week] AS DATEPART(WEEK, [date]),
                      [ISOweek] AS DATEPART(ISO_WEEK, [date]),
                      [DayOfWeek] AS DATEPART(WEEKDAY, [date]),
                      [quarter] AS DATEPART(QUARTER, [date]),
                      [year] AS DATEPART(YEAR, [date]),
                      FirstOfYear AS CONVERT(DATE, DATEADD(YEAR, DATEDIFF(YEAR, 0, [date]), 0)),
                      Style112 AS CONVERT(CHAR(8), [date], 112),
                      Style101 AS CONVERT(CHAR(10), [date], 101)
                      );

                      -- use the catalog views to generate as many rows as we need

                      INSERT #dim([date])
                      SELECT d
                      FROM
                      (
                      SELECT d = DATEADD(DAY, rn - 1, @StartDate)
                      FROM
                      (
                      SELECT TOP (DATEDIFF(DAY, @StartDate, @CutoffDate))
                      rn = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
                      FROM sys.all_objects AS s1
                      CROSS JOIN sys.all_objects AS s2
                      -- on my system this would support > 5 million days
                      ORDER BY s1.[object_id]
                      ) AS x
                      ) AS y;

                      drop table if exists dbo.DateDimension

                      CREATE TABLE dbo.DateDimension
                      (
                      --DateKey INT NOT NULL PRIMARY KEY,
                      [Date] DATE NOT NULL,
                      [Day] TINYINT NOT NULL,
                      DaySuffix CHAR(2) NOT NULL,
                      [Weekday] TINYINT NOT NULL,
                      WeekDayName VARCHAR(10) NOT NULL,
                      IsWeekend BIT NOT NULL,
                      IsHoliday BIT NOT NULL,
                      HolidayText VARCHAR(64) SPARSE,
                      DOWInMonth TINYINT NOT NULL,
                      [DayOfYear] SMALLINT NOT NULL,
                      WeekOfMonth TINYINT NOT NULL,
                      WeekOfYear TINYINT NOT NULL,
                      ISOWeekOfYear TINYINT NOT NULL,
                      [Month] TINYINT NOT NULL,
                      [MonthName] VARCHAR(10) NOT NULL,
                      [Quarter] TINYINT NOT NULL,
                      QuarterName VARCHAR(6) NOT NULL,
                      [Year] INT NOT NULL,
                      MMYYYY CHAR(6) NOT NULL,
                      MonthYear CHAR(7) NOT NULL,
                      FirstDayOfMonth DATE NOT NULL,
                      LastDayOfMonth DATE NOT NULL,
                      FirstDayOfQuarter DATE NOT NULL,
                      LastDayOfQuarter DATE NOT NULL,
                      FirstDayOfYear DATE NOT NULL,
                      LastDayOfYear DATE NOT NULL,
                      FirstDayOfNextMonth DATE NOT NULL,
                      FirstDayOfNextYear DATE NOT NULL
                      );
                      INSERT dbo.DateDimension WITH (TABLOCKX)
                      SELECT
                      --DateKey = CONVERT(INT, Style112),
                      [Date] = [date],
                      [Day] = CONVERT(TINYINT, [day]),
                      DaySuffix = CONVERT(CHAR(2), CASE WHEN [day] / 10 = 1 THEN 'th' ELSE
                      CASE RIGHT([day], 1) WHEN '1' THEN 'st' WHEN '2' THEN 'nd'
                      WHEN '3' THEN 'rd' ELSE 'th' END END),
                      [Weekday] = CONVERT(TINYINT, [DayOfWeek]),
                      [WeekDayName] = CONVERT(VARCHAR(10), DATENAME(WEEKDAY, [date])),
                      [IsWeekend] = CONVERT(BIT, CASE WHEN [DayOfWeek] IN (1,7) THEN 1 ELSE 0 END),
                      [IsHoliday] = CONVERT(BIT, 0),
                      HolidayText = CONVERT(VARCHAR(64), NULL),
                      [DOWInMonth] = CONVERT(TINYINT, ROW_NUMBER() OVER
                      (PARTITION BY FirstOfMonth, [DayOfWeek] ORDER BY [date])),
                      [DayOfYear] = CONVERT(SMALLINT, DATEPART(DAYOFYEAR, [date])),
                      WeekOfMonth = CONVERT(TINYINT, DENSE_RANK() OVER
                      (PARTITION BY [year], [month] ORDER BY [week])),
                      WeekOfYear = CONVERT(TINYINT, [week]),
                      ISOWeekOfYear = CONVERT(TINYINT, ISOWeek),
                      [Month] = CONVERT(TINYINT, [month]),
                      [MonthName] = CONVERT(VARCHAR(10), [MonthName]),
                      [Quarter] = CONVERT(TINYINT, [quarter]),
                      QuarterName = CONVERT(VARCHAR(6), CASE [quarter] WHEN 1 THEN 'First'
                      WHEN 2 THEN 'Second' WHEN 3 THEN 'Third' WHEN 4 THEN 'Fourth' END),
                      [Year] = [year],
                      MMYYYY = CONVERT(CHAR(6), LEFT(Style101, 2) + LEFT(Style112, 4)),
                      MonthYear = CONVERT(CHAR(7), LEFT([MonthName], 3) + LEFT(Style112, 4)),
                      FirstDayOfMonth = FirstOfMonth,
                      LastDayOfMonth = MAX([date]) OVER (PARTITION BY [year], [month]),
                      FirstDayOfQuarter = MIN([date]) OVER (PARTITION BY [year], [quarter]),
                      LastDayOfQuarter = MAX([date]) OVER (PARTITION BY [year], [quarter]),
                      FirstDayOfYear = FirstOfYear,
                      LastDayOfYear = MAX([date]) OVER (PARTITION BY [year]),
                      FirstDayOfNextMonth = DATEADD(MONTH, 1, FirstOfMonth),
                      FirstDayOfNextYear = DATEADD(YEAR, 1, FirstOfYear)
                      FROM #dim
                      OPTION (MAXDOP 1);



                      --solution
                      SELECT min(Date)
                      FROM [Test].[dbo].[DateDimension]
                      where [year] = 2018 and [Quarter]=4



                      | Date |
                      |------------|
                      | 2018-10-01 |





                      share|improve this answer


















                      • 1





                        This is the right way to do it - this way we can index the date parts, so it will be a bazillion times faster to join to DateDimension than to put a function on a column in the where clause.

                        – James
                        Jan 11 at 15:41













                      4












                      4








                      4







                      You could Create a date dimension or calendar table in SQL Server and query it



                      --demo setup 
                      drop table if exists #dim
                      DECLARE @StartDate DATE = '20000101', @NumberOfYears INT = 30;

                      -- prevent set or regional settings from interfering with
                      -- interpretation of dates / literals

                      SET DATEFIRST 7;
                      SET DATEFORMAT mdy;
                      SET LANGUAGE US_ENGLISH;

                      DECLARE @CutoffDate DATE = DATEADD(YEAR, @NumberOfYears, @StartDate);

                      -- this is just a holding table for intermediate calculations:

                      CREATE TABLE #dim
                      (
                      [date] DATE PRIMARY KEY,
                      [day] AS DATEPART(DAY, [date]),
                      [month] AS DATEPART(MONTH, [date]),
                      FirstOfMonth AS CONVERT(DATE, DATEADD(MONTH, DATEDIFF(MONTH, 0, [date]), 0)),
                      [MonthName] AS DATENAME(MONTH, [date]),
                      [week] AS DATEPART(WEEK, [date]),
                      [ISOweek] AS DATEPART(ISO_WEEK, [date]),
                      [DayOfWeek] AS DATEPART(WEEKDAY, [date]),
                      [quarter] AS DATEPART(QUARTER, [date]),
                      [year] AS DATEPART(YEAR, [date]),
                      FirstOfYear AS CONVERT(DATE, DATEADD(YEAR, DATEDIFF(YEAR, 0, [date]), 0)),
                      Style112 AS CONVERT(CHAR(8), [date], 112),
                      Style101 AS CONVERT(CHAR(10), [date], 101)
                      );

                      -- use the catalog views to generate as many rows as we need

                      INSERT #dim([date])
                      SELECT d
                      FROM
                      (
                      SELECT d = DATEADD(DAY, rn - 1, @StartDate)
                      FROM
                      (
                      SELECT TOP (DATEDIFF(DAY, @StartDate, @CutoffDate))
                      rn = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
                      FROM sys.all_objects AS s1
                      CROSS JOIN sys.all_objects AS s2
                      -- on my system this would support > 5 million days
                      ORDER BY s1.[object_id]
                      ) AS x
                      ) AS y;

                      drop table if exists dbo.DateDimension

                      CREATE TABLE dbo.DateDimension
                      (
                      --DateKey INT NOT NULL PRIMARY KEY,
                      [Date] DATE NOT NULL,
                      [Day] TINYINT NOT NULL,
                      DaySuffix CHAR(2) NOT NULL,
                      [Weekday] TINYINT NOT NULL,
                      WeekDayName VARCHAR(10) NOT NULL,
                      IsWeekend BIT NOT NULL,
                      IsHoliday BIT NOT NULL,
                      HolidayText VARCHAR(64) SPARSE,
                      DOWInMonth TINYINT NOT NULL,
                      [DayOfYear] SMALLINT NOT NULL,
                      WeekOfMonth TINYINT NOT NULL,
                      WeekOfYear TINYINT NOT NULL,
                      ISOWeekOfYear TINYINT NOT NULL,
                      [Month] TINYINT NOT NULL,
                      [MonthName] VARCHAR(10) NOT NULL,
                      [Quarter] TINYINT NOT NULL,
                      QuarterName VARCHAR(6) NOT NULL,
                      [Year] INT NOT NULL,
                      MMYYYY CHAR(6) NOT NULL,
                      MonthYear CHAR(7) NOT NULL,
                      FirstDayOfMonth DATE NOT NULL,
                      LastDayOfMonth DATE NOT NULL,
                      FirstDayOfQuarter DATE NOT NULL,
                      LastDayOfQuarter DATE NOT NULL,
                      FirstDayOfYear DATE NOT NULL,
                      LastDayOfYear DATE NOT NULL,
                      FirstDayOfNextMonth DATE NOT NULL,
                      FirstDayOfNextYear DATE NOT NULL
                      );
                      INSERT dbo.DateDimension WITH (TABLOCKX)
                      SELECT
                      --DateKey = CONVERT(INT, Style112),
                      [Date] = [date],
                      [Day] = CONVERT(TINYINT, [day]),
                      DaySuffix = CONVERT(CHAR(2), CASE WHEN [day] / 10 = 1 THEN 'th' ELSE
                      CASE RIGHT([day], 1) WHEN '1' THEN 'st' WHEN '2' THEN 'nd'
                      WHEN '3' THEN 'rd' ELSE 'th' END END),
                      [Weekday] = CONVERT(TINYINT, [DayOfWeek]),
                      [WeekDayName] = CONVERT(VARCHAR(10), DATENAME(WEEKDAY, [date])),
                      [IsWeekend] = CONVERT(BIT, CASE WHEN [DayOfWeek] IN (1,7) THEN 1 ELSE 0 END),
                      [IsHoliday] = CONVERT(BIT, 0),
                      HolidayText = CONVERT(VARCHAR(64), NULL),
                      [DOWInMonth] = CONVERT(TINYINT, ROW_NUMBER() OVER
                      (PARTITION BY FirstOfMonth, [DayOfWeek] ORDER BY [date])),
                      [DayOfYear] = CONVERT(SMALLINT, DATEPART(DAYOFYEAR, [date])),
                      WeekOfMonth = CONVERT(TINYINT, DENSE_RANK() OVER
                      (PARTITION BY [year], [month] ORDER BY [week])),
                      WeekOfYear = CONVERT(TINYINT, [week]),
                      ISOWeekOfYear = CONVERT(TINYINT, ISOWeek),
                      [Month] = CONVERT(TINYINT, [month]),
                      [MonthName] = CONVERT(VARCHAR(10), [MonthName]),
                      [Quarter] = CONVERT(TINYINT, [quarter]),
                      QuarterName = CONVERT(VARCHAR(6), CASE [quarter] WHEN 1 THEN 'First'
                      WHEN 2 THEN 'Second' WHEN 3 THEN 'Third' WHEN 4 THEN 'Fourth' END),
                      [Year] = [year],
                      MMYYYY = CONVERT(CHAR(6), LEFT(Style101, 2) + LEFT(Style112, 4)),
                      MonthYear = CONVERT(CHAR(7), LEFT([MonthName], 3) + LEFT(Style112, 4)),
                      FirstDayOfMonth = FirstOfMonth,
                      LastDayOfMonth = MAX([date]) OVER (PARTITION BY [year], [month]),
                      FirstDayOfQuarter = MIN([date]) OVER (PARTITION BY [year], [quarter]),
                      LastDayOfQuarter = MAX([date]) OVER (PARTITION BY [year], [quarter]),
                      FirstDayOfYear = FirstOfYear,
                      LastDayOfYear = MAX([date]) OVER (PARTITION BY [year]),
                      FirstDayOfNextMonth = DATEADD(MONTH, 1, FirstOfMonth),
                      FirstDayOfNextYear = DATEADD(YEAR, 1, FirstOfYear)
                      FROM #dim
                      OPTION (MAXDOP 1);



                      --solution
                      SELECT min(Date)
                      FROM [Test].[dbo].[DateDimension]
                      where [year] = 2018 and [Quarter]=4



                      | Date |
                      |------------|
                      | 2018-10-01 |





                      share|improve this answer













                      You could Create a date dimension or calendar table in SQL Server and query it



                      --demo setup 
                      drop table if exists #dim
                      DECLARE @StartDate DATE = '20000101', @NumberOfYears INT = 30;

                      -- prevent set or regional settings from interfering with
                      -- interpretation of dates / literals

                      SET DATEFIRST 7;
                      SET DATEFORMAT mdy;
                      SET LANGUAGE US_ENGLISH;

                      DECLARE @CutoffDate DATE = DATEADD(YEAR, @NumberOfYears, @StartDate);

                      -- this is just a holding table for intermediate calculations:

                      CREATE TABLE #dim
                      (
                      [date] DATE PRIMARY KEY,
                      [day] AS DATEPART(DAY, [date]),
                      [month] AS DATEPART(MONTH, [date]),
                      FirstOfMonth AS CONVERT(DATE, DATEADD(MONTH, DATEDIFF(MONTH, 0, [date]), 0)),
                      [MonthName] AS DATENAME(MONTH, [date]),
                      [week] AS DATEPART(WEEK, [date]),
                      [ISOweek] AS DATEPART(ISO_WEEK, [date]),
                      [DayOfWeek] AS DATEPART(WEEKDAY, [date]),
                      [quarter] AS DATEPART(QUARTER, [date]),
                      [year] AS DATEPART(YEAR, [date]),
                      FirstOfYear AS CONVERT(DATE, DATEADD(YEAR, DATEDIFF(YEAR, 0, [date]), 0)),
                      Style112 AS CONVERT(CHAR(8), [date], 112),
                      Style101 AS CONVERT(CHAR(10), [date], 101)
                      );

                      -- use the catalog views to generate as many rows as we need

                      INSERT #dim([date])
                      SELECT d
                      FROM
                      (
                      SELECT d = DATEADD(DAY, rn - 1, @StartDate)
                      FROM
                      (
                      SELECT TOP (DATEDIFF(DAY, @StartDate, @CutoffDate))
                      rn = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
                      FROM sys.all_objects AS s1
                      CROSS JOIN sys.all_objects AS s2
                      -- on my system this would support > 5 million days
                      ORDER BY s1.[object_id]
                      ) AS x
                      ) AS y;

                      drop table if exists dbo.DateDimension

                      CREATE TABLE dbo.DateDimension
                      (
                      --DateKey INT NOT NULL PRIMARY KEY,
                      [Date] DATE NOT NULL,
                      [Day] TINYINT NOT NULL,
                      DaySuffix CHAR(2) NOT NULL,
                      [Weekday] TINYINT NOT NULL,
                      WeekDayName VARCHAR(10) NOT NULL,
                      IsWeekend BIT NOT NULL,
                      IsHoliday BIT NOT NULL,
                      HolidayText VARCHAR(64) SPARSE,
                      DOWInMonth TINYINT NOT NULL,
                      [DayOfYear] SMALLINT NOT NULL,
                      WeekOfMonth TINYINT NOT NULL,
                      WeekOfYear TINYINT NOT NULL,
                      ISOWeekOfYear TINYINT NOT NULL,
                      [Month] TINYINT NOT NULL,
                      [MonthName] VARCHAR(10) NOT NULL,
                      [Quarter] TINYINT NOT NULL,
                      QuarterName VARCHAR(6) NOT NULL,
                      [Year] INT NOT NULL,
                      MMYYYY CHAR(6) NOT NULL,
                      MonthYear CHAR(7) NOT NULL,
                      FirstDayOfMonth DATE NOT NULL,
                      LastDayOfMonth DATE NOT NULL,
                      FirstDayOfQuarter DATE NOT NULL,
                      LastDayOfQuarter DATE NOT NULL,
                      FirstDayOfYear DATE NOT NULL,
                      LastDayOfYear DATE NOT NULL,
                      FirstDayOfNextMonth DATE NOT NULL,
                      FirstDayOfNextYear DATE NOT NULL
                      );
                      INSERT dbo.DateDimension WITH (TABLOCKX)
                      SELECT
                      --DateKey = CONVERT(INT, Style112),
                      [Date] = [date],
                      [Day] = CONVERT(TINYINT, [day]),
                      DaySuffix = CONVERT(CHAR(2), CASE WHEN [day] / 10 = 1 THEN 'th' ELSE
                      CASE RIGHT([day], 1) WHEN '1' THEN 'st' WHEN '2' THEN 'nd'
                      WHEN '3' THEN 'rd' ELSE 'th' END END),
                      [Weekday] = CONVERT(TINYINT, [DayOfWeek]),
                      [WeekDayName] = CONVERT(VARCHAR(10), DATENAME(WEEKDAY, [date])),
                      [IsWeekend] = CONVERT(BIT, CASE WHEN [DayOfWeek] IN (1,7) THEN 1 ELSE 0 END),
                      [IsHoliday] = CONVERT(BIT, 0),
                      HolidayText = CONVERT(VARCHAR(64), NULL),
                      [DOWInMonth] = CONVERT(TINYINT, ROW_NUMBER() OVER
                      (PARTITION BY FirstOfMonth, [DayOfWeek] ORDER BY [date])),
                      [DayOfYear] = CONVERT(SMALLINT, DATEPART(DAYOFYEAR, [date])),
                      WeekOfMonth = CONVERT(TINYINT, DENSE_RANK() OVER
                      (PARTITION BY [year], [month] ORDER BY [week])),
                      WeekOfYear = CONVERT(TINYINT, [week]),
                      ISOWeekOfYear = CONVERT(TINYINT, ISOWeek),
                      [Month] = CONVERT(TINYINT, [month]),
                      [MonthName] = CONVERT(VARCHAR(10), [MonthName]),
                      [Quarter] = CONVERT(TINYINT, [quarter]),
                      QuarterName = CONVERT(VARCHAR(6), CASE [quarter] WHEN 1 THEN 'First'
                      WHEN 2 THEN 'Second' WHEN 3 THEN 'Third' WHEN 4 THEN 'Fourth' END),
                      [Year] = [year],
                      MMYYYY = CONVERT(CHAR(6), LEFT(Style101, 2) + LEFT(Style112, 4)),
                      MonthYear = CONVERT(CHAR(7), LEFT([MonthName], 3) + LEFT(Style112, 4)),
                      FirstDayOfMonth = FirstOfMonth,
                      LastDayOfMonth = MAX([date]) OVER (PARTITION BY [year], [month]),
                      FirstDayOfQuarter = MIN([date]) OVER (PARTITION BY [year], [quarter]),
                      LastDayOfQuarter = MAX([date]) OVER (PARTITION BY [year], [quarter]),
                      FirstDayOfYear = FirstOfYear,
                      LastDayOfYear = MAX([date]) OVER (PARTITION BY [year]),
                      FirstDayOfNextMonth = DATEADD(MONTH, 1, FirstOfMonth),
                      FirstDayOfNextYear = DATEADD(YEAR, 1, FirstOfYear)
                      FROM #dim
                      OPTION (MAXDOP 1);



                      --solution
                      SELECT min(Date)
                      FROM [Test].[dbo].[DateDimension]
                      where [year] = 2018 and [Quarter]=4



                      | Date |
                      |------------|
                      | 2018-10-01 |






                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered Jan 10 at 21:51









                      Scott HodginScott Hodgin

                      17k21534




                      17k21534







                      • 1





                        This is the right way to do it - this way we can index the date parts, so it will be a bazillion times faster to join to DateDimension than to put a function on a column in the where clause.

                        – James
                        Jan 11 at 15:41












                      • 1





                        This is the right way to do it - this way we can index the date parts, so it will be a bazillion times faster to join to DateDimension than to put a function on a column in the where clause.

                        – James
                        Jan 11 at 15:41







                      1




                      1





                      This is the right way to do it - this way we can index the date parts, so it will be a bazillion times faster to join to DateDimension than to put a function on a column in the where clause.

                      – James
                      Jan 11 at 15:41





                      This is the right way to do it - this way we can index the date parts, so it will be a bazillion times faster to join to DateDimension than to put a function on a column in the where clause.

                      – James
                      Jan 11 at 15:41











                      3














                      I would avoid using strings at all but use date arithmetic combined with a known (or even unknown!) zero epoch.



                      DECLARE @epoch DATE = CONVERT(DATETIME, 0);
                      /* for some reason SQL Server let's you cast int to datetime but not to date, the above casts via datetime (second cast implicit) */

                      SET @date = DATEADD(MONTH, (@quarter-1)*3, DATEADD(YEAR, @year - YEAR(@epoch), @epoch));


                      This avoids string to date comparison which is messy, culture-dependent and expensive.






                      share|improve this answer





























                        3














                        I would avoid using strings at all but use date arithmetic combined with a known (or even unknown!) zero epoch.



                        DECLARE @epoch DATE = CONVERT(DATETIME, 0);
                        /* for some reason SQL Server let's you cast int to datetime but not to date, the above casts via datetime (second cast implicit) */

                        SET @date = DATEADD(MONTH, (@quarter-1)*3, DATEADD(YEAR, @year - YEAR(@epoch), @epoch));


                        This avoids string to date comparison which is messy, culture-dependent and expensive.






                        share|improve this answer



























                          3












                          3








                          3







                          I would avoid using strings at all but use date arithmetic combined with a known (or even unknown!) zero epoch.



                          DECLARE @epoch DATE = CONVERT(DATETIME, 0);
                          /* for some reason SQL Server let's you cast int to datetime but not to date, the above casts via datetime (second cast implicit) */

                          SET @date = DATEADD(MONTH, (@quarter-1)*3, DATEADD(YEAR, @year - YEAR(@epoch), @epoch));


                          This avoids string to date comparison which is messy, culture-dependent and expensive.






                          share|improve this answer















                          I would avoid using strings at all but use date arithmetic combined with a known (or even unknown!) zero epoch.



                          DECLARE @epoch DATE = CONVERT(DATETIME, 0);
                          /* for some reason SQL Server let's you cast int to datetime but not to date, the above casts via datetime (second cast implicit) */

                          SET @date = DATEADD(MONTH, (@quarter-1)*3, DATEADD(YEAR, @year - YEAR(@epoch), @epoch));


                          This avoids string to date comparison which is messy, culture-dependent and expensive.







                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited Jan 11 at 19:10

























                          answered Jan 11 at 6:53









                          IanF1IanF1

                          1313




                          1313



























                              draft saved

                              draft discarded
















































                              Thanks for contributing an answer to Database Administrators Stack Exchange!


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid


                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.

                              To learn more, see our tips on writing great answers.




                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function ()
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f226838%2fwhat-is-the-best-way-to-rebuild-a-date-from-integer-inputs%23new-answer', 'question_page');

                              );

                              Post as a guest















                              Required, but never shown





















































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown

































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown






                              Popular posts from this blog

                              Peggy Mitchell

                              Palaiologos

                              The Forum (Inglewood, California)