Forum Discussion

APM's avatar
APM
Icon for Helper I rankHelper I
5 years ago
Solved

Custom Calendar: YOY comparison to same weekday

Hi,

 

I am trying to create a date table for YOY comparisons.

 

This is seemingly simple, but it is complicated by two factors:

 

  • I use a retail calendar: IE: Every month starts with a Sunday. Thus, April 2021 starts April 4 and ends May 1; May 2021 starts May 2 and ends May 29, etc. Some months have 4 weeks, some months have 5 weeks, etc. Here is 2020:

 

 

  • My YOY comparisons need to be to the same weekday LY - April 12, 2021 is a Monday. April 12, 2020 was a Sunday. This is not an adequate comparison. I need to compare, in reality, Monday April 12,2021 to Monday April 13, 2020.

 

How do I build a date table that incorporates my retail year calendar and compares like-to-like days, truly apples-to-apples?

 

Thanks for your help!

  • You can make a DAX Date table like below starting on the first Sunday of your first year.

     

    Date 445 =
    ADDCOLUMNS (
        CALENDAR ( DATE ( 202015 )DATE ( 20211231 ) ),
        "Year"YEAR ( [Date] ),
        "DayOfWeek"FORMAT ( [Date], "dddd" )
    )

     

    Then you can add a DAX column to get the Day of the year with an expression like this.  The Day numbers of each year will line up.

     

    Day =
    VAR vThisYear = 'Date 445'[Year]
    VAR vFirstSunday =
        CALCULATE (
            MIN ( 'Date 445'[Date] ),
            ALL ( 'Date 445' ),
            'Date 445'[Year] = vThisYear,
            'Date 445'[DayOfWeek] = "Sunday"
        )
    VAR vPYFirstSunday =
        CALCULATE (
            MIN ( 'Date 445'[Date] ),
            ALL ( 'Date 445' ),
            'Date 445'[Year] = vThisYear - 1,
            'Date 445'[DayOfWeek] = "Sunday"
        )
    VAR vDayThisYear =
        DATEDIFF ( vFirstSunday, 'Date 445'[Date], DAY ) + 1
    VAR vDayPrevYear =
        DATEDIFF ( vPYFirstSunday, 'Date 445'[Date], DAY ) + 1
    VAR vResult =
        IF ( vDayThisYear <= 0vDayPrevYearvDayThisYear )
    RETURN
        vResult

     

    Pat

     

  • Please try this DAX table expression.  Just update the Sundays in the vSundays variable to bracket the date range.

     

    Date 445 =
    VAR vSundays =
        {
            DATE ( 20191229 ),
            DATE ( 20201227 ),
            DATE ( 20211226 ),
            DATE ( 20221225 )
        }
    VAR vCalendar =
        CALENDAR ( MINX ( vSundays, [Value] )MAXX ( vSundays, [Value] ) - 1 )
    VAR vAddDay =
        ADDCOLUMNS (
            vCalendar,
            "Day",
                VAR vFirstDOY =
                    MAXX ( FILTER ( vSundays, [Value] <= [Date] ), [Value] )
                RETURN
                    DATEDIFF ( vFirstDOY, [Date], DAY ) + 1
        )
    VAR vAddYearWeek =
        ADDCOLUMNS (
            vAddDay,
            "Year",
                YEAR ( MAXX ( FILTER ( vSundays, [Value] <= [Date] ), [Value] ) ) + 1,
            "Week"ROUNDUP ( [Day] / 70 )
        )
    VAR vAddMonth =
        ADDCOLUMNS (
            ADDCOLUMNS (
                vAddYearWeek,
                "MonthNum",
                    SWITCH (
                        TRUE (),
                        [Week] <= 41,
                        [Week] <= 82,
                        [Week] <= 133,
                        [Week] <= 174,
                        [Week] <= 215,
                        [Week] <= 266,
                        [Week] <= 307,
                        [Week] <= 348,
                        [Week] <= 399,
                        [Week] <= 4310,
                        [Week] <= 4711,
                        [Week] <= 5212
                    )
            ),
            "Month"FORMAT ( DATE ( 2020, [MonthNum], 1 )"MMMM" )
        )
    RETURN
        vAddMonth

     

    Pat

