Forum Discussion

ngadiez's avatar
ngadiez
Helper II
8 years ago
Solved

Minimum Difference between 2 dates

Hi all,

 

I have a table

John20180412
Dave20180131
Emily20171226
John20180205
Emily20180314
Dave20180405
John20180218
John20180125
Dave20180401
Emily

20180222

 

to

NameMin Difference (days)
John11
Dave4
Emily20

 

I am trying to use SUMX and SUMMARIZE but to not avail.

 

Is there any other way to get this? Using Calculated Column or Measure better?

@Greg_Deckler@MattAllington @Phil_Seamark @quentin_vigne

  • Anonymous's avatar
    Anonymous
    8 years ago

    This was a fun one. Took me a while, and I'll bet my solution isn't the prettiest or most efficient, but it works.

     

    For each date, to get the nearest date:

    Closest Date = 
    VAR previous = CALCULATE(MAX(Data[Date]), FILTER(Data, [Date] < EARLIER(Data[Date]) && [Name] = EARLIER(Data[Name])))
    VAR next = CALCULATE(MIN(Data[Date]), FILTER(Data, [Date] > EARLIER(Data[Date]) && [Name] = EARLIER(Data[Name])))
    VAR daysFromPrevious = DATEDIFF(previous, Data[Date], DAY)
    VAR daysFromNext = DATEDIFF(Data[Date], next, DAY) 
    return SWITCH(TRUE(),
        ISBLANK(next), previous,
        ISBLANK(previous), next,
        daysFromNext > daysFromPrevious, previous, next)

    Only a few swaps to get the days between that date and  the nearest date:

    Days From Closest Date = 
    VAR previous = CALCULATE(MAX(Data[Date]), FILTER(Data, [Date] < EARLIER(Data[Date]) && [Name] = EARLIER(Data[Name])))
    VAR next = CALCULATE(MIN(Data[Date]), FILTER(Data, [Date] > EARLIER(Data[Date]) && [Name] = EARLIER(Data[Name])))
    VAR daysFromPrevious = DATEDIFF(previous, Data[Date], DAY)
    VAR daysFromNext = DATEDIFF(Data[Date], next, DAY) 
    return SWITCH(TRUE(),
        ISBLANK(next), daysFromPrevious,
        ISBLANK(previous), daysFromNext,
        daysFromNext > daysFromPrevious, daysFromPrevious, daysFromNext)

     

    All that's left is a simple MIN()-based measure:

    Minimum Difference = MIN(Data[Days From Closest Date])

    Using variables really helps to break this problem down into its simplest components.

     

     

     

     

     

     

  • Hi ngadiez,

     

    The solution is achieved by "Summarize".

    Measure 2 =
    MINX (
        SUMMARIZE (
            'Table2',
            Table2[Name],
            Table2[Date],
            "dates", DATEDIFF (
                [Date],
                CALCULATE (
                    MIN ( 'Table2'[Date] ),
                    FILTER (
                        ALLEXCEPT ( 'Table2', Table2[Name] ),
                        'Table2'[Date] > MIN ( 'Table2'[Date] )
                    )
                ),
                DAY
            )
        ),
        [dates]
    )
    

    Minimum_Difference_between_2_dates

     

    Best Regards,

    Dale

  • OwenAuger's avatar
    OwenAuger
    8 years ago

    v-jiascu-msft

    That's very good - we just need to compare each date with the next date!

    You've inspired one last version from me (first time I've used NATURALINNERJOIN in a measure):

    Min Difference (Days) v3 = 
    VAR DateList =
        VALUES ( Data[Date] )
    VAR DateListIndexed =
        ADDCOLUMNS ( DateList, "Index", RANKX ( DateList, Data[Date],, ASC ) )
    VAR DateListIndexedPlusOne =
        SELECTCOLUMNS ( DateListIndexed, "Date2", Data[Date], "Index", [Index] + 1 )
    VAR Joined =
        NATURALINNERJOIN ( DateListIndexed, DateListIndexedPlusOne )
    RETURN
        MINX ( Joined, ABS ( [Date] - [Date2] ) )

    Regards,

    Owen

     

