I have a list of date timestamps and if any of the times happen outside of our working hours, I need to advance them forward to the start of the next workday.
Our work hours are M-F 8:30am-5:30pm, Saturday 8:30am-1:30pm, Sunday closed and we are also closed on holidays.
Examples:
Friday June 26, 2020 6:30pm should be advanced to Saturday June 27, 2020 8:30am
Friday July 3, 2020 6:30pm should be advanced to Monday July 6, 2020 8:30am. Because Saturday was a holiday and we are closed on Sunday.
Friday July 3, 2020 5:29pm should not be advanced because it began during work hours
Column A |Column B | Column C | Column B | Column E
Underwriter | LoanNumber | EntryTime_+3hrs | Desired Outcome | HOLIDAY
TOM | 1 | 07/31/2020 8:28:42 AM | 08/01/2020 8:30:00 AM | 01/01/2020
DICK | 2 | 07/30/2020 6:32:36 PM | 07/31/2020 8:30:00 AM | 01/20/2020
JANE | 3 | 07/30/2020 4:18:57 PM | 07/30/2020 4:18:57 PM | 02/17/2020
BETH | 4 | 07/30/2020 3:06:18 AM | 07/30/2020 8:30:00 AM | 05/25/2020
SALLY | 5 | 07/29/2020 6:35:37 PM | 07/30/2020 8:30:00 AM | 07/04/2020
GEORGE | 6 | 07/03/2020 7:45:26 PM | 07/06/2020 8:30:00 AM | 09/07/2020
| | | | 10/12/2020
| | | | 11/11/2020
| | | | 11/26/2020
| | | | 12/24/2020
| | | | 12/25/2020
Start date time stamps need to be validate and converted to next available time slot.
Current thinking is you have three potential outcomes:
The date will need to be shifted next possible day starting at 0830
The date will remain the same but the time will be shifted to 0830
The date and time are valid and no adjustment is required.
so a generic formula might look something like this:
IF(OR(HOLIDAY,SUNDAY,AFTERHOURS),FIND NEXT WORKDAY,
IF(BEFORE WORKHOURS, SET TIME TO START TIME, ITS VALID TIME))
In order to check each condition individually for a potential day shift we can use the following formulas:
(ASSUME C2 is the start date being tested)
WEEKDAY AFTER 1730
=AND(MOD(C2,1)>TIME(17,30,0),OR(WEEKDAY(C2)={2,3,4,5,6}))
SATURDAY AFTER 1330
=AND(MOD(C2,1)>TIME(13,30,0),WEEKDAY(C2)=7)
HOLIDAY (list in E2:E12)
=COUNTIF($E$2:$E$12,INT(C2))=1
SUNDAY
=WEEKDAY(C2)=1
The MOD function in the first two formulas is stripping the Integer/date value and just keeping the decimal/time portion
The { } is a manual list/array is a nice way of doing multiple OR checks with out writing out each individual check. Since these are sequential, you do have other options.
Now there is a way of flagging each case, So now just rearrange and group together so you have three choices in a nested IF function:
=IF(OR(AND(MOD(C2,1)>TIME(17,30,0),OR(WEEKDAY(C2)={2,3,4,5,6})),AND(MOD(C2,1)>TIME(13,30,0),WEEKDAY(C2)=7), COUNTIF($E$2:$E$12,INT(C2))=1, WEEKDAY(C2)=1), FIND NEXT DATE, IF(BEFORE WORK, SET TIME TO 0830, DO NOTHING))
Since each valid day starts at 0830 and invalid days have already been taken care of with the first IF, only the start time needs to be checked.
=MOD(C2,1)<TIME(08,30,00)
And the valid time is the only case left over so there is nothing to check for.
And you pseudo formula becomes something like:
=IF(OR(AND(MOD(C2,1)>TIME(17,30,0),OR(WEEKDAY(C2)={2,3,4,5,6})),AND(MOD(C2,1)>TIME(13,30,0),WEEKDAY(C2)=7), COUNTIF($E$2:$E$12,INT(C2))=1, WEEKDAY(C2)=1), FIND NEXT DATE, IF(MOD(C2,1)<TIME(08,30,00), SET TIME TO 0830, DO NOTHING))
So now you just need to figure out how to add some days, change the time, and keep what you have for a value.
Adjusting the number of days to add had me looking at multiple nested IF equal to the number of days in a row that could be invalid. Right now I have the worst case scenario being Thursday at 17:31 something starts. Friday is a holiday as a result of a holiday on Saturday, Sunday is a holiday, and Monday is a holiday due to the Sunday holiday. So first potential day would be 5 days away. Ugly nested IF. As an alternative I looked at AGGREGATE and adding 1 day at a time up to 5 and checking if its a valid date. Then take the lowest/earliest date and setting start time to 0830. To achieve this I tried the following formula:
=AGGREGATE(15,6,(INT(C2)+{1,2,3,4,5})/((COUNTIF($E$2:$E$12,(INT(C2)+{1,2,3,4,5}))<1)*(WEEKDAY(C2+{1,2,3,4,5})<>1)),1)+TIME(8,30,0)
Then next function you need to do is keep the date but set the time to 08:30
=INT(C2)+TIME(08,30,00)
and your do nothing is:
=C2
so now if we combine the crap out of that into one formula we wind up with:
=IF(OR(AND(MOD(C2,1)>TIME(17,30,0),OR(WEEKDAY(C2)={2,3,4,5,6})),AND(MOD(C2,1)>TIME(13,30,0),WEEKDAY(C2)=7), COUNTIF($E$2:$E$12,INT(C2))=1, WEEKDAY(C2)=1), AGGREGATE(15,6,(INT(C2)+{1,2,3,4,5})/((COUNTIF($E$2:$E$12,(INT(C2)+{1,2,3,4,5}))<1)*(WEEKDAY(C2+{1,2,3,4,5})<>1)),1)+TIME(8,30,0), IF(MOD(C2,1)<TIME(08,30,00), INT(C2)+TIME(08,30,00), C2))
I believe the desired date in D2 (red background) is wrong and should instead be 20/07/31 08:30
reference to your previous question
Now in theory this could be substituted for every B2 reference in the first formula, but A) the thing would become even more damned unreadable and hard to maintain than it already is, and B) may cause multiple repetitive calculations.
The goal is to fix a circular reference in my logic in this "two weeks pay" input workbook.
It's a temporary sheet for when people are outside the office and can't access the system.
That said, that sheet still should give them accurate data.
There's 26 sheets that contains the times done by an employee for example, in a typical format, for 2 weeks in each (a year in total).
Stripped of all formatting and non-useful information for this enquiry, they would look somewhat like this (with proper dates) :
+-----------+----------+--------+----------+--------+-------+------+
| Date | AM start | AM end | PM start | PM end | total | over |
+-----------+----------+--------+----------+--------+-------+------+
| Monday | 8:00 | 12:00 | 13:00 | 16:00 | 7:00 | 0:00 |
+-----------+----------+--------+----------+--------+-------+------+
| Tuesday | 8:00 | 12:00 | 13:00 | 15:00 | 6:00 | 0:00 |
+-----------+----------+--------+----------+--------+-------+------+
| Wednesday | 8:00 | 12:00 | 13:00 | 17:00 | 8:00 | 1:00 |
+-----------+----------+--------+----------+--------+-------+------+
| ... | .... | .... | .... | .... | .... | .... |
+-----------+----------+--------+----------+--------+-------+------+
Then on another sheet, there's some calculation has to what is the paid amount (maximum 70 hours per 2 weeks), the overtime done that has to be paid, etc.
A B C D E F G
+-------+------------+----------+---------------+-----------------------+-------+---------------------+
1 | Pay # | Hours paid | Overtime | Used overtime | Total hours worked | | Total overtime left |
+-------+------------+----------+---------------+-----------------------+-------+---------------------+
2 | 1 | 70:00 | 5:00 | 0:00 | 75:00 | | 0:00 |
+-------+------------+----------+---------------+-----------------------+-------+---------------------+
3 | 2 | 70:00 | 0:00 | 5:00 | 65:00 | | |
+-------+------------+----------+---------------+-----------------------+-------+---------------------+
4 | ... | ... | ... | .... | | | |
+-------+------------+----------+---------------+-----------------------+-------+---------------------+
In the above table, the pay #2 got 70 hours paid, but the person would have done only 65 hours and used 5 hours of the overtime done the past two weeks.
A1:E4 is connected together, G1:G2 is data by itself, not linked to the pay numbers or other data in that sheet (in other words, there is only one cell that contains that total overtime left and F is used to separate both tables).
G2 currently have 0:00 because the 5:00 it would have had has been used to complete the second pay.
The Hours paid cell (B) contains this formula :
=IF($E$2>=2.91666666666667,2.91666666666667,IF((2.91666666666667- $E$2)<=$G$2;2.91666666666667,$E$2+$D$2))
Step 1 [condition] : If the total hours worked for that two weeks is greater than or equals to 70 hours (the 2.91666666666667 is used here instead of "70:00" to make the comparison works);
Step 1.1 [true] : Then put "70:00" in the cell because there's a 70 hours maximum per two weeks (this is fine since we have another cell that stores the overtime done (in this example, C));
Step 1.2 [false->condition] : Else, the total hours worked for that two weeks is lower than 70 hours so check if 70 hours minus the total hours worked for that two weeks is lower than the total overtime left to be used (used to check if there's overtime left that can be used this time to make the pay the highest it can be up to a maximum of 70 hours);
Step 1.2.1 [true] : If it is, put 70 hours because we'll use some of the overtime left to be paid to complete this two weeks;
Step 1.2.2 [false] : Otherwise, put the total hours worked for that two weeks added to the used overtime for that week (this cell is explained later with her formula and this step is for when there's overtime left, but not enough to make it go up to 70 hours so we put the amount of time it ends up being).
The important part here is to remember that B needs D, hence why I explained it's formula.
The Overtime (C) and "Total hours worked" (E) cells contains basic formulas that either gives the amount of time over 70 hours or the total hours worked; no need to explain it here, it works.
The Used overtime cell (D) is where it gets tricky. To explain it, we'll need to know what's up with G2.
The Total overtime left cell (G2) is the total of overtime hours minus the sum of all cells in D (used overtime).
It's purpose is to get an up to date value of how much overtime there is left to be paid.
Back to Used Overtime.
You probably start to see circular reference here; D needs G2 to work and G2 is the sum of all cells in D (in the table range, not all of them).
The formula requires the notion of how much overtime there is left so it can check if we can use some.
Here's the formula :
=IF($E$2>=2.91666666666667,"00:00",IF((2.91666666666667-$E$2)<=$G$2,(2.91666666666667-$E$2),IF(($G$2+$E$2)<=2.91666666666667,$G$2,"00:00")))
Step 1 [condition] : If the total hours worked for that two weeks is greater than or equals to 70 hours;
Step 1.1 [true] : Then put 0 hours since that pay is already at the 70 hours maximum;
Step 1.2 [false->condition] : Else, the total hours worked for that two weeks is lower than 70 hours and could grow higher if we still have overtime to be paid so check if 70 hours minus the total hours worked for that two weeks (the amount of time we could add from the overtime left) is lower than or equals to the total overtime left to be paid;
Step 1.2.1 [true] : Then put 70 hours minus the total of hours worked for that two weeks (the amount of time we will add from the overtime left to make this pay grows to the maximum of 70 hours);
Step 1.2.2 [false->condition] : Otherwise, check if the total overtime left added to the total of hours worked for that two weeks is lower than or equals to 70 hours (if so, then it means that we can add all the overtime left here without getting over 70 hours);
Step 1.2.2.1 [true] : If it is then the value is the total overtime left since it will make the total hours worked for that two weeks still be under the maximum yet pay for the overtime that was left to be paid;
Step 1.2.2.2 [false] : Otherwise, put 0 hours since we will not be adding overtime to this pay because there is no overtime left to be added.
How could I both have the accurate overtime left and yet have the used overtime both dynamically calculating themselves without a circular reference ?
What if every row had an up to date value for Total Overtime Left after that pay period?
Formula for G2: =C2-D2
Then every G cell after that only needs to add the Overtime Left from the previous pay period + overtime - used overtime:
G3: =G2+C3-D3
And it just goes on from there.
I want to track my hours for work on my personal Excel spreadsheet.
My company records time in 6 minute intervals. So 8 hrs and 6 min worked is represented as 8.1 in the time card systems and so forth.
I have in cell A1 the header and A2 is the data.
+------------+-------------+-----------+---------+-------------+----------+
| Start Time | Start Lunch | End Lunch | End day | Total Hours | TC Hours |
+------------+-------------+-----------+---------+-------------+----------+
| 07:00 | 11:00 | 12:00 | 16:03 | 8:03 | 8 |
| 07:00 | 11:00 | 12:00 | 16:06 | 8:06 | 8.1 |
+------------+-------------+-----------+---------+-------------+----------+
I would like to achieve two results. The first is that anything that is from 0-3 minutes be rounded down and anything from 4-6 minutes be rounded up. The next one is to output in the Time Card (TC) format of 6 minutes =.1 and so forth. I have a previous code I used for both but need to adjust it.
This is for the rounding
=IF(ISBLANK($E10)," ", TIME(HOUR(F10), ROUND((MINUTE(F10)/60)*4, 0) * 15, 0))
This is for the TC
=IF(ISBLANK(E10)," ", ROUND((G10*24)/0.25,0)*0.25)
Get away from using math tricks to achieve your averaging and use MROUND and TIME instead. It is every bit as accurate (if not more so) in avoiding floating point problems with time and generally makes more sense to the user.
To average any time value to the nearest 6 minutes use,
=MROUND(E2, TIME(0, 6, 0))
To convert the total hours to hours as integers with minutes as floating points (in F2 as per the included image),
=HOUR(MROUND(E2, TIME(0, 6, 0)))+MINUTE(MROUND(E2, TIME(0, 6, 0)))/60
I receive a statement (as a .xls) each month which list a bunch billable items with an associated date. I want to create a formula (using either =sum() or =sumifs() to total the billable items, but only those which fall Monday to Friday (i.e., not weekends). Is that possible?
A B
------+--------------+-------------
1 | 05/12/2016 | $10.00
2 | 06/12/2016 | $10.00
3 | 07/12/2016 | $10.00
4 | 08/12/2016 | $10.00 dates are formatted as
5 | 09/12/2016 | $10.00 dd/mm/yyyy
6 | 10/12/2016 | $10.00
7 | 11/12/2016 | $10.00
8 | 12/12/2016 | $10.00
------+--------------+-------------
| Sum | $80.00
------+--------------+-------------
| Sum |
| (no weekends)| $60.00
------+--------------+-------------
EDIT:
I've just looked closer at the excel doc, and it's actually a datetime field, e.g. 31/10/2016 12:44:00 pm (displayed as 31/10/16 12:44).
I'm also not looking for a formula which works line by line, I'd like something which I can just copy and paste into a single cell at the bottom of the doc each month which examines A:A.
You need to use this formula:
=SUMPRODUCT(B1:B8,--(WEEKDAY(A1:A8,2)<6))
This is a hack which behaves like SUMIF but lets you use a function in your criteria. Otherwise, you would need to create an auxiliary column with WEEKDAY (in C for example) and then use =SUMIF(C1:C8,"<6",B1:B8).
WEEKDAY by default returns 1-7 for SUN-SAT. As this doesn't help, you can change the return type to type 2 with the optional second parameter to make the function return 1-7 for MON-SUN, which lets you do the easy <6 comparison. You can also use type 3, which returns 0-6 for MON-SUN, and then obviously use <5 instead.
More about the -- hack here.
In my theoretical data set, I have a list which shows the date-time of a sale, and the employee who completed the transaction.
I know how to do grouping in order to show how many sales each employee has per day, but I'm wondering if there's a way to count how many grouped days have more than 0 sales.
For example, here's the original data set:
Employee | Order Time
A | 8/12 8:00
B | 8/12 9:00
A | 8/12 10:00
A | 8/12 14:00
B | 8/13 10:00
B | 8/13 11:00
A | 8/13 15:00
A | 8/14 12:00
Here's the pivot table that I have created:
Employee | 8/12 | 8/13 | 8/14
A | 3 | 1 | 1
B | 1 | 2 | 0
And here's what I want to know:
Employee | Working Days
A | 3
B | 2
Split your Order Time column (assumed to be B) into two, say with Text to Columns and Space as the delimiter (might need a little adjustment). Then pivot (using the Data Model) as shown:
and sum the results (outside the PT) such as with:
=SUM(F3:H3)
copied down to suit.
Columns F:G may then be hidden.
I fully support #Andrea's Comment (a correction) on the above:
I think this could have been made simpler. If you remove the "Time" in values of the pivot table and then move "Order" from columns to values and use distinct count as in the example. It should count Employee per date making the sum not needed. If you scale this to make it larger. Say 50 dates then the =Sum() needs to be moved each time.