Date time diff in Excel - excel-formula

I would like assistance in calculating the difference of date and time between each of cells 1 through 15 in hours and minutes.
The problem is the ref is not the same for all so, when the ref changes from R001 to R002, the formula should start calculating the date time difference from the first cell, with the new reference to the last cell with the same ref.

This solution will use AGGREGATE, INDEX and optionally MINUTE functions built into excel
Step 1
Build a list of unique ref IDs and place them in column D
Step 2
Use AGGREGATE to determine the LAST row that a ref ID occurs in.
AGGREGATE(16,6,ROW($A$2:$A$16)/--($C$2:$C$16=D2),1)
AGGREGATE is a function that performs array like calculations. As such avoid using full column references within the function.
16 tells AGGREGATE to use the LARGE formula, so it will built a list in Descending order.
6 tells AGGREGATE to ignore/exclude any results in the list that are an error.
ROW() is going to pull the row number that is being evalutated.
-- will turn the resulting TRUE or FALSE result into 1 or 0.
C2:C16=D2 is looking to to see if the row has the REF ID .
1 tells AGGREGATE to return the 1st number in the list.
Step 3
Rinse, wash, repeat. Determine the FIRST row that a ref ID occurs in.
Again use aggregate just as before. Except this time instead of LARGE, we want to find SMALL so change the 16 to a 15. This will return the row number of the first occurrence of the REF ID.
AGGREGATE(15,6,ROW($A$2:$A$16)/--($C$2:$C$16=D2),1)
Step 4
Now that you know the ROW# to use, place the row number in an INDEX formula to get the cell you want to use. Note that index actually returns the cell address so can be used just like a cell reference.
First Time Refence
INDEX(B:B,AGGREGATE(16,6,ROW($A$2:$A$16)/--($C$2:$C$16=D2),1))
Last Time Reference
INDEX(B:B,AGGREGATE(15,6,ROW($A$2:$A$16)/--($C$2:$C$16=D2),1))
Step 5
Take the difference between the Last and First
INDEX(B:B,AGGREGATE(15,6,ROW($A$2:$A$16)/--($C$2:$C$16=D2),1))-INDEX(B:B,AGGREGATE(16,6,ROW($A$2:$A$16)/--($C$2:$C$16=D2),1))
Now if the first reference occurs before the time stamp of the last referenec you will wind up with a negative number. IF YOU DO NOT CARE ABOUT THE NEGATIVE NUMBER, wrap the whole thing in an absolute function or square the results then square root the results.
ABS(INDEX(B:B,AGGREGATE(15,6,ROW($A$2:$A$16)/--($C$2:$C$16=D2),1))-INDEX(B:B,AGGREGATE(16,6,ROW($A$2:$A$16)/--($C$2:$C$16=D2),1)))
Place your choice of the above formula in E2 and copy down as required.
Step 6
Since you want your answer in JUST hours and minutes, I opted to break the information into two separate columns so you could use them as needed. Also I will be referencing the values in column E instead of embedding them into the following formulas which is also an option if you want to avoid extra columns.
If you format the results in E2 as general you will note you get an integer and some decimal values. The integer represents the number of days. The decimals represent TIME as fraction of a day. In order to get the number of hours, you multiply by 24, since there are 24 hours in a day, and take just the integer. Place the following formula in F2 and copy down.
INT(24*E2)
Since you also want the minutes we can pull those directly from E2 using the MINUTE function. Place the following in G2 and copy down.
MINUTE(E2)

Related

Excel: Make a dynamic formula that counts a specified max sum of X consecutive days

