Forum Discussion

buttercream's avatar
buttercream
Helper II
2 years ago
Solved

Calculating Stage Duration in a Column

Hello,

 

Trying to calculate the number of business days between stages.  A SalesID is considered New until it is invoiced.  Any following  instances of "Invoiced" should be labelled Existing and should be calculated separately.  See below table for example.  The fields in red are needed as calculated columns (not measures).

 

SalesIDStageDateNew/ExistingRankDuration
10Entered4/1/2024New18
10Processed4/10/2024New213
10Invoiced4/26/2024New30
12Entered5/1/2024New13
12Processed5/3/2024New26
12Invoiced5/10/2024New30
12Returned3/1/2024Existing13
12Adjusted3/5/2024Existing214
12Invoiced3/23/2024Existing30
12Returned7/7/2024Existing11
12Researched7/8/2024Existing23
12Adjusted7/10/2024Existing316
12Invoiced7/31/2024Existing40
  • Hi buttercream - Create below calcualted column to get the New/Existing

    Calculated column:

    NewExisting =
    VAR FirstInvoiceDate =
        CALCULATE(
            MIN(Stage[Date]),
            Stage[Stage] = "Invoiced",
            ALLEXCEPT(Stage, Stage[SalesID])
        )
    RETURN
        IF(
            Stage[Date] <= FirstInvoiceDate,
            "New",
            "Existing"
        )

     

     

    create another calculated column to bring the rank

    Rank =
    RANKX(
        FILTER(
            Stage,
            Stage[SalesID] = EARLIER(Stage[SalesID]) &&
            Stage[NewExisting] = EARLIER(Stage[NewExisting])
        ),
        Stage[Date],
        ,
        ASC,
        DENSE
    )

     

    calcualte the duration calculated column :

    Duration =
    VAR CurrentDate = Stage[Date]
    VAR NextDate =
        CALCULATE(
            MIN(Stage[Date]),
            FILTER(
                Stage,
                Stage[SalesID] = EARLIER(Stage[SalesID]) &&
                Stage[NewExisting] = EARLIER(Stage[NewExisting]) &&
                Stage[Rank] = EARLIER(Stage[Rank]) + 1
            )
        )
    VAR BusinessDays =
        IF(
            NOT ISBLANK(NextDate),
            COUNTROWS(
                FILTER(
                    ADDCOLUMNS(
                        CALENDAR(CurrentDate, NextDate),
                        "IsBusinessDay",
                        WEEKDAY([Date], 2) < 6
                    ),
                    [IsBusinessDay] = TRUE
                )
            ) - 1,
            0
        )
    RETURN
        BusinessDays

     

    Replace the table name as per your model.

     

     

    Hope it works

     

     

3 Replies

  • Hi buttercream - Create below calcualted column to get the New/Existing

    Calculated column:

    NewExisting =
    VAR FirstInvoiceDate =
        CALCULATE(
            MIN(Stage[Date]),
            Stage[Stage] = "Invoiced",
            ALLEXCEPT(Stage, Stage[SalesID])
        )
    RETURN
        IF(
            Stage[Date] <= FirstInvoiceDate,
            "New",
            "Existing"
        )

     

     

    create another calculated column to bring the rank

    Rank =
    RANKX(
        FILTER(
            Stage,
            Stage[SalesID] = EARLIER(Stage[SalesID]) &&
            Stage[NewExisting] = EARLIER(Stage[NewExisting])
        ),
        Stage[Date],
        ,
        ASC,
        DENSE
    )

     

    calcualte the duration calculated column :

    Duration =
    VAR CurrentDate = Stage[Date]
    VAR NextDate =
        CALCULATE(
            MIN(Stage[Date]),
            FILTER(
                Stage,
                Stage[SalesID] = EARLIER(Stage[SalesID]) &&
                Stage[NewExisting] = EARLIER(Stage[NewExisting]) &&
                Stage[Rank] = EARLIER(Stage[Rank]) + 1
            )
        )
    VAR BusinessDays =
        IF(
            NOT ISBLANK(NextDate),
            COUNTROWS(
                FILTER(
                    ADDCOLUMNS(
                        CALENDAR(CurrentDate, NextDate),
                        "IsBusinessDay",
                        WEEKDAY([Date], 2) < 6
                    ),
                    [IsBusinessDay] = TRUE
                )
            ) - 1,
            0
        )
    RETURN
        BusinessDays

     

    Replace the table name as per your model.

     

     

    Hope it works

     

     

  • Hello buttercream 

     

    There are two options for doing this. I would provide both the solutions. Try using them and see if they work.

     

    Using advanced Editor in Power Query Mode.

    let
    Source = ... // your source step,

    // Define a function to calculate business days between two dates
    BusinessDaysBetween = (StartDate as date, EndDate as date) =>
    let
    DayCount = List.Count(List.Select(List.Dates(StartDate, Duration.Days(EndDate - StartDate) + 1, #duration(1, 0, 0, 0)), each not Date.IsInCurrentMonth(_))),
    BusinessDays = List.Count(List.Select(List.Dates(StartDate, Duration.Days(EndDate - StartDate) + 1, #duration(1, 0, 0, 0)), each Date.DayOfWeek(_, Day.Monday) < 5))
    in
    BusinessDays,

    // Add the "New/Existing" column based on your logic
    AddNewExisting = Table.AddColumn(Source, "New/Existing", each if [Stage] = "Invoiced" and [Rank] > 1 then "Existing" else "New"),

    // Sort the table by SalesID and Date
    SortTable = Table.Sort(AddNewExisting,{{"SalesID", Order.Ascending}, {"Date", Order.Ascending}}),

    // Add Rank column
    AddRank = Table.Group(SortTable, {"SalesID"}, {
    {"AllData", each Table.AddIndexColumn(_, "Rank", 1, 1, Int64.Type)}
    }),
    ExpandData = Table.ExpandTableColumn(AddRank, "AllData", {"SalesID", "Stage", "Date", "New/Existing", "Rank"}),

    // Add Duration column
    AddDuration = Table.AddColumn(ExpandData, "Duration", each if [New/Existing] = "Existing" then BusinessDaysBetween([Date], List.Min(Table.SelectRows(ExpandData, each [SalesID] = [SalesID] and [Rank] = [Rank] - 1)[Date])) else null, Int64.Type)
    in
    AddDuration

     

    Using DAX:

    Create a calculated Column:

    New/Existing =
    IF (
    [Stage] = "Invoiced" && [Rank] > 1,
    "Existing",
    "New"
    )

     

    Duration =
    VAR CurrentDate = [Date]
    VAR PreviousDate =
    CALCULATE (
    MAX([Date]),
    FILTER (
    Table,
    [SalesID] = EARLIER([SalesID]) && [Rank] = EARLIER([Rank]) - 1
    )
    )
    RETURN
    IF (
    [New/Existing] = "Existing" && NOT ISBLANK(PreviousDate),
    NETWORKDAYS(PreviousDate, CurrentDate),
    BLANK()
    )

     

    Did I answer your question? Mark my post as a solution!
    If I helped you, click on the Thumbs Up to give Kudos.