I have a start time, duration and a data value in Columns A, B and C respectively.
How can I capture the data that falls during the start time and end time and insert the sum of this data in a 30-minute cycle (e.g. 09:00, 09:30, 10:00, 10:30 etc) in the "Output" column?
For example, if Data_A had a start time was at 09:15 and end time at 10:15, its value would be returned at 09:00, 09:30 and 10:00.
If more than 1 data value was received within the same 30-minute cycle, the values would be summed.
For example, Data_A has a value of 0.1 and Data_B has a value of 0.2.
Data_B has a start time at 09:50 and end time at 10:10. The sum values at 09:00, 09:30 and 10:00 would be 0.1, 0.3 and 0.3 respectively.
If no data was received for any 30-minute cycle, it simply returns a zero.
The following SUMIFS function can be used to sum the values at start time but I couldn't modify it to take into account the duration and end time.
=SUMIFS($C$2:$C$10,$A$2:$A$10,">="&G2,$A$2:$A$10,"<"&G2+TIME(0,29,59))
The dataset I have is over a year's worth, I am open to solutions using cell equations or VBA.
Link to dropbox file
I would create a VBA function SumBetweenDateTimeLoop with inputs the cell of the starting datetime, the range of starting time, range of ending time, range of values to add and minutes of the loop (in this case fixed to 30).
Public Function SumBetweenDateTimeLoop(this_date As Range, dt_start As Range, dt_end As Range, values As Range, min_loop As Integer)
Dim i As Integer
Dim v As Double
Dim d1 As Date, d2 As Date
Dim v1 As Date, v2 As Date
If dt_start.Count <> dt_end.Count Or values.Count <> dt_end.Count Or dt_start.Count <> values.Count Then
Call MsgBox("Length of ranges have to be the same.")
Exit Function
End If
v = 0
For i = 1 To dt_start.Count
d1 = CDate(dt_start(i))
d2 = CDate(dt_end(i))
v1 = CDate(this_date)
v2 = DateAdd("n", min_loop, v1)
If Not ((d1 < v1 And d2 < v1) Or (d1 > v2 And d2 > v2)) Then
v = v + CDbl(values(i))
End If
Next i
SumBetweenDateTimeLoop = v
End Function
The result is reported in the red column (there are some differences from your green column but it should be correct if I understood correctly your problem).
In order to call the function (after have copied it into a module in VBA), type in the desired Excel cell the following request.
=SumBetweenDateTimeLoop(G2;A$2:A$10;E$2:E$10;C$2:C$10;30)
Code explanation
The idea is to define extremes of the cycle, so define v1 as the datetime in column G and v2 = v1+min_loop.
Then make a loop over the cells of the ranges (Excel columns A, E and C), define the extremes of datetime (d1 start datetime in column A and d2 ending datetime in column E) and check whether or not both d1 and d2 are lower than v1 or greather than v2.
If this condition is not satisfied, it means that at least a part of the time is inside the desired cycle and then add the relative value to the incremental parameter v, which at the end will be the return of the function.
It's not that difficult: the solution is 48 :-)
By this I mean that, in Excel, and entire day is one unit (e.g. 01/01/2022 + 1 = 02/01/2022).
As a result, one hour equals 1/24th and half an hour (30 minutes) corresponds with 1/48th of a day.
So, you want to round down to 1/48, which you can do using this simple formula:
=FLOOR(B2*48,1)/48
Hereby some examples:
Related
In cell A1 I have an interval value which is an integer which can either be 1, 5 or 15 which means 1 minute, 5 minutes or 15 minutes
In range "B1:B12", I have the sample data (it will be more)
12:03
12:03
12:06
12:06
12:09
12:11
12:14
12:15
12:15
12:16
12:31
12:32
Now in column C, I need to extract time slots based on number is available in cell A1.
If cell A1 has 15 then the column C would contain below
12:15
12:30
because first 15th minute in column starts at 12:15 then increment it by 15 mins until last available data which falls in that 15 min range.
If cell A1 has 5 then the column C would contain below
12:05
12:10
12:15
12:30
because first 5th minute starts at 12:05 then increment it by 5 mins until last available data which falls in that 15 min range.
and if cell A1 has 1 then extract everything except duplicates.
I hope I have explained the scenario properly. I am not able to think of a logic to do this in excel vba and need help with how to start so that I can try to apply the logic and comeup with a code.
Thank you
EDIT
I am adding a pic of the desired result.
if A1 contains 1 then copy all timestamps in column C without the duplicates
if A1 contains 5 then show only 5 times of 5 min interval
if A1 contains 15 then show only 3 times of 15 min interval
Using VBA (1) returning an array
You will need to ctrl-shif-enter
Option Explicit
Function get_unique_time_interval(ByVal interval_size As Double, ByVal input_data As Range) As Variant
interval_size = interval_size / 60# / 24#
Dim d
Set d = CreateObject("Scripting.Dictionary")
Dim r As Range
For Each r In input_data
Dim t As Double
t = Int(r.Value / interval_size) * interval_size
If Not d.exists(t) Then d.Add t, t
Next r
get_unique_time_interval = Application.WorksheetFunction.Transpose(d.keys)
End Function
(2) hard-coded outputting to C1
option explicit
Sub get_unique_time_interval_sub()
Dim interval_size As Double: interval_size = ActiveSheet.Range("a1").Value
Dim input_data As Range: Set input_data = Range(ThisWorkbook.Sheets(1).Range("b1"), ThisWorkbook.Sheets(1).Range("b1").End(xlDown))
interval_size = interval_size / 60# / 24#
Dim d
Set d = CreateObject("Scripting.Dictionary")
Dim r As Range
For Each r In input_data
Dim t As Double
t = Int(r.Value / interval_size) * interval_size
If Not d.exists(t) Then d.Add t, t
Next r
Dim v As Variant
Dim i As Long
i = 0
If Not IsEmpty(Range("c1").Value) Then Range(Range("c1"), Range("c1").End(xlDown)).ClearContents
For Each v In d.keys
ThisWorkbook.Sheets(1).Range("c1").Offset(i, 0).Value = v
i = i + 1
Next v
End Sub
this works as a single cell formula in C1:
=UNIQUE(INT(B1:B12/(A1/60/24))*(A1/60/24))
breaking it down:
A1/60/24
is the time interval you want (A1 in minutes so divide by 60 mins per hour and 24 hours per day to get to Excel time interval units). Then:
INT(B1:B12/(A1/60/24))
rounds you down to the start of the time period. Then:
*(A1/60/24)
converts you back up to the time of the interval in which the input time falls. Then:
UNIQUE(
pulls out the unique values.
The helpful thing here is that by including B1:B12 as a range it makes everything (helpfully) spill
If you accept a formula based answer then This should work for you:
A1: some inteval value.
B1:
=0.5+A1/(24*60)
Where 0.5 mean 12:00 in Excel.
In B2:
=B1+$A$1/(24*60)
And drag this formula down to where you need it.
Exampls:
I have a table of values that I am trying to pull a number from by using a for loop that chooses the right table column based a value that was input into my spreadsheet. The input value (FvX2) is rounded to the nearest tenths place using the Ceiling function. This is then compared to values in the table by increasing the column number until the rounded value in the table equals the rounded number input into the spreadsheet. My problem is excel will not recognize when the two values are equal and never returns a value for Fvcl. I think this has something to do with the ceiling function but don't know how to get around it. Any ideas? Input value is 0.52 and is rounded to 0.6. Table values start at 0.1 and increase to 0.6 by increments of 0.1. Excel will not return Fvcl when FvX2 equals table value.
Dim FvX1 As Double
Dim FvX2 As Double
Dim Fvcl As Double
FvX2 = WorksheetFunction.Ceiling(Worksheets("Sheet1").Range("B7").Value, 0.1)
FvX1 = FvX2 - 0.1
For j = 0 To 5
If Worksheets("Tables").Cells(11, 2 + j).Value = FvX2 Then
Fvcl = 2 + j
End If
Next j
I have a date which I will need to increment the date by a day, month or year from the actual date. This is based of a list of fields below and is different per the input. Also each resultant date has to be a business day i.e not a weekend day or a bank holiday. Also if the resultant date is either Dec 25 or Jan 1st the day needs to move forward to the next business day (not a weekend day).
I have created this in Excel using a couple of formulas though it is a bit clunky.
Below is my data set
Business Date 15/05/2018
Tenor Settlement Value Settlement Period
ON 1 Day
TN 2 Day
SP 2 Day
SN 3 Day
1W 7 Day
2W 14 Day
3W 21 Day
1M 1 Month
2M 2 Month
3M 3 Month
In column E - I am using formula
=IF(D4="Day",$B$1+C4,IF(D4="Month",EDATE($B$1,C4),(TEXT($B$1,"dd/mm/")&(YEAR($B$1)+C4))+0))
In column F - I am using formula
=E4+LOOKUP(WEEKDAY(E4),{1,2,3,4,5,6,7},{1,0,0,0,0,0,2})
In column G - I am using formula
=F4+IF(AND(OR(TEXT(F4,"ddmm")="2512",TEXT(F4,"ddmm")="0101"),WEEKDAY(F4)>=2,WEEKDAY(F4)<=6),LOOKUP(WEEKDAY(F4),{1,2,3,4,5,6,7},{0,1,1,1,1,3,0}),LOOKUP(WEEKDAY(F4),{1,2,3,4,5,6,7},{1,0,0,0,0,0,2}))
In H I format the date in mm/dd/yyyy and I have my desired result.
storax has kindly created a function for me which replicates my excel formula in column E - on this thread Increment a date by a number of days, months or years
Function IncDate(ByVal dt As Date, ByVal add As Long, ByVal dmy As String) As Date
Select Case UCase(dmy)
Case "DAY"
IncDate = DateAdd("d", add, dt)
Case "MONTH"
IncDate = DateAdd("m", add, dt)
Case "YEAR"
IncDate = DateAdd("yyyy", add, dt)
Case Else
IncDate = dt
End Select
Could use some advise on how I could incorporate my formulas in columns F & G to make the process less clunky.
Manipulating the DATE function (DateSerial in vba) with the WORKDAY.INTL function seems to produce the correct business dates.
Put this in E4 and fill down.
=WORKDAY.INTL(DATE(YEAR(B$1)+(D4="year")*C4, MONTH(B$1)+(D4="month")*C4, DAY(B$1)+(D4="day")*C4)-1, 1, 1, holidays)
[holidays] is a named range (Formulas, Defined Names, Defined Name) with a Refers To: of,
=Sheet10!$Z$2:INDEX(Sheet10!$Z:$Z, MATCH(1E+99, Sheet10!$Z:$Z))
Consider this data:
Project Name Due Completed
P1 T1 04/10/14 04/10/14
P1 T2 05/10/14 06/10/14
P2 T22 07/10/14 07/10/14
P1 T3 17/10/14
Is there a formula that can look at this list and pick out all the P1's and evaluate the dates to work out whether they were completed on time. I.E. the data above should produce no as the second task was completed late.
Assuming your data is in columns A - D, add your Project name to cell E1, and enter this as an array formula (Ctrl + Shift + Enter):
=IF(MAX(IF($A:$A=E$1,$D:$D-$C:$C))>0,"no","yes")
Output:
How it works
Excel stores dates as numbers, so you can subtract one date from another.
Here, I'm subtracting Due from Completed:
If the result is a positive number (row 3), the project was completed late. The negative number occurs because a blank cell is treated as 0 when doing calculations. Oct 17, 2014 is stored by Excel as the number 41929, so 0 - 41929 = -41929.
This part of the array formula compares each project in column A to the project name in E1, and it returns an array of the results:
IF($A:$A=E$1,$D:$D-$C:$C)
In our example, the array looks like this: {0,1,-41929}
The MAX function takes the maximum value from the array – in this case the number 1.
The outer IF function tests if MAX's result is greater than 0, which would indicate that the project was completed late. If so, it returns "no." Otherwise, it returns "yes."
I have an Excel file with several columns in it and many rows. One column, say A has ID numbers. Another column, say G has prices. Column A has repeating ID numbers, however not all numbers repeat the same amount of times. Sometimes just once, other times 2, 3 or several times. Each column G for that row has a unique price.
Basically, I need to average those prices for a given ID in column A. If each ID was repeated the same number of times, this would be quite simple, but because they are not I have to manually do my average calculation for each grouping. Since my spreadsheet has many many rows, this is taking forever.
Here is an example (column H is the average that I am currently calculating manually):
A ... G H
1 1234 3.00 3.50
2 1234 4.00
3 3456 2.25 3.98
4 3456 4.54
5 3456 5.15
11 8890 0.70 0.95
13 8890 1.20
...
So in the above example, the average price for ID# 1234 would be 3.50. Likewise, the average price for ID# 3456 would be 3.98 and for #8890 would be 0.95.
NOTICE how rows are missing between row 5 and 11, and row 12 is missing too? That is because they are filtered out for some other reason. I need to exclude those hidden rows from my calculations and only calculate the average for the rows visible.
Im trying to write a VBA script that will automatically calculate this, then print that average value for each ID in column H.
Here is some code I have considered:
Sub calcAvg()
Dim rng As Range
Set rng = Range("sheet1!A1:A200003")
For Each Val In rng
Count = 0
V = Val.Value '''V is set equal to the value within the range
If Val.Value = V Then
Sum = Sum + G.Value
V = rng.Offset(1, 0) '''go to next row
Count = Count + 1
Else
'''V = Val.Value '''set value in this cell equal to the value in the next cell down.
avg = Sum / Count
H = avg '''Column G gets the avg value.
End If
Next Val
End Sub
I know there are some problems with the above code. Im not too familiar with VBA. Also this would print the avg on the same line everytime. Im not sure how to iterate the entire row.
This seems overly complicated. Its a simple problem in theory, but the missing rows and differing number of ID# repetitions makes it more complex.
If this can be done in an Excel function, that would be even better.
Any thoughts or suggestions would be greatly appreciated. thanks.
If you can add another row to the top of your data (put column Headers in it) its quite simple with a formula.
Formula for C2 is
=IF(A2<>A1,AVERAGEIFS(B:B,A:A,A2),"")
copy this down for all data rows.
This applies for Excel 2007 or later. If using Excel 2003 or earlier, use AVERAGEIF instead, adjusting ranges accordingly
If you can't add a header row, change the first formula (cell C1) to
=AVERAGEIFS(B:B,A:A,A1)
In my way ..
Sub calcAvg()
Dim x, y, i, y2, t, Count, Mount As Integer
Dim Seek0 As String
x = 1 '--> means Col A
y = 1 '--> means start - Row 1
y2 = 7 '--> means end - Row 19
For i = y To y2
If i = y Then
Seek0 = Cells(i, x)
t = i
Count = Cells(i, x + 6)
Mount = 1
Else
If Cells(i, x) <> Seek0 Then
Cells(t, x + 7) = Count / Mount
Count = Cells(i, x + 6)
Mount = 1
t = i
Seek0 = Cells(i, x)
Else
Count = Count + Cells(i, x + 6)
Mount = Mount + 1
End If
End If
Next
End Sub
Hope this helps ..