I am trying to make a formula that could count the max sum of any number of consecutive days that I indicate in some cell. Here is the dataset and the formula:
Dataset
The formula that calculates the maximum sum of three consecutive days:
=MAX(IFERROR(INDEX(
INDEX(E2:AI2,0)+
INDEX(F2:AI2,0)+
INDEX(G2:AI2,0),
0),""))
As you can see the number of days here is determined by the number of rows in the formula that start with "Index". The only difference between these rows is the letters (E, F, G). Is there any way I could reference a cell in which I could put a number for those days, instead of adding more rows to this formula?
Another approach avoding use of Offset is to use Scan to generate an array of running totals, then subtract totals which are N elements apart (where N is the number of consecutive cells to be added):
=LET(range,E2:AI2,
length,A1,
runningTotal,SCAN(0,range,LAMBDA(a,b,a+b)),
sequence1,SEQUENCE(1,COLUMNS(range)-length+1,A1),
sequence2,SEQUENCE(1,COLUMNS(range)-length+1,0),
difference,INDEX(runningTotal,sequence1)-IF(sequence2,INDEX(runningTotal,sequence2),0),
MAX(difference))
The answer here was posted by another user on another website, so I will repost it here:
One way to achieve this without relying on a VBA solution would be to use the BYCOL() function (available for Excel for Microsoft 365):
=BYCOL(array, [function])
The array specifies the range to which you want to apply your function, and the function itself is specified in a lambda statement. In the end, you want to get the minimum value of the sum of x consecutive days. Assuming that your data is stored in the range E2:AI2 and the number of consecutive days is stored in cell A1, the function looks like this:
=MIN(BYCOL(E2:AI2,LAMBDA(col,SUM(OFFSET(col,,,,A1)))))
The MIN() part ensures that you get only the smallest sum of the array (all sums of the x consecutive values) returned. The array is simply the range in which your data is stored; it is named in the lambda argument col and consequently used by its name. In your case, you want to apply the sum function for, e.g., x = 4 consecutive days (where 4 is stored in cell A1).
However, with this simple specification, you run into the problem of offsetting beyond cells with values toward the right end of the data. This means that the last sum you get would be 81.8 (value on 31 Jan) + 3 times 0 because the cells are empty. To avoid this, you can combine your function with an IF() statement that replaces the result with an empty cell if the number of empty cells is greater than 0. The adjusted formula looks like this:
=MIN(BYCOL(E2:AI2,
LAMBDA(col,IF(COUNTIF(OFFSET(col,,,,A1),"")>0,"",SUM(OFFSET(col,,,,A1))))))
If you do not have the Microsoft 365 version, there are two approaches that would also work. However, the two approaches are a bit more tedious, especially for cases with multiple days (because the number of days can not really be set automatically; except for potentially constructing the ranges with a combination of ADDRESS() and INDIRECT()), but I would still argue a bit neater than your current specification:
=MIN(INDEX(E2:AF2+F2:AG2+G2:AH2+H2:AI2,0))
=SUMPRODUCT(MIN(E2:AF2+F2:AG2+G2:AH2+H2:AI2))
The idea regarding the ranges is the same in both scenarios, with a shift in the start and end of the range by 1 for each additional day.
Another approach getting to the same result:
=LET(range,E2:AI2,
cons,4,
repeat,COLUMNS(range)-cons+1,
MAX(
BYROW(SEQUENCE(repeat,cons,,1)-INT(SEQUENCE(repeat,cons,0,1/cons))*(cons-1),
LAMBDA(x,SUM(INDEX(range,1,x))))))
This avoids OFFSET (volatile, slowing your file down) and the repeat value, consecutive number and/or the range are easily changeable.
Hope it helps (I answered to the max sum, as stated in the title). Change max to min to get the min sum result.
Edit:
I changed the repeat part in the formula to be dynamic (max number of consecutive columns in range), but you can replace it by a number or a cell reference.
The cons part can also be linked to a cell reference.
Also found a big in my formula which is fixed.

Find the weighted average of two rows based on another containing dates

