Home » Calculate Name-Based Durations

Calculate Name-Based Durations

Work out the durations in hours against all names. First row beneath each name is Start Date and Time and second row beneath each name is End Date and Time. Duration is End Date Time – Start Date Time.

📌 Challenge Details and Links
ExcelBI Excel Challenge Number: 573
Challenge Difficulty: ⭐️
📥Download Sample File
📥Link to the solutions on LinkedIn

Solving the challenge of Calculate Name-Based Durations with Power Query

Power Query solution 1 for Calculate Name-Based Durations, proposed by Kris Jaganah:
let
  A = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content], 
  B = Table.ToColumns(A), 
  C = List.Select(B{0}, each Text.From(_) = _), 
  D = List.Transform(List.Difference(B{0}, C), Number.From), 
  E = List.Transform(
    List.Split(List.Transform({0 .. List.Count(D) - 1}, each D{_} + List.RemoveNulls(B{1}){_}), 2), 
    (x) => (x{1} - x{0}) * 24
  ), 
  F = Table.FromColumns({C, E}, {"Name", "Duration"})
in
  F
Power Query solution 2 for Calculate Name-Based Durations, proposed by Kris Jaganah:
let
  A = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content], 
  B = Table.AddColumn(A, "Num", each Number.From([#"Name & Date"]) + [Time]), 
  C = Table.TransformColumns(B, {"Name & Date", each if Text.From(_) = _ then _ else null}), 
  D = Table.FillDown(C, {"Name & Date"}), 
  E = Table.Group(D, {"Name & Date"}, {"Duration", each ([Num]{2} - [Num]{1}) * 24})
in
  E
Power Query solution 3 for Calculate Name-Based Durations, proposed by Aditya Kumar Darak 🇮🇳:
let
  Source = Excel.CurrentWorkbook(){[Name = "data"]}[Content], 
  Rename = Table.RenameColumns(Source, {{"Name & Date", "Name"}}), 
  Return = Table.Group(
    Rename, 
    "Name", 
    {
      "Duration", 
      each [
        S = Date.From(_{1}[Name]) & Time.From(_{1}[Time]), 
        E = Date.From(_{2}[Name]) & Time.From(_{2}[Time]), 
        R = Duration.TotalHours(E - S)
      ][R]
    }, 
    0, 
    (x, y) => 1 - Number.From(y is datetime)
  )
in
  Return
Power Query solution 4 for Calculate Name-Based Durations, proposed by Alejandro Simón 🇵🇦 🇪🇸:
let
  Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content], 
  Rename = Table.RenameColumns(Source, {{"Name & Date", "Name"}}), 
  Sol = Table.Group(
    Rename, 
    "Name", 
    {
      {
        "Duration", 
        each 
          let
            a = Table.Skip(_), 
            b = Table.AddColumn(a, "A", each Date.From([Name]) & Time.From([Time]))[A], 
            c = Duration.TotalHours(List.Last(b) - b{0})
          in
            c
      }
    }, 
    0, 
    (x, y) => Number.From(y is text)
  )
in
  Sol
Power Query solution 5 for Calculate Name-Based Durations, proposed by Alejandro Simón 🇵🇦 🇪🇸:
let
Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
Ren = Table.RenameColumns(Source,{{"Name & Date", "Name"}}),
Sol = Table.Group(Ren, "Name", {{"Duration", each 
 let
 a = Table.Skip(_),
 b = Table.AddColumn(a,"A", each 
 let 
 c = [Name],
 d = [Time],
 e = hashtag#datetime(Date.Year(c), Date.Month(c), Date.Day(c), 
 Time.Hour(Time.From(d)), Time.Minute(Time.From(d)), 0)
 in e)[A],
 f = Number.From(List.Last(b) - b{0})*24
 in f}},0, (x,y)=>Number.From(y is text))
in
Sol


                    
                  
          
Power Query solution 6 for Calculate Name-Based Durations, proposed by Abdallah Ally:
let
  Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content], 
  AddCol1 = Table.AddColumn(
    Source, 
    "DateTime", 
    each try Number.From([#"Name & Date"]) + [Time] otherwise null
  ), 
  AddCol2 = Table.AddColumn(
    AddCol1, 
    "Name", 
    each if [DateTime] = null then [#"Name & Date"] else null
  ), 
  FillDown = Table.FillDown(AddCol2, {"Name"}), 
  Result = Table.Group(
    FillDown, 
    {"Name"}, 
    {"Duration", each [a = List.RemoveNulls([DateTime]), b = (a{1} - a{0}) * 24][b]}
  )
in
  Result
Power Query solution 7 for Calculate Name-Based Durations, proposed by Bhaskar Joshi:
let
  Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content], 
  Table.Rename = Table.RenameColumns(Source, {{"Name & Date", "Date"}}), 
  Table.Group = Table.Group(
    Table.Rename, 
    "Date", 
    {
      {
        "Details", 
        each 
          let
            rawTable = Table.Skip(_), 
            Entry    = Date.From(rawTable[Date]{0}) & Time.From(rawTable[Time]{0}), 
            Exit     = Date.From(rawTable[Date]{1}) & Time.From(rawTable[Time]{1}), 
            Net      = Exit - Entry
          in
            Duration.TotalHours(Net), 
        type number
      }
    }, 
    GroupKind.Local, 
    (x as text, y as any) as number => 1 - Number.From(not (y is text))
  )
in
  Table.Group

Solving the challenge of Calculate Name-Based Durations with Excel

Excel solution 1 for Calculate Name-Based Durations, proposed by Bo Rydobon 🇹🇭:
=LET(a,WRAPROWS(A3:A14,3),HSTACK(TAKE(a,,1),MMULT(DROP(a+WRAPROWS(B3:B14,3),,1),{-24;24})))
Excel solution 2 for Calculate Name-Based Durations, proposed by Rick Rothstein:
=LET(a,A3:A14,b,b3:b14,HSTACK(FILTER(a,ISTEXT(a)),BYROW(WRAPROWS(FILTER(a+B,ISNUMBER(B)),2),LAMBDA(r,24*(MAX(r)-MIN(r))))))
Excel solution 3 for Calculate Name-Based Durations, proposed by Kris Jaganah:
=LET(a,
    A3:A14,
    b,
    SCAN(
        ,
        a,
        LAMBDA(
            x,
            y,
            IF(
                ISTEXT(
                    y
                ),
                y,
                x
            )
        )
    ),
    c,
    IFERROR(
        a+B3:B14,
        
    ),
    SORTBY(GROUPBY(b,
    (XLOOKUP(
        b,
        b,
        c,
        ,
        ,
        -1
    )-c)*24,
    SUM,
    ,
    0,
    ,
    c>0),
    UNIQUE(
        b
    )))
Excel solution 4 for Calculate Name-Based Durations, proposed by Julian Poeltl:
=LET(D,
    A3:B14,
    C,
    TAKE(
        D,
        ,
        1
    ),
    F,
    FILTER(
        C,
        NOT(
            ISNUMBER(
                C
            )
        )
    ),
    W,
    WRAPROWS(
        TOROW(
            BYROW(
                FILTER(
                    D,
                    ISNUMBER(
                C
            )
                ),
                SUM
            )
        ),
        2
    ),
    HSTACK(F,
    (DROP(
        W,
        ,
        1
    )-TAKE(
        W,
        ,
        1
    ))*24))
Excel solution 5 for Calculate Name-Based Durations, proposed by Timothée BLIOT:
=LET(A,
    A3:A14,
    F,
    LAMBDA(
        n,
        m,
        FILTER(
            n,
            m(
                A
            )
        )
    ),
    S,
    WRAPROWS(
        F(
            A,
            ISNUMBER
        )+F(
            B3:B14,
            ISNUMBER
        ),
        2
    ),
    HSTACK(F(
        A,
        ISTEXT
    ),
    (TAKE(
        S,
        ,
        -1
    )-TAKE(
        S,
        ,
        1
    ))*24))
Excel solution 6 for Calculate Name-Based Durations, proposed by Hussein SATOUR:
=LET(O,
    OFFSET,
    D,
    MAP(B3:B14,
    LAMBDA(x,
    IF(x="",
    (SUM(
        O(
            x,
            2,
            -1,
            ,
            2
        )
    )-SUM(
        O(
            x,
            1,
            -1,
            ,
            2
        )
    ))*24,
    ""))),
    FILTER(
        HSTACK(
            A3:A14,
            D
        ),
        D<>""
    ))
Excel solution 7 for Calculate Name-Based Durations, proposed by Oscar Mendez Roca Farell:
=LET(d,
    A3:B14,
    n,
    TAKE(
        d,
        ,
        1
    ),
    HSTACK(FILTER(
        n,
        n>"A"
    ),
    24*BYROW(WRAPROWS(TOCOL((1/BYROW(
        d,
        SUM
    ))^-1,
    2),
    2)*{-1,
    1},
    SUM)))
Excel solution 8 for Calculate Name-Based Durations, proposed by LEONARD OCHEA 🇷🇴:
=LET(I,
    INDEX,
    m,
    WRAPROWS(
        IFERROR(
            A3:A14+B3:B14,
            A3:A14
        ),
        3
    ),
    HSTACK(I(
        m,
        ,
        1
    ),
    24*(I(
        m,
        ,
        3
    )-I(
        m,
        ,
        2
    ))))
Excel solution 9 for Calculate Name-Based Durations, proposed by Pieter de B.:
=LET(
    t,
    WRAPROWS(
        TOCOL(
            FILTER(
                A3:B14,
                LEN(
                    B3:B14
                )
            )
        ),
        4
    ),
    HSTACK(
        FILTER(
            A3:A14,
            ISTEXT(
                A3:A14
            )
        ),
        BYROW(
            t,
            LAMBDA(
                t,
                SUM(
                    DROP(
                        t,
                        ,
                        2
                    )-TAKE(
                        t,
                        ,
                        2
                    )
                )*24
            )
        )
    )
)
Excel solution 10 for Calculate Name-Based Durations, proposed by Hamidi Hamid:
=LET(x,
    TOCOL(
        IF(
            ISERROR(
                A3:A14*1
            ),
            A3:A14,
            1/0
        ),
        3
    ),
    u,
    DROP(
        WRAPROWS(
            A3:A14,
            3
        ),
        ,
        1
    ),
    d,
    TAKE(
        WRAPROWS(
            B3:B14,
            3
        ),
        ,
        -2
    ),
    dd,
    VSTACK(D2:E2,
    HSTACK(x,
    (TAKE(
        d+u,
        ,
        -1
    )-TAKE(
        d+u,
        ,
        1
    ))*24)),
    dd)
Excel solution 11 for Calculate Name-Based Durations, proposed by ferhat CK:
=LET(a,
    DROP(REDUCE(0,
    A3:A14,
    LAMBDA(x,
    y,
    VSTACK(x,
    LET(ti,
    OFFSET(
        y,
        1,
        
    ),
    ts,
    OFFSET(
        y,
        2,
        
    ),
    si,
    TEXT(
        OFFSET(
            y,
            1,
            1
        ),
        "ss:dd"
    ),
    ss,
    TEXT(
        OFFSET(
            y,
            2,
            1
        ),
        "ss:dd"
    ),
    IF(ISTEXT(
        y
    ),
    IF((ss-si)=0,
    ts-ti,
    (24-(--ti)*24)+(--ts)*24)+(ss-si-1)*24,
    ""))))),
    1),
    HSTACK(
        FILTER(
            A3:A14,
            ISTEXT(
                A3:A14
            )
        ),
        FILTER(
            a,
            ISNUMBER(
                a
            )
        )
    ))
Excel solution 12 for Calculate Name-Based Durations, proposed by Jaroslaw Kujawa:
=LET(b ;
     A3:B14;
     
c ;
     HSTACK(
         SCAN(
             "" ;
              TAKE(
                  b ;
                   ;
                   1
              );
             
             LAMBDA(
                 a ;
                  x ;
                  IF(
                      ISTEXT(
                          x
                      ) ;
                       x ;
                       a
                  )
             )
         ) ;
          b
     ) ;
     
d ;
     FILTER(
         c ;
          ISNUMBER(
              CHOOSECOLS(
                  c ;
                   2
              )
          )
     ) ;
     
e ;
     HSTACK(
         TAKE(
             d ;
              ;
              1
         ) ;
          CHOOSECOLS(
              d ;
               2
          )+CHOOSECOLS(
              d ;
               3
          )
     ) ;
     
seq ;
     SEQUENCE(
         ROWS(
             e
         )
     ) ;
     
f ;
     HSTACK(TAKE(
         e ;
          ;
          1
     ) ;
     24*(INDEX(
         e ;
          seq ;
          2
     )-INDEX(
         e ;
          seq-1 ;
          2
     )) ;
     seq);
     FILTER(
         TAKE(
             f ;
              ;
              2
         ) ;
          MOD(
              TAKE(
                  f ;
                   ;
                   -1
              ) ;
               2
          )=0
     ))
Excel solution 13 for Calculate Name-Based Durations, proposed by Andy Heybruch:
=LET(
_input,
    A3:B14,
    
_filter,
    ISNUMBER(
        TAKE(
            _input,
            ,
            1
        )
    ),
    
_times,
    WRAPROWS(
        BYROW(
            FILTER(
                _input,
                _filter
            ),
            SUM
        ),
        2
    ),
    
HSTACK(FILTER(
    TAKE(
            _input,
            ,
            1
        ),
    _filter=FALSE
),
    (TAKE(
        _times,
        ,
        -1
    )-TAKE(
        _times,
        ,
        1
    ))*24))
Excel solution 14 for Calculate Name-Based Durations, proposed by Imam Hambali:
=LET(
nd, A3:A14,
t, B3:B14,
f, nd+t,
tbl, WRAPROWS(IF(ISERROR(f),nd,f),3),
HSTACK(TAKE(tbl,,1), (TAKE(tbl,,-1)-CHOOSECOLS(tbl,2))*24)
)
Excel solution 15 for Calculate Name-Based Durations, proposed by Milan Shrimali:
=let(a,
    wraprows(
        TOCOL(
            A2:B13,
            1
        ),
        5
    ),
    
byrow(a,
    lambda(x,
    hstack(choosecols(
        x,
        1
    ),
    ((choosecols(
        x,
        4
    )+choosecols(
        x,
        5
    ))-(CHOOSECOLS(
        x,
        2
    )+choosecols(
        x,
        3
    )))*24))))
Excel solution 16 for Calculate Name-Based Durations, proposed by Edwin Tisnado:
=LET(
    a,
    A3:A14,
    b,
    WRAPROWS(
        IFERROR(
            a+B3:B14,
            a
        ),
        3
    ),
    HSTACK(
        TAKE(
            b,
            ,
            1
        ),
        24*MMULT(
            DROP(
            b,
            ,
            1
        ),
            {-1;1}
        )
    )
)
Excel solution 17 for Calculate Name-Based Durations, proposed by Philippe Brillault:
=LET(f,
    LAMBDA(z,
    c,
    TOCOL(IFS(c-(2*c-1)*ISNUMBER(
        z
    ),
    z),
    3)),
    d,
    A3&:B14,
    §1,
    INDEX(
        d,
        ,
        1
    ),
    tn,
    f(
        §1,
        1
    ),
    tt,
    f(
        d,
        0
    ),
    m,
    WRAPROWS(SCAN(
        0,
        tt,
        LAMBDA(
            c,
            t,
            IF(
                t>=1,
                t,
                c+t
            )
        )
    )*(tt<1),
    4),
    HSTACK(
        tn,
        MMULT(
            m,
            {0;-1;0;1}
        )*24
    ))
Excel solution 18 for Calculate Name-Based Durations, proposed by Cary Ballard, DML:
=LET(a,
    A3:A14,
     b,
    B3:B14,
    
 n,
     FILTER(
         a,
          ISTEXT(
              a
          )
     ),
    
 t,
     WRAPROWS(
         FILTER(
             a + b,
              ISNUMBER(
              a
          )
         ),
          2
     ),
    
 beg,
     TAKE(
         t,
          ,
          1
     ),
    
 end,
     DROP(
         t,
          ,
          1
     ),
    
 dur,
     (end - beg) * 24,
    
 HSTACK(
     n,
      dur
 )
)
Excel solution 19 for Calculate Name-Based Durations, proposed by Stefan Alexandrov:
=LET(_table,
    HSTACK(
        WRAPROWS(
            TRANSPOSE(
                A3:A14
            ),
            3
        ),
        WRAPROWS(
            TRANSPOSE(
                B3:B14
            ),
            3
        )
    ),
    
_Name,
    CHOOSECOLS(
        _table,
        1
    ),
    
_start,
    CHOOSECOLS(
        _table,
        2
    )+CHOOSECOLS(
        _table,
        5
    ),
    
_end,
    CHOOSECOLS(
        _table,
        3
    )+CHOOSECOLS(
        _table,
        6
    ),
    
_result,
    (_end-_start)*24,
    
HSTACK(
    _Name,
    _result
))

Solving the challenge of Calculate Name-Based Durations with Python

Python solution 1 for Calculate Name-Based Durations, proposed by Konrad Gryczan, PhD:
import pandas as pd
import numpy as np
path = "573 Durations.xlsx"
input = pd.read_excel(path, usecols="A:B", skiprows=1, nrows=12)
test = pd.read_excel(path, usecols="D:E", skiprows=1, nrows=4)
test["Duration"] = test["Duration"].apply(lambda x: round(x, 1))
input["Name"] = input["Name & Date"].apply(lambda x: x if type(x) == str else np.nan)
input["Name"] = input["Name"].ffill()
input = input.dropna(subset=["Time"]).reset_index(drop=True)
input["Time"] = input["Time"].apply(lambda x: x.strftime("%H:%M:%S"))
input["Name & Date"] = input["Name & Date"].apply(lambda x: x.strftime("%Y-%m-%d"))
input["Time"] = pd.to_datetime(input["Name & Date"] + " " + input["Time"])
input = input.drop(columns=["Name & Date"])
input["RowNumber"] = input.groupby("Name").cumcount() + 1
input = input.pivot(index="Name", columns="RowNumber", values="Time").reset_index()
input.columns.name = None
input["Duration"] = input[2] - input[1]
input["Duration"] = input["Duration"].apply(lambda x: x.total_seconds() / 3600)
input = input.drop(columns=[1, 2]).sort_values("Duration").reset_index(drop=True)
print(input.equals(test))   # True
                    
                  

Solving the challenge of Calculate Name-Based Durations with Python in Excel

Python in Excel solution 1 for Calculate Name-Based Durations, proposed by Alejandro Campos:
from datetime import datetime
df = pd.DataFrame({
 'Name & Date': ['Emily', '01/10/2024', '01/10/2024', 'Thomas', '02/10/2024', '03/10/2024',
 'Russell', '03/10/2024', '04/10/2024', 'Greg', '05/10/2024', '07/10/2024'],
 'Time': ['', '9:00 AM', '4:00 PM', '', '7:00 PM', '3:30 AM', '', '3:00 PM', '12:00 AM', '', '11:30 PM', '5:00 AM']
})
names = []
start_datetimes = []
end_datetimes = []
durations = []
i = 0
while i < len(df):
 if df.loc[i, 'Time'] == '':
 name = df.loc[i, 'Name & Date']
 start_datetime = df.loc[i + 1, 'Name & Date'] + " " + df.loc[i + 1, 'Time']
 end_datetime = df.loc[i + 2, 'Name & Date'] + " " + df.loc[i + 2, 'Time']
 start_dt = datetime.strptime(start_datetime, "%d/%m/%Y %I:%M %p")
 end_dt = datetime.strptime(end_datetime, "%d/%m/%Y %I:%M %p")
 duration = (end_dt - start_dt).total_seconds() / 3600
 names.append(name)
 start_datetimes.append(start_datetime)
 end_datetimes.append(end_datetime)
 durations.append(duration)
 i += 3
 else:
 i += 1
result_df = pd.DataFrame({
 "Name": names,
 "Duration (hours)": durations
})
result_df
                    
                  
Python in Excel solution 2 for Calculate Name-Based Durations, proposed by Anshu Bantra:
df = xl("A2:B14", headers=True).fillna(0)
results = {}
current_name, current_start_time = None, None
for index, row in df.iterrows():
 if row['Time']==0:
 current_name = row['Name & Date']
 else:
 if row['Time'] != 0:
 date = row['Name & Date']
 time = row['Time']
 if current_start_time is None:
 current_start_time = pd.Timestamp.combine(date, time)
 else:
 end_time = pd.Timestamp.combine(date, time)
 duration = (end_time - current_start_time).total_seconds() / 3600
 results[current_name] = results.get(current_name, 0) + duration
 current_start_time = None
pd.DataFrame(list(results.items()), columns=['Name', 'Duration'])
                    
                  

Solving the challenge of Calculate Name-Based Durations with R

R solution 1 for Calculate Name-Based Durations, proposed by Konrad Gryczan, PhD:
library(tidyverse)
library(readxl)
library(hms)
library(janitor)
library(lubridate)
path = "Excel/573 Durations.xlsx"
input = read_excel(path, range = "A2:B14")
test = read_excel(path, range = "D2:E6")
result = input %>%
 mutate(name = ifelse(str_detect(`Name & Date`, "[a-zA-Z]"), `Name & Date`, NA)) %>%
 fill(name) %>%
 filter(!is.na(Time)) %>% 
 mutate(date = excel_numeric_to_date(as.numeric(`Name & Date`)) %>% as.character(),
 time = as_hms(Time) %>% as.character()) %>%
 unite("datetime", c("date", "time"), sep = " ") %>%
 mutate(datetime = ymd_hms(datetime)) %>%
 select(name, datetime) %>%
 mutate(rn = row_number(), .by = name) %>%
 pivot_wider(names_from = rn, values_from = datetime) %>%
 mutate(duration = as.numeric(`2` - `1`)) %>%
 select(Name = name, Duration = duration)
all.equal(result, test, check.attributes = FALSE)
#> [1] TRUE
                    
                  

&&

Leave a Reply