Forum Discussion

dkay84_PowerBI's avatar
dkay84_PowerBI
Icon for Microsoft Employee rankMicrosoft Employee
9 years ago
Solved

Date Dimension Table that Dynamically Pulls Start and End dates from a Column of Dates

As the title suggests, I am looking to create a date dimension table with M that checks for the earliest and most recent invoice dates and creates a date table from that with 1 day increments.  I have code to create a dimDate table but the user has to manually enter start and end dates.  Similarly, I have two functions that, when invoked, return the earliest and most recent date, respectively.  Can anyone give me some tips on how to integrate these?

 

Below is the code I am using (I did not create this) to generate a user defined dimDate table.  Is it possible to call the functions that return the start date and end date instead of requiring the user to hard code these in?

 

let CreateDateTable = (StartDate as date, EndDate as date, optional Culture as nullable text) as table =>
  let
    DayCount = Duration.Days(Duration.From(EndDate - StartDate)),
    Source = List.Dates(StartDate,DayCount,#duration(1,0,0,0)),
    TableFromList = Table.FromList(Source, Splitter.SplitByNothing()),
    ChangedType = Table.TransformColumnTypes(TableFromList,{{"Column1", type date}}),
    RenamedColumns = Table.RenameColumns(ChangedType,{{"Column1", "Date"}}),
    InsertYear = Table.AddColumn(RenamedColumns, "Year", each Date.Year([Date])),
    InsertQuarter = Table.AddColumn(InsertYear, "QuarterOfYear", each Date.QuarterOfYear([Date])),
    InsertMonth = Table.AddColumn(InsertQuarter, "MonthOfYear", each Date.Month([Date])),
    InsertDay = Table.AddColumn(InsertMonth, "DayOfMonth", each Date.Day([Date])),
    InsertDayInt = Table.AddColumn(InsertDay, "DateInt", each [Year] * 10000 + [MonthOfYear] * 100 + [DayOfMonth]),
    InsertMonthName = Table.AddColumn(InsertDayInt, "MonthName", each Date.ToText([Date], "MMMM", Culture), type text),
    InsertCalendarMonth = Table.AddColumn(InsertMonthName, "MonthInCalendar", each (try(Text.Range([MonthName],0,3)) otherwise [MonthName]) & " " & Number.ToText([Year])),
    InsertCalendarQtr = Table.AddColumn(InsertCalendarMonth, "QuarterInCalendar", each "Q" & Number.ToText([QuarterOfYear]) & " " & Number.ToText([Year])),
    InsertDayWeek = Table.AddColumn(InsertCalendarQtr, "DayInWeek", each Date.DayOfWeek([Date])),
    InsertDayName = Table.AddColumn(InsertDayWeek, "DayOfWeekName", each Date.ToText([Date], "dddd", Culture), type text),
    InsertWeekEnding = Table.AddColumn(InsertDayName, "WeekEnding", each Date.EndOfWeek([Date]), type date)
  in
    InsertWeekEnding
in
  CreateDateTable
  • As is typical in these types of challenges, I spent a while scouring the internet and trying to get a solution before I posted my question here, only to arrive at one a few minutes later...

     

    Anyway, here is the revised code that can be used:

    let CreateDateTable = () as table =>
      let
        StartDate = List.Min(Table.Column(Invoices,"OrderDate")),
        EndDate = List.Max(Table.Column(Invoices,"OrderDate")),
        DayCount = Duration.Days(Duration.From(EndDate - StartDate)),
        Source = List.Dates(StartDate,DayCount,#duration(1,0,0,0)),
        TableFromList = Table.FromList(Source, Splitter.SplitByNothing()),
        ChangedType = Table.TransformColumnTypes(TableFromList,{{"Column1", type date}}),
        RenamedColumns = Table.RenameColumns(ChangedType,{{"Column1", "Date"}}),
        InsertYear = Table.AddColumn(RenamedColumns, "Year", each Date.Year([Date])),
        InsertQuarter = Table.AddColumn(InsertYear, "QuarterOfYear", each Date.QuarterOfYear([Date])),
        InsertMonth = Table.AddColumn(InsertQuarter, "MonthOfYear", each Date.Month([Date])),
        InsertDay = Table.AddColumn(InsertMonth, "DayOfMonth", each Date.Day([Date])),
        InsertDayInt = Table.AddColumn(InsertDay, "DateInt", each [Year] * 10000 + [MonthOfYear] * 100 + [DayOfMonth]),
        InsertMonthName = Table.AddColumn(InsertDayInt, "MonthName", each Date.ToText([Date], "MMMM"), type text),
        InsertCalendarMonth = Table.AddColumn(InsertMonthName, "MonthInCalendar", each (try(Text.Range([MonthName],0,3)) otherwise [MonthName]) & " " & Number.ToText([Year])),
        InsertCalendarQtr = Table.AddColumn(InsertCalendarMonth, "QuarterInCalendar", each "Q" & Number.ToText([QuarterOfYear]) & " " & Number.ToText([Year])),
        InsertDayWeek = Table.AddColumn(InsertCalendarQtr, "DayInWeek", each Date.DayOfWeek([Date])),
        InsertDayName = Table.AddColumn(InsertDayWeek, "DayOfWeekName", each Date.ToText([Date], "dddd"), type text),
        InsertWeekEnding = Table.AddColumn(InsertDayName, "WeekEnding", each Date.EndOfWeek([Date]), type date)
      in
        InsertWeekEnding
    in
      CreateDateTable

    The red text is what you would need to customize, where, in my example, the table name is "Invoices" and the invoice date column is "OrderDate"

  • blopez11's avatar
    blopez11
    9 years ago

    This is route I ended up using since I wanted the table updated when I did a refresh

    I found this from another post, so I can't take any credit here

     

    DateTable =
    ADDCOLUMNS (
    CALENDAR (MINX(HR_HEADCOUNT,[Date]), NOW()),
    "Year", YEAR ( [Date] ),
    "QuarterOfYear", FORMAT ( [Date], "Q" ),
    "MonthOfYear", FORMAT ( [Date], "MM" ),
    "DateInt", FORMAT ( [Date], "YYYYMMDD" ),
    "MonthName", FORMAT ( [Date], "mmmm" ),
    "MonthInCalendar", FORMAT ( [Date], "mmm YYYY" ),
    "QuarterInCalendar", "Q" & FORMAT ( [Date], "Q" ) & " " & FORMAT ( [Date], "YYYY" ),
    "DayInWeek", WEEKDAY ( [Date] ),
    "DayOfWeekName", FORMAT ( [Date], "dddd" ),
    "DayOfWeekShort", FORMAT ( [Date], "ddd" ),
    "YearMonthShort", FORMAT ( [Date], "YYYY/mmm" ),
    "MonthNameShort", FORMAT ( [Date], "mmm" )

14 Replies

  • dkay84_PowerBI's avatar
    dkay84_PowerBI
    Icon for Microsoft Employee rankMicrosoft Employee

    As is typical in these types of challenges, I spent a while scouring the internet and trying to get a solution before I posted my question here, only to arrive at one a few minutes later...

     

    Anyway, here is the revised code that can be used:

    let CreateDateTable = () as table =>
      let
        StartDate = List.Min(Table.Column(Invoices,"OrderDate")),
        EndDate = List.Max(Table.Column(Invoices,"OrderDate")),
        DayCount = Duration.Days(Duration.From(EndDate - StartDate)),
        Source = List.Dates(StartDate,DayCount,#duration(1,0,0,0)),
        TableFromList = Table.FromList(Source, Splitter.SplitByNothing()),
        ChangedType = Table.TransformColumnTypes(TableFromList,{{"Column1", type date}}),
        RenamedColumns = Table.RenameColumns(ChangedType,{{"Column1", "Date"}}),
        InsertYear = Table.AddColumn(RenamedColumns, "Year", each Date.Year([Date])),
        InsertQuarter = Table.AddColumn(InsertYear, "QuarterOfYear", each Date.QuarterOfYear([Date])),
        InsertMonth = Table.AddColumn(InsertQuarter, "MonthOfYear", each Date.Month([Date])),
        InsertDay = Table.AddColumn(InsertMonth, "DayOfMonth", each Date.Day([Date])),
        InsertDayInt = Table.AddColumn(InsertDay, "DateInt", each [Year] * 10000 + [MonthOfYear] * 100 + [DayOfMonth]),
        InsertMonthName = Table.AddColumn(InsertDayInt, "MonthName", each Date.ToText([Date], "MMMM"), type text),
        InsertCalendarMonth = Table.AddColumn(InsertMonthName, "MonthInCalendar", each (try(Text.Range([MonthName],0,3)) otherwise [MonthName]) & " " & Number.ToText([Year])),
        InsertCalendarQtr = Table.AddColumn(InsertCalendarMonth, "QuarterInCalendar", each "Q" & Number.ToText([QuarterOfYear]) & " " & Number.ToText([Year])),
        InsertDayWeek = Table.AddColumn(InsertCalendarQtr, "DayInWeek", each Date.DayOfWeek([Date])),
        InsertDayName = Table.AddColumn(InsertDayWeek, "DayOfWeekName", each Date.ToText([Date], "dddd"), type text),
        InsertWeekEnding = Table.AddColumn(InsertDayName, "WeekEnding", each Date.EndOfWeek([Date]), type date)
      in
        InsertWeekEnding
    in
      CreateDateTable

    The red text is what you would need to customize, where, in my example, the table name is "Invoices" and the invoice date column is "OrderDate"

    • blopez11's avatar
      blopez11
      Icon for Super User rankSuper User

      Thanks for this post, I have looked for such as well

      A couple of questions

       

      Does this dynamically update as dates in your Invoices table change?  Meaning, if the max date in your invoice table changes based on data refresh, will the dates in the date table reflect this?  Also, how would this be called in such a scenario

       

      Thanks,

      • dkay84_PowerBI's avatar
        dkay84_PowerBI
        Icon for Microsoft Employee rankMicrosoft Employee

        Yes this dynamically updates.  Notice near the beginning of the code we have two declarations: 

         

        StartDate = List.Min(Table.Column(Invoices,"OrderDate"))

        EndDate = List.Max(Table.Column(Invoices,"OrderDate"))

         

        To set this up with your own data, after connecting to your data, open the query editor.  Create a new blank table.  Select the table from the list of queries and go to Advanced Editor.  Replace the existing code with the code from this post and it should become a function.  Then, to invoke, simply select the function and look for the button "invoke".