I have a table in which one row contains dates, another row contains AHT (Avg Handle Time) and the third row contains no of calls handled.
I have situation where I need to find the Weighted average for each week in another table. I am able to find simple average for each week. However not getting this weighted average for each week.
Thanks
This should work in most versions of Excel
=SUMPRODUCT(INDEX($3:$3,MATCH("Week "&A9,$1:$1,0)):INDEX($3:$3,MATCH("Week "&A9,$1:$1,0)+6),
INDEX($5:$5,MATCH("Week "&A9,$1:$1,0)):INDEX($5:$5,MATCH("Week "&A9,$1:$1,0)+6))
/SUM(INDEX($3:$3,MATCH("Week "&A9,$1:$1,0)):INDEX($3:$3,MATCH("Week "&A9,$1:$1,0)+6))
May need to be array-entered pre Excel 365.
Notes
The weighted mean formula is
Weighted mean = Σwx/Σw
where are the weights and x are the values. So in this case, from OP's comment, the third row is the weights (number of calls) and the last row is the values (AHT).
The easiest way to get Σwx is to use Sumproduct, and to get Σw is just to use Sum. So the basic formula for (say) week 40 would be simply
=SUMPRODUCT(A3:G3,A5:G5)/SUM(A3:G3)
However, I reasoned that it would be inconvenient to re-write this formula for each different week, so I have used Match to find the starting column of each week from row 1 , then index to find the corresponding position in either row 3 or 5 (let's call it startpos), then index again to find the position six places to the right of startpos (let's call it endpos). The required range to be placed in each part of the short formula above is therefore startpos:endpos (I can use this notation because startpos and endpos, the values returned from the Index function, are both references).
If Excel 365 is available, this can all be expressed much more succinctly and clearly using Let to assign variables names to each part of the formula.
=LET(startCol,MATCH("Week "&A9,$1:$1,0),
startWeight,INDEX($3:$3,startCol),
endWeight,INDEX($3:$3,startCol+6),
startValue,INDEX($5:$5,startCol),
endValue,INDEX($5:$5,startCol+6),
weightRange,startWeight:endWeight,
valueRange,startValue:endValue,
SUMPRODUCT(weightRange,valueRange)/SUM(weightRange))

Sum the number of days in one date range which fall within a second date range

I have two columns of dates. One is the move in date and the other the move out date. I want to figure out how many days the tenant was there during a second date range. for example: how many total "bed days" did we have in the month of July? 7/1/2016-7/31/2016
This function calculates the number of days each tenant was there each month but I would like it if I could get the entire calculation into one cell without creating a dummy column for each month.
=MAX(0,MIN(EOMONTH($B$2,0),I14)-MAX($B$2,H14))
I tried to change a few things and use it as an array function but it is not working. I am very new to array functions so I may be doing it completely wrong.
=SUM(MAX(0,MIN(EOMONTH($B$2,0),I:I)-MAX($B$2,H:H)))
any help is much appreciated! Let me know if you need more info too.
Bad news - you can't use MAX and MIN in an array formula like this because instead of treating H and I as two arrays it just treats them as one big long array and you only get one value out of them.
You also need to add 1 to your original formula because if they moved in on the last day of the month (say) it should still count as one day.
If you replace the MAX and MIN with IF statements you get something like this
=SUM(IF(IF(EOMONTH($B$2,0)<IF(I2:I10="Active",TODAY(),I2:I10),EOMONTH($B$2,0),IF(I2:I10="Active",TODAY(),I2:I10))-IF($B$2>H2:H10,$B$2,H2:H10)<0,0,
IF(EOMONTH($B$2,0)<IF(I2:I10="Active",TODAY(),I2:I10),EOMONTH($B$2,0),IF(I2:I10="Active",TODAY(),I2:I10))-IF($B$2>H2:H10,$B$2,H2:H10)+1))
which has to be entered using CtrlShiftEnter
A useful tip if you are new to arrays is not to include more rows in an array formula than you need to because it will be slow, and test it first on a small number of rows so that you can step through it using Evaluate Formula if you run into trouble.

Counting the number of occurences of a value dynamically

