Finding oldest date in column with separated data - excel

I am making a function that will search through a range and find the oldest date (the oldest date is in last row with data). My range is structured as following and I won't be able to change this structure:
Year Month Day
yyyy mm dd
So the year month and day are seperated in three different columns.
My code is as following:
Function OLDEST(yearrng As Range) As Variant
Dim lastrow As Long
Dim year, month, day As String
lastrow = Range(yearrng).SpecialCells(xlCellTypeBlanks).Row
year = Range("I" & lastrow).value
month = year.Offset(0, 1).value
day = year.Offset(0, 2).value
OLDEST = year & month & day
End Function
The yearrng is the same range which the years are displayed.
The problem is that this function is not working and is returning "value error"...
I hope you understood my question.
Thanks!

For a non-volatile worksheet function, you can try:
=DATE(LOOKUP(2,1/(LEN($I:$I)>0),I:I),LOOKUP(2,1/(LEN($I:$I)>0),J:J),LOOKUP(2,1/(LEN($I:$I)>0),K:K))
where I is the column to test for which is the "bottom" row, and I, J, and K are the columns with the relevant date parts.

Related

Is there a way retrieve a value that falls between 2 dates?

I am trying to build a VBA code where I am given 2 dates to be used as a date range. Using this date range, I am trying to compare it to a date in every row within a table. If the table date is within the date range, I want to retrieve a specific value also within the table.
Example:
Date Range:
02/01/2021 - 07/01/2021
The colors are in Column A and the dates are in column B
Red - 03/08/2021
Orange - 09/01/2021
For this example, I need it to return "Red"
Yes there is...
If you try it, remember to first set the correct values on the CONFIG sections of the code.
Sub RetrieveValue()
Dim start_date, end_date As Date
Dim dates_col, db_start_row, db_end_row As Integer
Dim counter, values_col, retrieve_values_col As Integer
'CONFIG THIS BEFORE YOU RUN THE MACRO
'--------------------------
retrieve_values_col = 4 'column number where you want to retrieve the values
values_col = 2 'column where all the values are
dates_col = 3 'in what column are the dates?
db_start_row = 3 'in what row does the data start?
start_date = Date - 4 'set the date interval
end_date = Date + 3 'DATE is a function that returns todays date
'--------------------------
db_end_row = Cells(Rows.Count, dates_col).End(xlUp).Row
For counter = db_start_row To db_end_row
If Cells(counter, dates_col) >= _
start_date And Cells(counter, dates_col) <= end_date Then
Cells(counter, retrieve_values_col) = Cells(counter, values_col)
End If
Next counter
End Sub
The dates must be set like in the following picture for the macro to work.

Calculating Attendance dates for Students using VBA Excel