6 Replies

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

    You can make a DAX Date table like below starting on the first Sunday of your first year.

     

    Date 445 =
    ADDCOLUMNS (
        CALENDAR ( DATE ( 202015 )DATE ( 20211231 ) ),
        "Year"YEAR ( [Date] ),
        "DayOfWeek"FORMAT ( [Date], "dddd" )
    )

     

    Then you can add a DAX column to get the Day of the year with an expression like this.  The Day numbers of each year will line up.

     

    Day =
    VAR vThisYear = 'Date 445'[Year]
    VAR vFirstSunday =
        CALCULATE (
            MIN ( 'Date 445'[Date] ),
            ALL ( 'Date 445' ),
            'Date 445'[Year] = vThisYear,
            'Date 445'[DayOfWeek] = "Sunday"
        )
    VAR vPYFirstSunday =
        CALCULATE (
            MIN ( 'Date 445'[Date] ),
            ALL ( 'Date 445' ),
            'Date 445'[Year] = vThisYear - 1,
            'Date 445'[DayOfWeek] = "Sunday"
        )
    VAR vDayThisYear =
        DATEDIFF ( vFirstSunday, 'Date 445'[Date], DAY ) + 1
    VAR vDayPrevYear =
        DATEDIFF ( vPYFirstSunday, 'Date 445'[Date], DAY ) + 1
    VAR vResult =
        IF ( vDayThisYear <= 0vDayPrevYearvDayThisYear )
    RETURN
        vResult

     

    Pat

     

    • APM's avatar
      APM
      Icon for Helper I rankHelper I

      Hey mahoneypat , 

      Thanks!

      This worked generally really well, but I have one big issue:

       

      My retail calendar has, for example, for January 2020: December 29,2019 - January 25, 2020 (the calendar I showed you previously was actually off, and I got sent an updated copy).

       

      This is the correct calendar:

       

      Going through the days, I noticed that it counts days 1-7 and then restarts the count on January 5th. January 5 should be the 8th day, not day 1 again. This throws the whole set off again. Is there a fix for this?

       

      Also, having this built, I'm thinking now about the dashboard and slicers. 

       

      Since December 29, 2019 is actually the first day of January 2020 in my Calendar, when I create a slicer and select "January", the first day of my calendar's January won't show up.

       

      Is the only way around this to hardcode aMonth column in (either manually typing in 'January' etc or with a IF formula for each month)? Or is there a better way?

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

        Please try this DAX table expression.  Just update the Sundays in the vSundays variable to bracket the date range.

         

        Date 445 =
        VAR vSundays =
            {
                DATE ( 20191229 ),
                DATE ( 20201227 ),
                DATE ( 20211226 ),
                DATE ( 20221225 )
            }
        VAR vCalendar =
            CALENDAR ( MINX ( vSundays, [Value] )MAXX ( vSundays, [Value] ) - 1 )
        VAR vAddDay =
            ADDCOLUMNS (
                vCalendar,
                "Day",
                    VAR vFirstDOY =
                        MAXX ( FILTER ( vSundays, [Value] <= [Date] ), [Value] )
                    RETURN
                        DATEDIFF ( vFirstDOY, [Date], DAY ) + 1
            )
        VAR vAddYearWeek =
            ADDCOLUMNS (
                vAddDay,
                "Year",
                    YEAR ( MAXX ( FILTER ( vSundays, [Value] <= [Date] ), [Value] ) ) + 1,
                "Week"ROUNDUP ( [Day] / 70 )
            )
        VAR vAddMonth =
            ADDCOLUMNS (
                ADDCOLUMNS (
                    vAddYearWeek,
                    "MonthNum",
                        SWITCH (
                            TRUE (),
                            [Week] <= 41,
                            [Week] <= 82,
                            [Week] <= 133,
                            [Week] <= 174,
                            [Week] <= 215,
                            [Week] <= 266,
                            [Week] <= 307,
                            [Week] <= 348,
                            [Week] <= 399,
                            [Week] <= 4310,
                            [Week] <= 4711,
                            [Week] <= 5212
                        )
                ),
                "Month"FORMAT ( DATE ( 2020, [MonthNum], 1 )"MMMM" )
            )
        RETURN
            vAddMonth

         

        Pat

    • APM's avatar
      APM
      Icon for Helper I rankHelper I

      So I'm back to this setup, and I have been able to use the TODAY function to get this year's data and last year's data using a DAX formula.


      However, I'd really like to just have all the sales data flow in and then use a slicer to toggle between:

       

      • Today
      • Last Week
      • Month-To-Date

       

      Such that when I select "Today" in the slicer, sales data for today and the comparable day last year (as per above calendar) come up - and the same for last week and month-to-date (with comparable last year data for each).

       

      Does anyone know how to do this?

       

      Thanks!

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

    APM  You can start your calendar on DATE(2019,12,29) and use this column expression instead.  I'll think about the Month issue, but it should be doable.

     

    Day 2 =
    VAR vThisYear = 'Date 445'[Year]
    VAR vMaxSunday =
        CALCULATE (
            MAX ( 'Date 445'[Date] ),
            ALL ( 'Date 445' ),
            'Date 445'[Year] = vThisYear,
            'Date 445'[DayOfWeek] = "Sunday"
        )
    VAR vPYMaxSunday =
        CALCULATE (
            MAX ( 'Date 445'[Date] ),
            ALL ( 'Date 445' ),
            'Date 445'[Year] = vThisYear - 1,
            'Date 445'[DayOfWeek] = "Sunday"
        )
    VAR vDayThisYear =
        DATEDIFF ( vMaxSunday, 'Date 445'[Date], DAY ) + 1
    VAR vDayPrevYear =
        DATEDIFF ( vPYMaxSunday, 'Date 445'[Date], DAY ) + 1
    VAR vResult =
        IF ( [Date] >= vMaxSundayvDayThisYearvDayPrevYear )
    RETURN
        vResult

     

    Pat