DAX: Calculate Start Dates Based on Duration & Order - powerbi

I have a table that I am trying to convert into a gantt chart. This table contains the task order (sometimes the same for those in parallel), as well as a task duration (by quarter).
If I have a Project Start Date = 1/1/2020, how could I calculate the Start & End dates for each subsequent task?
Example,
Task A: Order = 1, Duration = 4 ---> Start = 1/1/2020, End = 1/1/2021
Task B: Order = 2, Duration = 1 ---> Start = 1/1/2021, End = 3/1/2021
Task C: Order = 3, Duration = 2 ---> Start = 3/1/2021, End = 9/1/2021

You can calculate the total duration elapsed using appropriate filter modifiers. Then you can use EDATE function to get the start and end dates from the project start date adding elapsed months.
Here is an example formula of start date in a calculated column.
StartDate =
VAR ProjectStartDate = Date ( 2020, 1, 1 )
VAR CurrentOrder = Tasks[Order]
-- Quarters passed since the project start date before the current task
VAR DurationElapsedBefore = CALCULATE (
SUM ( Tasks[Duration] ),
REMOVEFILTERS (),
Tasks[Order] < CurrentOrder
)
-- Multiplying by 3 to turn quarters into months
RETURN EDATE ( ProjectStartDate, DurationElapsedBefore * 3 )
The formula for end date is just replacing < with <= inside CALCULATE.

Related

Last month average constant in Power-Bi