I need a little help with resolving a VBA code for an school assignment.
Dim i As Long
Dim LastStudent As Long
Records.Sheets("Student").Activate
LastStudent = Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To LastStudent
If (DateDiff("d", Date, Attendance_rng.Range("I" & i).Value) > 80) Then
.Range("K15").Value = WorksheetFunction.CountIfs(Attendance_rng.Range("A:A"), RollNo, Attendance_rng.Range("D:D"), "ACTIVE")
End If
Next
I tried to execute the above code snippet. I don't see any errors but I don't get any data output either.
I want to count the number of days (Today's date - date in column I for each student), if that value is > 80 then record the day count in cell K15 for each student(Roll Number) from column A where the G Column data is "Active".
Note:
Column I has the Weekly recorded attendance dates

Get data based on Months (Name) excel vba

Im currently creating a template for our report. And I would like to do some automation.
I have a source sheet which I call "KPISource" (Data source is in sharepoint, thus this is a table). And in the first column I would like to get data which has has the current Month and the previous month.
Basically, If it is current month, it will then put the data in the "August" column. And If the date is previous month, then it will also put the data in the "July".
In my source sheet, the columns are Date, Tickets Solved (productivity), YTD, Ticket Reopen Rate(quality), Aging <5 days (Quality), YTD (Aging <5 days) Aging > 5 days (Quality), YTD (Aging >5 days), Customer Satisfaction, YTD (Customer Satisfaction)
Currently here is my code, but no output is appearing. This is the code that I'm trying if the there is a previous date in column 1 (KPISource), then it will have the value in KPI.Cells(6, 4).Value (Tickets Solved "July").
Sub OperationalKPI()
Dim KPI As Worksheet
Set KPI = Sheets("OperationalKPI")
Dim KPISource As Worksheet
Set KPISource = Sheets("KPISource")
mPrevious = Format(DateAdd("m", -1, Date), "mmmm")
mCurrent = Format(Date, "mmmm")
lastrow = KPISource.Cells(Rows.Count, 1).End(xlUp).Row
For x = 2 To lastrow
If mPrevious = KPISource.Cells(x, 1) Then
KPI.Cells(6, 4).Value = KPISource.Cells(x, 2).Value
End If
Next x
End Sub
The problem, based upon your feedback, is in the line
If mPrevious = KPISource.Cells(x, 1) Then
mPrevious is a string containing the name of the month, eg "July", however KPISource.Cells(x, 1) contains a date so the two are never going to be equal.
Change the line to:
If mPrevious = Format(KPISource.Cells(x, 1),"mmmm") Then
This will make both items strings with the name of the month in them and the If should find the matches.

Writing a VBA function to sum "Cost Per Hour" into "Cost Per Day" and then into "Cost per Month"

I am trying to model the cost of my home heating unit. I have 3.15 years of hourly data. I calculated cost per hour, cost per day, cost per month, and cost per year. I want to write two VBA function, one called CostPerDay and the other called CostPerMonth in order to simplify the process when I add more data. I have attached a picture of my data.
Picture of Data
The function I wrote for Cost Per Day is:
=SUM(OFFSET($M$18,(ROW()-18)*24,0,24,1))
The function I wrote for Cost Per Month is:
Jan-13 =SUM(OFFSET($P$18,(ROW()-18)*31,0,31,1))
Feb-13 =SUM(OFFSET($P$49,(ROW()-19)*28,0,28,1))
Mar-13 =SUM(OFFSET($P$77,(ROW()-20)*31,0,31,1))
Etc...
In case you need the whole range of data:
Cost Per Hour - M18:M27636
Cost Per Day - P18:P1168
Cost Per Month - S18:S55
Average Cost Per Month - V18:V29
This is what I was trying. As you can see, I am new to VBA. In the first attempt, I was trying to use Dim to define where the data was located in the spreadsheet and which cell I wanted the calculation in. I got stuck because I couldn't insert the =SUM(OFFSET($M$18,(ROW()-18)*24,0,24,1))function into VBA. I then was trying to make get rid of the hard-coded $M$18by replacing it with Cells(Match(Day,O18:O1168)+17,"P"). But none of it worked.
The second one I was playing with dialogue boxes, but I don't think I want to use them.
In the third attempt I was trying to calculate Cost Per Month. I don't have it because I didn't save it. I was using SUMIFSto match Months with the number of days in the month. That may have been my closest attempt but it still didn't work.
Function CostPerDay(BeginningCostPerDay, OutputCell)
Dim BeginningCostPerDay, OutputCell
BeginningCostPerDay = WorksheetFunction.DSum()
OutputCell = ActiveCell.Offset(3, -3).Activate
End Function
Function CostPerDay1()
Dim myValue1 As Variant, myValue2 As Variant
myValue1 = InputBox("Where do you want the data put?")
myValue2 = InputBox("What is the beginning Cost Per Day")
Range("myValue1").Value = myValue1
Range("myValue2").Value = myValue2
End Function
What if you added a helper column that started with 1 in cell A1 for example. Second row (A2) would be =If(A1=24,1,A1+1). Column B would have the hourly data. Column C or C1 would say =If(and(A1=24,A2=1),B1,B1+B2)). I didn't test, but I think this should work with perhaps a tweak.
Here's your answer.
Private Sub SumCosts(ByVal MainColumn As String, ByVal CostColumn As String, ByVal FirstDataRow As Long, Optional ByVal BracketType As Byte)
'
'Parameters:
'MainColumn: the columns with dates or months.
'CostColumn: the column that holds the costs to sum.
'FirstDataRow: the first row where the data starts
'BracketType: either 0 for hours or 1 for months
'
'This procedure assumes that in the data on the sheet
'- every hour of every day in the hours columns
'- every day of a month is present in the days columns
'are present. I.e. All hours of all 31 days of January are persent
'in the 'Date' column before the hours of February start and all days of January
'are present in the 'Month' column before the days of February start.
Const Hours As Byte = 24
'
Dim Cel As Range
Dim I As Long
Dim J As Long
Dim K As Long
Dim Rng As String
Dim Bracket As Byte
Dim Days As Byte
'
'Clean the target area, so the modle can be reused time after time.
Set Cel = Range(MainColumn & Application.Rows.Count).Offset(0, 1)
Rng = Split(Cel.Address, "$")(1)
Rng = (Rng & FirstDataRow & ":" & Rng & Cel.End(xlUp).Row)
Range(Rng).ClearContents
'
J = FirstDataRow
For Each Cel In Range(MainColumn & ":" & MainColumn)
If Cel.Value = vbNullString Then Exit For
If Cel.Row > (FirstDataRow - 1) Then
'Number of days in a month. Since this fluctuates the bracket fluctuates.
Days = DateSerial(Year(Cel.Value), Month(Cel.Value) + 1, 1) - DateSerial(Year(Cel.Value), Month(Cel.Value), 1)
Bracket = IIf(BracketType = 0, Hours, Days) 'Select the bracket to use.
K = ((Cel.Row - 1) * Bracket) + (FirstDataRow - 1) 'Determine where to stop calculating for a given day or month.
For I = J To K
Cel.Offset(0, 1).Value = Cel.Offset(0, 1).Value + Range(CostColumn & I).Value 'Do the calculation.
Next
J = K + 1 'Next loop we must pick up where we left off.
End If
Next
End Sub
Public Sub LaunchCostCalculations()
SumCosts "O", "M", 2, 0
SumCosts "R", "P", 2, 1
End Sub
Create a button in your sheet to launch LaunchCostCalculations and Bob's your uncle.

