How it works...

The first eight lines are designed for the user to define the starting numeric months and days on which their quarters begin. The ninth line grabs the year from the current date and the tenth line simply gets the date from the current row. These ten variables are then used throughout the remainder of the DAX calculation to determine to which quarter a date belongs.

Following along with the calculation, the next step is to create a table called __QuarterMonths. The DAX table constructor is used along with the starting month variables __Q1StartMonth, __Q2StartMonth, __Q3StartMonth, and __Q4StartMonth. On the next line, we calculate the maximum value of these starting months using the MAXX iterator function. It may not seem like it, but this is the real magic of this recipe. We need to know which quarter might roll over between years. In the example, that quarter is Q2, since part of Q2 is in one year (November and December) and part is in the next year (January and February). 

The first four conditions of the SWITCH statement are designed to catch the condition where a quarter rolls over from one year to the next. The only quarter that can possibly roll over from one year to the next is the quarter with the highest number for its starting month. Thus, this is the first check of each of these first four conditions. If this statement is true, then we know that the quarter might roll over from one year to the next, and so we check whether the date is greater than or equal to the starting date of the current quarter or less than the starting date of the next quarter. We use the DATE function to construct these dates from the variables set at the start of the recipe. We must have one of these statements for each quarter, since we have no idea where an organization might begin or end their quarters.

Once we account for the odd case of a quarter rolling over from one year to the next, the next four conditional statements are fairly straightforward. We can again construct dates using the DATE function for the starting and ending of quarters and simply check whether the current date under consideration is greater than or equal to the current quarter start date and less than the next quarter's start date. Again, we need one of these for each quarter.

Although the last condition for Q4 could have been replaced by the catch-all else condition of the SWITCH statement, it was instead decided to make the SWITCH statement conditions all inclusive and return an error if one of the conditions is not met. In other words, instead of checking explicitly for Q4, we could have had the last value for the SWITCH statement simply be Q4 instead of Error, the thought being that if none of the other conditions are met, the value must be Q4.

However, because this recipe is specifically designed for the user to enter their own values, it was determined safer to identify any odd condition as an error rather than masking it with a potentially incorrect Q4 value.

The really nifty part is that this recipe also works for standard calendar quarters!