Not sure if I've worded the question correctly... but, I have a spreadsheet that imports data across with a 'transaction date' and on day 1 there may be 15 transactions, day 2 there may be 30 etc.
Now I already have a formula that is counting how MANY are imported each day
=SUMPRODUCT((MONTH('Further Evidence'!$A$2:$A$5000)=MONTH(DATEVALUE(Configuration!H2&" 1")))*('Further Evidence'!$A$2:$A$5000<>""))
That shows how many have come in that particular month, what I need to work out now is what the highest intake was during that month (and if possible, which day it was).
Rather than list 365 days of the year and doing a countif in every cell next to them, is there an intuitive way to only count values that exist in the list?
It will be simple for one of you, but I can't quite figure it out or what to google :)
edit -
=MAX(FREQUENCY('New Appeals'!A2:A5000,MONTH('New Appeals'!A2:A5000)))
This works for the whole list of dates, but how can I make it check months specifically, or pinpoint the specific day?
To find the max value within a given month you can use an array formula like below
I've used a sample range of rows 36 to 48. I've assumed that date is in column I and that transactions is in column J
=MAX(IF(TEXT($I$36:$I$48, "mmm")="jan", $J$36:$J$48, ""))
(To enter an array formula you have to press ctrl + shift + enter when you are in the cell)
This is restricting the MAX function to the month of jan.
You can then find the day associated to this max value by using another array formula that is a mix of first MATCH then INDEX. The MATCH first looks for the max value within the range of cells associated to the given month, then returns this position. This position is then used in the INDEX to return the date
=INDEX($I$36:$I$48, MATCH(K34, IF(TEXT($I$36:$I$48, "mmm")="jan", $J$36:$J$48, "")))
Please note that if you have two days within a month with the same max then it will just bring back the first one
Hope this helps

Search Column A to match a number in column C if True return column B if false return "0"

I am trying to make data collected in 15 minute increments look like data collected in 5 minute increments with the blank spaces being zero. I have created a column with Julian date/time in 15 minute increments (A) and a column with Julian date/time in 5 minute increments (C) and the 15 minute increment data is in column B. I have created a simple formula to check all of column A for an exact match to column C if true I need it to return Column B corresponding to the match in column A, If false it can return 0.
Here is what I have so far with the ?????? being the missing True return formula. What is the formula to return the corresponding data in column B?
=IF(ISNUMBER(MATCH(C2,D:D,0)),"?????????","0")
The common way to handle this sort of lookup is using INDEX-MATCH. You may also be able to use VLOOKUP but I always prefer INDEX-MATCH.
Picture of ranges shows the 5 minute times in column C with 15 minute data in column F.
Formula in C1 is a combination of INDEX-MATCH and IFERROR. The IFERROR is used to handle the case of a value not found and returning the 0 you wanted.
=IFERROR(INDEX($F$1:$F$11,MATCH(B1,$E$1:$E$11,0)),0)
That formula can be copied down from C1 to the end of the 5-minute times.
Your sample formula looks like it uses different columns that your narrative describes. I will use what I understand from your description as the columns. See my sample image below for clarity.
Time lookups are prime candidates for 15 digit precision floating point errors. This is due to the base nature of time being a decimal portion of a day and the repeating decimals inherent with displaying 60 minutes and 24 hours. This problem is often magnified by using incremental progression vs datum growth.
If you have a base time in A2 and wish to create a series of 15 minute increments from that to fill down the column, do not use something like the following:
=TIME(0,15,0)+A2 ◄ generates incremental error growth
When you fill that formula down, any error is multiplied as you fill down. Your base display of minutes may not show any obvious errors but if it was displayed as seconds you would likely find that an extra second was added or subtracted every several hundred rows. This is known as Incremental Error Expansion where each successive row adds to the error generated by the previous formula. In short, if you have a hundred of these formulas in a column, any error in the first is multiplied by 100 by the last one.
By always basing the sequential time formula on A2, the error is minimized to a
single calculation. Change the formula to something like,
=TIME(0,ROW(1:1)*15,0)+A$2 ◄ datum growth based on minutes added to A2
Even with a datum growth formula you may have some errors on exact matches. Best to wrap the formula in an MROUND function that allows you to round off the returned value to a specified multiple; in this case to the nearest second.
=MROUND(TIME(0, ROW(1:1)*15,0)+A$2, TIME(0, 0, 1))
Fill down to get a progressive column of values with a 15 minute increment. You will likely not see any difference in the displayed values but the raw underlying value that is used for the lookup will be quite different. This principle is know as Datum Incrementing; e.g. all progressive numbers are based on a single calculation against the original.
So with a time value in A2 these are the formulas that should be used.
8:30:00 AM ◄ starting time value in A2
=MROUND(TIME(0, ROW(1:1)*15,0)+A$2, TIME(0, 0, 1)) ◄ in A3 add 15 minutes to A2 (fill down as necessary)
=A2 ◄ starting time value in C2
=MROUND(TIME(0, ROW(1:1)*5,0)+C$2, TIME(0, 0, 1)) ◄ in C3 add 5 minutes to C2 (fill down as necessary)
These will produce the most accurate time increments to be used for an exact match lookup.
Now you can apply a VLOOKUP function or an INDEX function paired with a MATCH function to retrieve the values from column B. An IFERROR function will catch non-matches and output a 0 instead of the #N/A error.
     