I am working in Power-Bi desktop. I need to compute a constant measure (same for all rows) that indicates me the daily average of the amounts stored in a column named "Values" considering the last month as window. The distinct-count for the days of the last month has to exclude the last two days of the week. The window has to start Today() - [DELTA], where DELTA is a constant number of days.
An example below (which is rolling, not constant, and does not include DELTA):
dailyAverageValue =
var nobs = CALCULATE(DISTINCTCOUNT(TABLE[DATE]), PREVIOUSMONTH(TABLE[DATE]), TABLE[WEEK_DAY_NO] <> 6, TABLE[WEEK_DAY_NO] <> 7)
var summ = CALCULATE(SUM(TABLE[VALUES], PREVIOUSMONTH(TABLE[DATE]))
return summ/nobs
dailyAverageValue =
var nobs = CALCULATE(DISTINCTCOUNT(TABLE[DATE]), DATESINPERIOD(TABLE[DATE], TODAY() - [DELTA], -[WINDOW], DAY))
var summ = CALCULATE(SUM(TABLE[VALUES]), DATESINPERIOD(TABLE[DATE], TODAY() - [DELTA], -[WINDOW], DAY))
return summ/nobs

Power BI calculating time difference excluding weekends and non working hours

I have the below table and calculating the durations between First_change_Date and Create_date using this DAX formula:
Response_time =
VAR Minutes = DATEDIFF('otrs ticket Response'[otrs ticket.create_time], 'otrs ticket Response'[First_Change_time],MINUTE)
var days =INT(Minutes/1440)
var hourNo=INT(MOD(Minutes,1440) / 60)
var minuteNO=MOD(Minutes,60)
RETURN
CONCATENATE( CONCATENATE( CONCATENATE(days,"d "), CONCATENATE(hourNo, "H ")), CONCATENATE(minuteNO, "m "))
I want to exclude the weekends (Friday, Saturday in my case) and non working hours (5:00pm - 9:00am)
Data:
For my client, I have created a logic. First created a WorkingHoursTable.
Then created a calculated column with the following formula, in the table which has the start and end dateTime's.
Working Hours Between Dates =
var startDate = [yourStartDateTime].[Date]
var startTime = [yourStartDateTime] - startDate
var endDate = [yourEndDateTime].[Date]
var endTime = [yourEndDateTime] - endDate
var firstFullDay = startDate + 1
var lastFullDay = endDate - 1
var inBetweenWorkingHours =
IF(
firstFullDay > lastFullDay,
0,
SUMX(CALENDAR(firstFullDay, lastFullDay), LOOKUPVALUE(WorkingHoursTable[WorkingHoursInAllDay], WorkingHoursTable[WeekDay], WEEKDAY([Date], 2)))
)
var firstDayStart = LOOKUPVALUE(WorkingHoursTable[StartTime], WorkingHoursTable[WeekDay], WEEKDAY(startDate, 2))
var firstDayEnd = LOOKUPVALUE(WorkingHoursTable[EndTime], WorkingHoursTable[WeekDay], WEEKDAY(startDate, 2))
var lastDayStart = LOOKUPVALUE(WorkingHoursTable[StartTime], WorkingHoursTable[WeekDay], WEEKDAY(endDate, 2))
var lastDayEnd = LOOKUPVALUE(WorkingHoursTable[EndTime], WorkingHoursTable[WeekDay], WEEKDAY(endDate, 2))
var effectiveStartTime = IF(startTime < firstDayStart, firstDayStart, startTime)
var effectiveEndTime = IF(endTime > lastDayEnd, lastDayEnd, endTime)
return
IF(
startDate = endDate,
24 * IF(effectiveEndTime > effectiveStartTime, effectiveEndTime - effectiveStartTime, 0),
var firstDayWorkingHour =
24 *
IF(
startTime > firstDayEnd,
0,
firstDayEnd - effectiveStartTime
)
var lastDayWorkingHour =
24 *
IF(
endTime < lastDayStart,
0,
effectiveEndTime - lastDayStart
)
return firstDayWorkingHour + lastDayWorkingHour + inBetweenWorkingHours
)
In this formula you just set the first 4 variables correctly. Then it will calculate total working hours. Unit will be in hours.
Edit: As I see from your post that your weekends are Friday and Saturday, you will need to use WEEKDAY functions slightly different. You can send 1 as a second parameter to WEEKDAY function, instead of 2. You will also need to modify the WeekDay column of WorkingHoursTable.
After this one, you can parse it to '9d 20H 52m' with your formula.
I split the date/time in to date and time columns. I then use a date dimension, where one of the columns is "Is Working Day" = TRUE(), based on which day of the week it is (a simple calculated column). In the time dimension, you do the same to identify "Working Hour" = TRUE(), again, a simple calculation.
Once you have the dimensions in place it then becomes very easy to build your calculations to include / exclude.

Calculating a Moving Average for 3 months without blank values in DAX Power BI

I have Client Services table with [Billable Minutes] value.
I need to create [Moving Average for 3 months] measure, where the calculation will
only happen - if there are values in all 3 months in [Billable Minutes] exist !
(See below)
If [Billable Minutes] value is blank in at least one month in my Client Services table, then I want [Moving Avg] will show 0 or blank!
My goal:
Client Services table: Result:
Period [Billable Minutes] Period [Moving Avg]
2018-11 200 2019-01 200
2018-12 300
2019-01 100
To reach my goal, I am using the following DAX expression for [Moving Avg 3 months]:
Moving Avg 3 month =
VAR PeriodToUse = DATESINPERIOD('Calendar FY'[Date], LASTDATE('Calendar FY'[Date]), -3, MONTH)
VAR Result = CALCULATE(DIVIDE([Billable Minutes], COUNTROWS ('Calendar FY')), PeriodToUse)
VAR ZeroValue=IF(Minx('Client Services',[Billable Minutes])=0,0,Result)
Return Result
But, unfortunately, my end result is:
Client Services table: Result:
Period [Billable Minutes] Period [Moving Avg]
2018-11 200 2018-11 67
2018-12 300 2018-12 167
2019-01 100 2019-01 200
So, it takes an existing values in Client Services table and divides them by the number of periods.
For example for 2018-11, 2018-10, 2018-09 - it takes (200+0+0)/3=66.6 (67 rounded)
But I need the Moving Avg would be empty for 2018-11, because there are no values for 2018-10, 2018-09 in the Client Services table (same - for 2018-12, should not calculate)
Please, HELP!
Updated:
Here is the solution for this (thx to the answer below)
In order to check if there zero in the selected period, extra measures should be created:
Billable Minutes
Moving Avg Prev Month = Calculate('Client Services'[Billable Minutes],
PREVIOUSMONTH('Calendar FY'[Date]))
Billable Minutes
Moving Avg 2nd Prev Month = Calculate
('Client Services'[Billable Minutes Prev Month],
PREVIOUSMONTH('Calendar FY'[Date]))
Then, when you check whether there are zero values - you need to check it - not
just for [Billable Minutes], but for [Billable Minutes] within 3 months period =
within
[Billable Minutes]+[Billable Minutes Prev Month]+
[Billable Minutes 2nd Prev Month]
See the updated below (worked perfect):
enter
Billable Minutes 3 Months Avg =
VAR PeriodToUse = DATESINPERIOD('Calendar FY'[Date],
LASTDATE('Calendar FY'[Date]), -3, MONTH)
VAR Result = CALCULATE(DIVIDE([Billable Minutes],
COUNTROWS ('Calendar FY')), PeriodToUse)
VAR NMonthsPeriodBlank =
if([Billable Minutes] = BLANK(),0,1) +
if([Billable Minutes Prev Month] = BLANK(),0,1) +
if([Billable Minutes 2nd Prev Month] = BLANK(),0,1)
RETURN IF(NMonthsPeriodBlank < 3, BLANK(), Result)
Follow these below steps-
Step-1: Convert your Period column to Date considering 1st date of each month as below-
Step-2: Get back to report by clicking Close & Apply and create this below 4 measures-
total = SUM('Client Services'[Billable Minutes])
total prev = CALCULATE([total],PREVIOUSMONTH('Client Services'[Period]))
total second prev = CALCULATE([total prev],PREVIOUSMONTH('Client Services'[Period]))
3 month avergae =
VAR devide_by = if([total] = BLANK(),0,1) + if([total prev] = BLANK(),0,1) + if([total second prev] = BLANK(),0,1)
VAR total_amount = [total] + [total prev] + [total second prev]
RETURN IF(
devide_by < 3,
BLANK(),
total_amount/devide_by
)
Here is the final output-
====================
Solution in single measure
====================
You can convert all measures into 1 measure as below-
3 month average new =
VAR this_month = SUM('Client Services'[Billable Minutes])
VAR prev_month =
CALCULATE(
SUM('Client Services'[Billable Minutes]),
PREVIOUSMONTH('Client Services'[Period])
)
VAR second_prev_month =
CALCULATE(
SUM('Client Services'[Billable Minutes]),
PREVIOUSMONTH(
DATEADD(
'Client Services'[Period],
-1,
MONTH
)
)
)
VAR devide_by =
if(this_month = BLANK(),0,1) +
if(prev_month = BLANK(),0,1) +
if(second_prev_month = BLANK(),0,1)
VAR total_amount = this_month + prev_month + second_prev_month
RETURN IF(
devide_by < 3,
BLANK(),
total_amount/devide_by
)

Sum row with next row value and grab next value in other column for the date selected

Let's say I have this data:
Earn Earn Cum.
13-Apr - -
14-Apr 48 48
15-Apr 257 305
16-Apr 518 823
17-Apr 489 1,312
18-Apr 837 2,149
19-Apr 1,005 3,154
20-Apr 1,021 4,175
21-Apr 1,463 5,638
22-Apr 2,630 8,268
23-Apr 2,993 11,261
24-Apr 3,354 14,615
25-Apr 4,332 18,947
26-Apr 4,885 23,832
27-Apr 4,514 28,346
28-Apr 4,356 32,702
29-Apr 4,824 37,526
30-Apr 7,082 44,608
1-May 6,091 50,699
2-May 1,407 52,106
When a date is selected in a dropdown slicer for example: 1-May I'd like to sum the rows 1-May with the next row 2-May for the column Earn and grab the next value 52,106 for the column Earn Cum.. The result should be:
1-May 7,498 52,106
Another example: if the date selected was 30-Apr the result must be:
30-Apr 13,173 50,699
I'm scratching my head trying to do this using a measure in Power BI.
I'll call your table "Data".
Create a measure:
Next Earn =
VAR Current_Date = MAX ( Data[Date] )
VAR Next_Date = Current_Date + 1
RETURN
CALCULATE (
SUM ( Data[Earn] ),
Data[Date] = Current_Date || Data[Date] = Next_Date
)
Create another measure:
Next Cum Earn =
VAR Current_Date = MAX ( Data[Date] )
VAR Next_Date = Current_Date + 1
RETURN
CALCULATE ( SUM ( Data[Earn Cum] ), Data[Date] = Next_Date )
Result:
Note: the code assumes that your dates are sequential (no gaps). If they have gaps, things are a bit more complex.
It will help to have access to date intelligence, so create a date table if you don't have one already. The following dax sets up a small table that just barely covers the sample data in your example.
Date = CALENDAR(Date(2019,4,10),Date(2019,5,5))
Create a relationship between the Dates in your table and the new Date dimension. Add a slicer to your visuals using the Date dimension.
We can use IF and ISFILTERED to check if filtering is being done. If we aren't filtering on Date then we get the normal table behavior. If we are, we'll see our modified result.
Earn _ Alt =
var tomorrow = CALCULATE (
SUM(Table1[Earn]),
dateadd('Table1'[Date], 1, DAY)
)
return Sum(Table1[Earn]) + IF(ISFILTERED`('Date'[Date]),tomorrow,0)`
and
Earn Cum. _ Alt = IF(ISFILTERED('Date'[Date]),
CALCULATE (
SUM(Table1[Earn Cum.]),
dateadd('Table1'[Date], 1, DAY)
),
SUM(Table1[Earn Cum.]))
Results:
-Unfiltered-
-Filtered-

Why does operator <= (less than or equal) not return expected result when date is variable?

Problem: DAX is not returning expected result in if statement with operator when date is a variable.
Background: I've checked to make sure that there is no date or time difference.
Dates are ALL in format (1stday of month, 12:00:00AM). I have 2 years (2018 & 2019: 24 distinct dates).
I've tried to use the <= operator in a calculated column to determine if a date is "Before/Same" to a variable date or "After". I've tried to combine < filter and = filter with || (or), same result.
TestColumn =
var CurrentDate = [Current_Period]
return
IF(
ValuesTable[Month-Year] <= CurrentDate,
"Before/Same", "After"
)
FYI: The [Current_Period] Measure, this works fine, returns one date as expected
Current_Period =
VAR ThisActMonth =
CALCULATE (
DISTINCT ( Fact_FX[Month-Year] ),
Fact_FX[bool_Latest_FX_Act] = TRUE ()
)
RETURN
ThisActMonth
I would expect that for every row where the Month-Year (Date) <= the result would be "Before/Same";
however, The result I currently get is:
"Before/Same" only where ValuesTable[Month-Year] = CurrentDate
CurrentDate = April 2019
"After" all other Months (23)
Please Help!
What's happening is that you are evaluating your Current_Period measure within the row context of the calculated column, so the measure doesn't see the row with Fact_FX[bool_Latest_FX_Act] = TRUE () except in the April row.
The solution is to calculate the Current_Period outside of that evaluation context and there are multiple possible approaches. A quick solution would be to remove row context using the ALL function inside of your CALCULATE:
Current_Period =
VAR ThisActMonth =
CALCULATE (
DISTINCT ( Fact_FX[Month-Year] ),
ALL( Fact_FX ),
Fact_FX[bool_Latest_FX_Act] = TRUE ()
)
RETURN
ThisActMonth