Find number of concurrent, overlapping, date ranges

I have a puzzle I've been trying to solve for ages now, but it's quite simply beyond me.
I have a spreadsheet with 3 columns. Column A is instructor ID numbers, Column B is their course Start date and Column C is their course end date. There are multiple courses for each instructor ID.
I'm basically trying to answer the question, what is the maximum number of courses this instructor is teaching at any given time.
Essentially, I need to find, for each ID number, the number of maximum, concurrent, overlapping date ranges.
The trouble is, while I know how to find overlapping date ranges, I don't know how to count the number of concurrent courses.
Eg.
Instructor 115 has the following date ranges listed:
9/10/13 / 11/04/13
9/17/13 / 11/11/13
11/05/13 / 12/30/13
11/12/13 / 1/20/14
While the 11/05/13 course overlaps with both the 9/17/13 course and the 11/12/13 course, they do not overlap with each other... so this instructor is only teaching a maximum of 2 courses at any time.
Is there a way to write a function that will return the highest number of concurrent overlapping date ranges for each ID?
Edit not form OP to transfer details from a comment:
I can solve this geometrically, but I don't know how to do that in a VBA function (I'm still very new to programming). If I were to solve this outside of code, I would create a table for each ID making a column for every day. I'd then create a row for each date range, marking a 1 in each column that range overlaps with. then I’d sum the total overlaps for each day. Then I’d use a simple MAX function to return the highest number of consecutive overlaps. Is there a way to do this inside of a function without having Excel physically draw out these tables?
Using VBA, assuming Column A contains your start dates, and column B contains your end dates, and assuming your data starts in row 1 and there are no blank rows in your data, the below sub will do what you outlined in your comment:
Sub getMaxConcurrent()
'get minimum date (startDate)
Dim startDateRange
Set startDateRange = Range("A1", Range("A1").End(xlDown))
Dim startDate As Date
startDate = WorksheetFunction.Min(startDateRange)
'get maximum date (endDate)
Dim endDateRange
Set endDateRange = Range("B1", Range("B1").End(xlDown))
Dim endDate As Date
endDate = WorksheetFunction.Max(endDateRange)
'get date range (dateInterval)
Dim dateInterval As Integer
dateInterval = DateDiff("d", startDate, endDate)
'Create daily table header
Rows("1:1").Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
Dim x As Integer
For x = 0 To dateInterval
Dim dateVal As Date
dateVal = DateAdd("d", startDate, x)
Cells(1, 3 + x).Value = dateVal
Next
'Fill in daily table
Dim y As Integer
y = 2
Dim startDateValue As Date
startDateValue = Cells(y, 1).Value
Do Until IsEmpty(Cells(y, 1).Value)
For x = 3 To dateInterval + 3
If (Cells(y, 1).Value <= Cells(1, x).Value) Then
If (Cells(y, 2).Value >= Cells(1, x).Value) Then
Cells(y, x).Value = 1
Else
Cells(y, x).Value = 0
End If
Else
Cells(y, x).Value = 0
End If
Next
y = y + 1
Loop
'sum up each day
For x = 3 To dateInterval + 3
Cells(y, x).Value = WorksheetFunction.Sum(Range(Cells(2, x).Address & ":" & Cells(y - 1, x).Address))
Next
MsgBox ("Max concurrent courses: " & WorksheetFunction.Max(Range(Cells(y, 3).Address & ":" & Cells(y, x).Address)))
End Sub
If you have data down to row 1000 then this "array formula" will give the maximum number of concurrent courses for an Instructor ID in E2
=MAX(COUNTIFS(A:A,E2,B:B,"<="&B$2:C$1000,C:C,">="&B$2:C$1000))
confirmed with CTRL+SHIFT+ENTER
Let's assume there is only one instructor and you have start and end dates in A1:B4.
Copy A1:A4 to A7:A10, copy B1:b4 to A11:a14 (right under it). Select A7:A14, hit Sort (on data tab) and "remove duplicates". You have a list unique list of dates in ascending order. Let's assume there were no duplicates (as in your example), your of date is same A7:a14. Select it copy, and paste spacial with transpose to C5.
At this point You have start and end dates in A1:B4 and list of uniqe dates in C5:J5. Put formula =IF(AND($A1<=C$5,C$5<=$B1),1,0) in C1 and copy it to C1:J4.
put formula =SUM(C1:C4) in C6 and copy it to C6:J6.
Maximum number in C6:j6 is your maximum concurrent courses for this instructor

Resources