My formula in column D uses an INDEX/MATCH pair. D2 is,
=IFERROR(INDEX($B:$B, MATCH(C2,$A:$A, 0)), 0)
There is an alternate formula in E2 using VLOOKUP,
=IFERROR(VLOOKUP(C2,$A:$B, 2, FALSE), 0)
Caveat: There is a maximum number of minutes that can be applied with the TIME function. This is the maximum positive value of a signed integer or 32,767 (about 22¾ days worth of minutes).
You could eliminate the look-up altogether and just use the index function to reference the cells needed like this:
Regarding Is a comment warning enough when dealing with potential data loss? and =TIME(0,ROW(1:1)*15,0)+A$2 I caution that applied ‘liberally’ there may be the risk of loss of data. May depend on machine specifications etc. but trying to fill most of a column with that formula my Excel crashed (after attempting for most of 1-1/2 hours). I’d be interested in the experiences of others, in part because dealing with the least significant digit might be processor dependent.
On my machine I tried comparing:
=TIME(0,ROW(1:1)*15,0)+A$2
with
=TIME(0,15,0)+B2
Over 1,000 rows (ie about 10-1/2 days of quarter hours) and found differences (computed, so a possible source of further inaccuracy). The main difference being that the latter accounts for day changes (the integer part in Number format) whereas the former does not. Allowing for integer differences over 1,000 data points there were about 30 that differed by 0.00000000000003, in Number format, and a further 10 or so by much smaller amounts.
The last data point (09:45 AM on day 10) was one of those exhibiting the larger difference (though not as the accumulation of a series of smaller differences). Any difference can be enough for a failure to make an exact match but in seconds that is a difference of about 0.000000002592 by my reckoning, say ~0.0000026 milliseconds or ~26 nanoseconds.
Since in my opinion the day (integer part) is likely to be useful, I would recommend series fill by entering 0 in one cell and 00:15:00 in the next, the dragging down to suit. This has no performance impact because the cell contents are values rather than formulae. For the last entry this gives rise to a difference of 0.00000000000005, ie about twice as much as above, and in some cases as much as 0.00000000000009, about 78 nanoseconds.
With rounding to the second there are differences of a similar order of magnitude. However, a comparison on the last series fill result, with rounding to the second, with the last result from =MROUND(TIME(0, ROW(1:1)*15,0)+A$2, TIME(0, 0, 1)) using EXACT, returns “TRUE”.
Series fill of an entire column took me about 3 seconds. Then rounding to one second with a formula in another column about 12 seconds.

Resources