March 31 - April 2, 2025, in Las Vegas, Nevada. Use code MSCUST for a $150 discount! Early bird discount ends December 31.
Register NowBe one of the first to start using Fabric Databases. View on-demand sessions with database experts and the Microsoft product team to learn just how easy it is to get started. Watch now
Hello,
After seeing this following post and in order to not reopen it, I tried the function explained at the bottom but it returns sometimes suspicious values.
Remind, here's the function :
let // calculates a duration between two timestamps in working hours fnDurationWorkingHours = (StartDateTime as datetime, EndDateTime as datetime) as duration => let // start and end date StartDate = Date.From(StartDateTime), EndDate = Date.From(EndDateTime), // start and end time StartTime = Time.From(StartDateTime), EndTime = Time.From(EndDateTime), // end of the shift on the first day and start of the shift on the last day ShiftEndOnStartDate = #time(17, 0, 0), ShiftStartOnEndDate = #time(8, 0, 0), // working days are from Mon=0 to Fri=4 fnIsWorkingDay = (dt as date) as logical => Date.DayOfWeek(dt, Day.Monday) < 5, // generate whole days between StartDateTime and EndDateTime DaysBetween = List.Generate( () => Date.AddDays(StartDate, 1), each _ < EndDate, each Date.AddDays(_, 1) ), // select only working days WorkingDaysBetween = List.Select(DaysBetween, fnIsWorkingDay), // get minimum of two times fnMin = (first as time, second as time) as time => if first > second then second else first, // get maximum of two times fnMax = (first as time, second as time) as time => if first > second then first else second, // duration on the first day StartDateWorkingHours = if not fnIsWorkingDay(StartDate) then #duration(0, 0, 0, 0) else if ShiftEndOnStartDate < StartTime then #duration(0, 0, 0, 0) else ShiftEndOnStartDate - fnMax(StartTime, ShiftStartOnEndDate), // duration on the days between WorkingHoursBetween = #duration(0, List.Count(WorkingDaysBetween) * 9, 0, 0), // duration on the last day EndDateWorkingHours = if not fnIsWorkingDay(EndDate) then #duration(0, 0, 0, 0) else if EndTime < ShiftStartOnEndDate then #duration(0, 0, 0, 0) else fnMin(EndTime, ShiftEndOnStartDate) - ShiftStartOnEndDate, // sum it up Result = if StartDateTime > EndDateTime then #duration(0, 0, 0, 0) else if StartDate = EndDate and not fnIsWorkingDay(StartDate) then #duration(0, 0, 0, 0) else if StartDate = EndDate then fnMin(EndTime, ShiftEndOnStartDate) - fnMax(StartTime, ShiftStartOnEndDate) else StartDateWorkingHours + WorkingHoursBetween + EndDateWorkingHours in Result
But for example, when I have in start and end time these
There's no 6 days and 20h betweend 19/09/2022 and 13/10/2022, even if we exclude weekends.
Some other examples :
Could you help me please ?
Thank you!
Solved! Go to Solution.
so complicated...
(from, to, optional st, optional et) =>
[s_time = st ?? #time(8, 0, 0),
e_time = et ?? #time(17, 0, 0),
start = List.Min({from, to}),
end = List.Max({from, to}),
start_date = Date.From(start),
end_date = Date.From(end),
gen = List.Generate(
() => [c = start_date, sod = List.Max({start, start_date & s_time}), eod = List.Min({end, c & e_time})],
(x) => x[c] <= end_date,
(x) => [c = Date.AddDays(x[c], 1), sod = c & s_time, eod = List.Min({end, c & e_time})],
(x) => if Date.DayOfWeek(x[c], Day.Monday) > 4 then null else x[eod] - x[sod]
),
result = if List.NonNullCount({from, to}) < 2 then null else List.Sum(gen)][result]
Thanks to both of you helping me to resolve my problems!!! 🙂
so complicated...
(from, to, optional st, optional et) =>
[s_time = st ?? #time(8, 0, 0),
e_time = et ?? #time(17, 0, 0),
start = List.Min({from, to}),
end = List.Max({from, to}),
start_date = Date.From(start),
end_date = Date.From(end),
gen = List.Generate(
() => [c = start_date, sod = List.Max({start, start_date & s_time}), eod = List.Min({end, c & e_time})],
(x) => x[c] <= end_date,
(x) => [c = Date.AddDays(x[c], 1), sod = c & s_time, eod = List.Min({end, c & e_time})],
(x) => if Date.DayOfWeek(x[c], Day.Monday) > 4 then null else x[eod] - x[sod]
),
result = if List.NonNullCount({from, to}) < 2 then null else List.Sum(gen)][result]
Hello,
I tried your solution but it seems to have problems in it :
Some results are wrong (between 3 and 17, there's not only 3 days 😞 )
that is DURATION where 1 day = 24 hours. If you want solution in (working) hours then apply Duration.TotalHours.
Hi @Heremion, I also replied to that post. Have you tried my soution? If you want help provide sample data in usable format (read note below my post if you don't know how) and expected resuld based on sample data please.
Hi,
I tried it but it seems I got an issue with start and end because you use #time... instead I could reuse existing field with datetime datatype.
I tried to replace them with #"début" and #"fin" or [début] and [fin] but I got an error with "field not recognized"
You'll find a sample below
début | dateEC | DiffEC | dateT | dateF |
19/09/2022 08:00:00 | 19/09/2022 14:09:12 | 0.06:09:12 | 20/01/2023 17:01:57 | 19/09/2022 14:09:57 |
03/09/2024 08:00:00 | 17/09/2024 08:09:37 | 3.18:09:37 | null | 17/09/2024 08:09:09 |
12/09/2024 08:00:00 | 12/09/2024 14:09:35 | 0.06:09:35 | null | 12/09/2024 16:09:05 |
06/09/2024 08:00:00 | 06/09/2024 11:09:53 | 0.03:09:53 | 06/09/2024 14:09:45 | 06/09/2024 14:09:29 |
19/09/2022 08:00:00 | 13/10/2022 10:10:09 | 6.20:10:09 | 03/08/2023 15:08:12 | 03/08/2023 15:08:12 |
06/09/2024 08:00:00 | 06/09/2024 10:09:45 | 0.02:09:45 | 10/09/2024 11:09:31 | 10/09/2024 11:09:59 |
19/09/2022 08:00:00 | null | null | 20/09/2022 09:09:18 | 20/09/2022 09:09:18 |
19/09/2022 08:00:00 | null | null | null | 23/09/2022 09:09:17 |
09/09/2024 08:00:00 | 09/09/2024 08:09:09 | 0.00:09:09 | 09/09/2024 15:09:37 | 09/09/2024 15:09:16 |
19/09/2022 08:00:00 | 19/09/2022 15:09:19 | 0.07:09:19 | 19/09/2022 15:09:11 | 19/09/2022 15:09:01 |
09/09/2024 08:00:00 | 09/09/2024 09:09:37 | 0.01:09:37 | 09/09/2024 15:09:14 | 09/09/2024 15:09:55 |
null | null | null | 02/09/2024 20:09:54 | 02/09/2024 20:09:54 |
19/09/2022 08:00:00 | 19/09/2022 14:09:44 | 0.06:09:44 | 16/02/2023 15:02:04 | 20/09/2022 10:09:00 |
09/09/2024 08:00:00 | 09/09/2024 09:09:42 | 0.01:09:42 | 09/09/2024 15:09:44 | 09/09/2024 15:09:31 |
09/09/2024 08:00:00 | 09/09/2024 09:09:05 | 0.01:09:05 | 09/09/2024 15:09:56 | 09/09/2024 15:09:42 |
20/09/2022 08:00:00 | 20/09/2022 15:09:30 | 0.07:09:30 | 20/09/2022 17:09:34 | 20/09/2022 17:09:52 |
21/09/2022 08:00:00 | null | null | 29/11/2022 09:11:03 | 29/11/2022 09:11:55 |
21/09/2022 08:00:00 | 27/09/2022 15:09:54 | 1.19:09:54 | 28/09/2022 10:09:01 | null |
11/09/2024 08:00:00 | 11/09/2024 16:09:48 | 0.08:09:48 | 11/09/2024 17:09:08 | 11/09/2024 17:09:53 |
03/09/2024 08:00:00 | null | null | null | 03/09/2024 09:09:22 |
11/09/2024 08:00:00 | 11/09/2024 16:09:51 | 0.08:09:51 | 11/09/2024 17:09:39 | 11/09/2024 17:09:31 |
21/09/2022 08:00:00 | 21/09/2022 15:09:20 | 0.07:09:20 | 22/11/2022 16:11:55 | 29/09/2022 18:09:00 |
03/09/2024 08:00:00 | null | null | null | 03/09/2024 10:09:22 |
11/09/2024 08:00:00 | 11/09/2024 17:09:43 | 0.09:00:00 | 12/09/2024 10:09:12 | 12/09/2024 10:09:56 |
11/09/2024 08:00:00 | 11/09/2024 17:09:47 | 0.09:00:00 | 12/09/2024 10:09:04 | 12/09/2024 10:09:51 |
21/09/2022 08:00:00 | 21/09/2022 17:09:43 | 0.09:00:00 | 21/09/2022 17:09:37 | 21/09/2022 17:09:30 |
11/09/2024 08:00:00 | 11/09/2024 17:09:21 | 0.09:00:00 | 12/09/2024 11:09:30 | 12/09/2024 11:09:22 |
11/09/2024 08:00:00 | 11/09/2024 17:09:29 | 0.09:00:00 | 12/09/2024 11:09:01 | 12/09/2024 11:09:53 |
21/09/2022 08:00:00 | null | null | 21/09/2022 18:09:53 | 21/09/2022 18:09:43 |
I try to get three fieds :
* diff between début and dateEC
* diff between début and dateT
* diff between début and dateF
excluding weekends
Thx for your help
Difference in time. After I can convert in days if I have to.
Examples :
18/09/2024 08:00:00 -> 18/09/2024 10:00:00 = 02:00:00
18/09/2024 08:00:00 -> 19/09/2024 10:00:00 = 11:00:00 according working between 08:00:00 and 17:00:00 each day (so 08:00:00 -> 17:00:00 + 08:00:00 -> 10:00:00)
Check this. Ignore first 4 rows (I've added them just for test purpose).
You can edit shiftStart and shiftEnd in Helper step.
EDIT: I've added option where you can decide whether you want to include or exclude weekends:
Output
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("nVZRbuwwCLxKtd+rLGA7iX2Vam9Q9e/d/zng2NQmaVJppRUTDMMATj4/H7i+IL4IiD5gTgESwOP5IKgorskXtPzez3wsmsfcjWPxT8cQkisOGqWKHmRb89PxmE+ZBlJGYcp17MZWPm4u7gOXBJjCYh3M6JYGdvr+R5rlBxqT22K4CZvx/e/ry/KEKPTJjNtQYeGCos/GHld58kMIwne24ioUkatzEtc1Y+5S+2ChFM/Udy+E2sr8y8U+H/NEzdj0XIv6IeWz0iADvVYNNKoTUDUQuoIdWmg4q6YoXf7U1nAXE64H6NWIe2DXhyiTF83a4zhPXDs0o7lsYpZ5HFCcL+6ReJc0SzVGF7RQwIvVxEZ1Ajzh7S00yPibCkPbFWKZgj9Ab1ws3qvNZAPzWFIb4jyMvrttpUdwRxBPShAx+tK9KYi7pTsElUaMQeHZTC6LqvegpdG1CylQU+R6F0F70RgNJQ1eWNT4Qqz7tO25s9AyMHZEWjriPDE4YawGrX1fcefAU4SW7gqVW9uvIshaDe3CpYOJ5jv7+PVkb4Hrek50h2lAxZSNgZOLJopnQmMnNOkJYYOodi4zkc5xP9VnhVqrPwkiHbwsCJPz5RUazbc31O+NAQ3zrTTLr2n4nhnTXNX9oJrBha/jEYU71RCeVYP1WhjQe72h+GsaXtcBLWt16Z7BbgL5M2pAs7Dv938=", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [début = _t, dateEC = _t, DiffEC = _t, dateT = _t, dateF = _t]),
ChangedType = Table.TransformColumnTypes(Source,{{"dateF", type datetime}, {"dateT", type datetime}, {"DiffEC", type duration}, {"dateEC", type datetime}, {"début", type datetime}}),
Helper = [ shiftStart = #time(8,0,0),
shiftEnd = #time(17,0,0),
includeWeekends = "no", //type "yes" if you want to include weekends. Type "no" if you want to exclude weekends
workingHours = shiftEnd - shiftStart ],
fn_WorkingDuration =
(previousStep as table, start as text, end as text, optional colName as text)=>
let
// Ad_StartColumn = Table.DuplicateColumn(ChangedType, "début", "S"),
// Ad_EndColumn = Table.DuplicateColumn(Ad_StartColumn, "dateEC", "E"),
Ad_StartColumn = Table.DuplicateColumn(previousStep, start, "S"),
Ad_EndColumn = Table.DuplicateColumn(Ad_StartColumn, end, "E"),
Ad_SDate = Table.AddColumn(Ad_EndColumn, "S Date", each DateTime.Date([S]), type date),
Ad_STime = Table.AddColumn(Ad_SDate, "S Time", each DateTime.Time([S]), type time),
Ad_EDate = Table.AddColumn(Ad_STime, "E Date", each DateTime.Date([E]), type date),
Ad_ETime = Table.AddColumn(Ad_EDate, "E Time", each DateTime.Time([E]), type time),
// Weekends excluded
Ad_WorkingDays = Table.AddColumn(Ad_ETime, "Working Days", each try
[ a = List.Dates([S Date], Duration.TotalDays([E Date] - [S Date]) +1, #duration(1,0,0,0)), //weekends included
b = List.Select(a, (x)=> Date.DayOfWeek(x, Day.Monday) < 5), //weekends excluded
c = if Text.Trim(Text.Lower(Helper[includeWeekends])) = "yes" then a else b
][c] otherwise null, type list),
// [S Date] and [E Date] excluded
Ad_FullDaysHours = Table.AddColumn(Ad_WorkingDays, "Full Days Hours", each try
[ a = List.RemoveItems([Working Days], { [S Date], [E Date]}),
b = Helper[workingHours] * List.Count(a)
][b] otherwise null, type duration),
Ad_FirstDayHours = Table.AddColumn(Ad_FullDaysHours, "Fist Day Hours", each try if [S Date] = List.First([Working Days])
then (if [S Date] = [E Date] then List.Min({ [E Time], Helper[shiftEnd] }) else Helper[shiftEnd]) - List.Max({ [S Time], Helper[shiftStart] })
else #duration(0,0,0,0) otherwise null, type duration),
Ad_LastDayHours = Table.AddColumn(Ad_FirstDayHours, "Last Day Hours", each try if [S Date] = [E Date] then #duration(0,0,0,0) else if [E Date] = List.Last([Working Days])
then Helper[workingHours]
else #duration(0,0,0,0) otherwise null, type duration),
// Ad_TotalWorkingDuration = Table.AddColumn(Ad_LastDayHours, "Total Working Duration", each [Full Days Hours] + [Fist Day Hours] + [Last Day Hours], type duration),
Ad_TotalWorkingDuration = Table.AddColumn(Ad_LastDayHours, if colName <> null then colName else "Total Working Duration" , each [Full Days Hours] + [Fist Day Hours] + [Last Day Hours], type duration),
_RemovedColumns = Table.RemoveColumns(Ad_TotalWorkingDuration,{"S", "E", "S Date", "S Time", "E Date", "E Time", "Working Days", "Full Days Hours", "Fist Day Hours", "Last Day Hours"})
in
_RemovedColumns,
StepBack = ChangedType,
Ad_dateECDuration = fn_WorkingDuration(StepBack, "début", "dateEC", "dateEC duration"),
Ad_dateTDuration = fn_WorkingDuration(Ad_dateECDuration, "début", "dateT", "dateT duration"),
Ad_dateFDuration = fn_WorkingDuration(Ad_dateTDuration, "début", "dateF", "dateF duration")
in
Ad_dateFDuration
Hello, Thanks for your help and time.
If I want to make this diff between two of my datetime field, where do I have to put them because I see start and end but they're text field, not datetime field.
Thanks
I declare this function and tried to use it as following :
#"Step5" = Table.AddColumn(#"Step4", "delay", each fn_WorkingDuration(#"Step4",[début],[dateEC], "dateEC duration"))
but I got this issue :
Expression.Error : Sorry... We could not convert the value #datetime(2022, 9, 19, 8, 0, 0) in Text type
Détails :
Value=19/09/2022 08:00:00
Type=[Type]
I removed ChangedType because in function, it allows only 3 or 4 parameter. I let Helper but I got this now :
I've edited my Function - there are different parameters. Check my previous post again, download attached .xlsx file and use that function.
In that function you have to declare parameters:
1.) tbl (usualy previous step - or step before Helper step) this must be a table
2.) h (Helper step) - this must be a record
3.) start dateTime (column name with start dateTime) as text
4.) end dateTime (column name with start dateTime) as text
5.) optional - new column name
I refreshed the post, but in your function, I still see only 4 parameters :
March 31 - April 2, 2025, in Las Vegas, Nevada. Use code MSCUST for a $150 discount!
Your insights matter. That’s why we created a quick survey to learn about your experience finding answers to technical questions.
Arun Ulag shares exciting details about the Microsoft Fabric Conference 2025, which will be held in Las Vegas, NV.