5 Replies

  • Anonymous's avatar
    Anonymous
    Not applicable

    This was a fun one. Took me a while, and I'll bet my solution isn't the prettiest or most efficient, but it works.

     

    For each date, to get the nearest date:

    Closest Date = 
    VAR previous = CALCULATE(MAX(Data[Date]), FILTER(Data, [Date] < EARLIER(Data[Date]) && [Name] = EARLIER(Data[Name])))
    VAR next = CALCULATE(MIN(Data[Date]), FILTER(Data, [Date] > EARLIER(Data[Date]) && [Name] = EARLIER(Data[Name])))
    VAR daysFromPrevious = DATEDIFF(previous, Data[Date], DAY)
    VAR daysFromNext = DATEDIFF(Data[Date], next, DAY) 
    return SWITCH(TRUE(),
        ISBLANK(next), previous,
        ISBLANK(previous), next,
        daysFromNext > daysFromPrevious, previous, next)

    Only a few swaps to get the days between that date and  the nearest date:

    Days From Closest Date = 
    VAR previous = CALCULATE(MAX(Data[Date]), FILTER(Data, [Date] < EARLIER(Data[Date]) && [Name] = EARLIER(Data[Name])))
    VAR next = CALCULATE(MIN(Data[Date]), FILTER(Data, [Date] > EARLIER(Data[Date]) && [Name] = EARLIER(Data[Name])))
    VAR daysFromPrevious = DATEDIFF(previous, Data[Date], DAY)
    VAR daysFromNext = DATEDIFF(Data[Date], next, DAY) 
    return SWITCH(TRUE(),
        ISBLANK(next), daysFromPrevious,
        ISBLANK(previous), daysFromNext,
        daysFromNext > daysFromPrevious, daysFromPrevious, daysFromNext)

     

    All that's left is a simple MIN()-based measure:

    Minimum Difference = MIN(Data[Days From Closest Date])

    Using variables really helps to break this problem down into its simplest components.

     

     

     

     

     

     

  • Hi ngadiez

    Here's another version, just a measure:

    (PBIX link for reference)

     

    Min Difference (days) = 
    VAR DateList =
        VALUES ( Data[Date] )
    RETURN
        MINX (
            GENERATE (
                SELECTCOLUMNS ( DateList, "Date1", Data[Date] ),
                SELECTCOLUMNS ( EXCEPT ( DateList, { [Date1] } ), "Date2", Data[Date] )
            ),
            ABS ( [Date1] - [Date2] )
        )

     

    EDIT: Possible improvement if we restrict Date2 > Date1:

    Min Difference (days) v2 = 
    VAR DateList =
        VALUES ( Data[Date] )
    RETURN
        MINX (
            GENERATE (
                SELECTCOLUMNS ( DateList, "Date1", Data[Date] ),
                SELECTCOLUMNS ( FILTER ( DateList, Data[Date] > [Date1] ), "Date2", Data[Date] )
            ),
            ABS ( [Date1] - [Date2] )
        )

     

    Note these assume there are no repeated dates, so the difference is the minimum difference between distinct dates.

     

    Regards,

    Owen

  • v-jiascu-msft's avatar
    v-jiascu-msft
    Microsoft Employee

    Hi ngadiez,

     

    The solution is achieved by "Summarize".

    Measure 2 =
    MINX (
        SUMMARIZE (
            'Table2',
            Table2[Name],
            Table2[Date],
            "dates", DATEDIFF (
                [Date],
                CALCULATE (
                    MIN ( 'Table2'[Date] ),
                    FILTER (
                        ALLEXCEPT ( 'Table2', Table2[Name] ),
                        'Table2'[Date] > MIN ( 'Table2'[Date] )
                    )
                ),
                DAY
            )
        ),
        [dates]
    )
    

    Minimum_Difference_between_2_dates

     

    Best Regards,

    Dale

    • OwenAuger's avatar
      OwenAuger
      Super User

      v-jiascu-msft

      That's very good - we just need to compare each date with the next date!

      You've inspired one last version from me (first time I've used NATURALINNERJOIN in a measure):

      Min Difference (Days) v3 = 
      VAR DateList =
          VALUES ( Data[Date] )
      VAR DateListIndexed =
          ADDCOLUMNS ( DateList, "Index", RANKX ( DateList, Data[Date],, ASC ) )
      VAR DateListIndexedPlusOne =
          SELECTCOLUMNS ( DateListIndexed, "Date2", Data[Date], "Index", [Index] + 1 )
      VAR Joined =
          NATURALINNERJOIN ( DateListIndexed, DateListIndexedPlusOne )
      RETURN
          MINX ( Joined, ABS ( [Date] - [Date2] ) )

      Regards,

      Owen