Calculate date overlap in months - excel

Need a bit of help, if you'd be so kind.
In MS Excel, I'm trying to work out the number of months that a student attends university based off of the academic year.
For instance, a student enrolls & finishes university on the following dates:
23/06/2018 - 23/06/2020
and there are multiple academic years which the student attends:
01/08/2017 - 31/07/2018
01/08/2018 - 31/07/2019
01/08/2018 - 31/07/2020
I want to calculate how many months the student attends in each academic year:
01/08/2017 - 31/07/2018 (1 month)
01/08/2018 - 31/07/2019 (12 months)
01/08/2018 - 31/07/2020 (11 months)
I've managed to calculate the days using this function:
=MAX(MIN(term_end_date, student_,end_date) - MAX(term_start_date, student_start_date)+1,0)
But, I need months, if possible.
Appreciate the help in advance.

=DATEDIF(A1,B1,”M”) will give the number of whole months between 2 dates (i.e., excluding start and end months) where dates are entered in A1 and B1. The “M” signifies that you’d like the information reported in months.
For a more accurate result, try:
=(DATEDIF(A1,B1,”D”) / 365) * 12. If the dates span multiple years - including leap years - try dividing by 365.25 vs 365.

Please try this UDF.
Function MonthsOverlap(Rng As Range, _
AccYear As Integer) As String
' 016
Const Ststart As Long = 1 ' index of array 'Study'
Const Stend As Long = 2 ' index of array 'Study'
Dim Fun As Integer ' Months of overlap
Dim YearStart As Date, YearEnd As Date
Dim Study As Variant
YearStart = DateSerial(AccYear, 8, 1) ' modify year and day as required
YearEnd = DateAdd("yyyy", 1, YearStart)
Study = Rng.Value ' Rng columns must be adjacent
With Application.WorksheetFunction
If Study(1, Ststart) <= YearStart Then
Fun = DateDiff("m", .Max(Study(1, Ststart), YearStart), .Min(Study(1, Stend), YearEnd))
ElseIf Study(1, Ststart) <= YearEnd Then
Fun = DateDiff("m", .Max(Study(1, Ststart), YearStart), YearEnd)
End If
Fun = .Max(Fun, 0)
End With
MonthsOverlap = Fun & " month" & IIf(Fun = 1, "", "s")
End Function
I tested it in a sheet like the one pictured below. Please observe the formula in the Formula Bar.
As you see, the function returns unexpected results for the years 2017 and 2019. I don't think they are wrong. The formula just uses rounding of months different from your system. I think the function can be modified to accommodate your rule once you make it known. Meanwhile it follows Microsoft's rule which, frankly, I also don't know. However, observe that the total time of study is 24 months which is correct and therefore sufficient, in conjunction with a look at the clock, to convince me to let good be good enough for today :-)

I found a solution which works a treat:
Thanks for all your help everyone.

Related

How to handle dates across midnight in Excel

I have data with the following structure:
Date
Time
01-01-2021
0800-1600
01-01-2021
2000-0400
Each line is an employee and their worked hours. Meaning the first line employee #1 meets 0800 and leaves at 1600 the same day. However employee #2 meets 2000 and leaves 0400 the following day.
My issue is that I'm working showing no. of employees present at specific times. The first employee is easy to do as meeting and leaving is the same day. However the second is a bit more problematic, as in my current setup the employee is shown on work the same day.
The data is updated automatically into excel so I don't want to make any manual adjustments.
In order to show it correctly, and from my point of view, I need to make an additional line with the hours for the following day. I could make this with VBA, but I'm not sure if this is the easiest and best way to do it.
So any ideas on how to handle an issue like this?
Thanks!
This formula will give your the hours worked:
=LET(DateValue, A2,
TimeValues,FILTERXML("<t><c>"&SUBSTITUTE(B2,"-","</c><c>")&"</c></t>","//c"),
Start,INDEX(TimeValues,1),
End,INDEX(TimeValues,2),
StartTime, SUM(DateValue, Start/2400),
EndTime, IF(Start<End,SUM(DateValue,End/2400),SUM(DateValue+1,End/2400)),
EndTime - StartTime)
This will give you the hours worked in day one or day two (change the last variable to Day1Hours):
=LET(DateValue, A2,
TimeValues,FILTERXML("<t><c>"&SUBSTITUTE(B2,"-","</c><c>")&"</c></t>","//c"),
Start,INDEX(TimeValues,1),
End,INDEX(TimeValues,2),
StartTime, SUM(DateValue, Start/2400),
EndTime, IF(Start<End,SUM(DateValue,End/2400),SUM(DateValue+1,End/2400)),
Day1Hours, IF(Start<End,EndTime-StartTime,(DateValue+1)-StartTime),
Day2Hours,IF(End<Start, EndTime-(DateValue+1),0),
Day2Hours)
This I was hoping would return both results, but FILTERXML didn't seem to work within the LET function when returning the results:
=LET(DateValue, A2,
TimeValues,FILTERXML("<t><c>"&SUBSTITUTE(B2,"-","</c><c>")&"</c></t>","//c"),
Start,INDEX(TimeValues,1),
End,INDEX(TimeValues,2),
StartTime, SUM(DateValue, Start/2400),
EndTime, IF(Start<End,SUM(DateValue,End/2400),SUM(DateValue+1,End/2400)),
Day1Hours, IF(Start<End,EndTime-StartTime,(DateValue+1)-StartTime),
Day2Hours,IF(End<Start, DateValue+1-EndTime,0),
TRANSPOSE(FILTERXML("<t><c>" & Day1Hours & "</c><c>" & Day2Hours & "</c></t>","//c")))
Create a User Defined Function (UDF) to return a datetime in cols C and D from the values in col A and B. Put the UDF code in a module. For example the formula in C2 would be =date_time($A2,$B2,0) and in D2 =date_time($A2,$B2,1)
Option Explicit
' i=0 for start , i=1 for end
Function date_time(dt As Date, hrs As String, i As Integer) As Date
Dim ar
ar = Split(hrs, "-")
If ar(1) < ar(0) Then ar(1) = ar(1) + 2400 ' next day
' add minutes
date_time = DateAdd("n", Left(ar(i), 2) * 60 + Right(ar(i), 2), dt)
End Function

Calculation and search in ranges of codes

I have a question regarding the Calculation of something:
I used to use this function below to calculate the available hours of working colleagues like this:
Function BerekenUrenPercentage(OptelGebied As Range, TriggerWoord As String, PercentageGebied As Range) As Double
Dim Cel As Range, Uren As Double, Waarde As String, Teller As Double, Factor As Integer
For Each Cel In OptelGebied.Cells
Teller = Teller + 1
If InStr(Cel.Formula, TriggerWoord) > 0 Then
Waarde = Cel.Formula
Waarde = Replace(Waarde, TriggerWoord, "")
Factor = PercentageGebied.Formula(Teller, 1)
Uren = Uren + ((Int(Waarde) * Factor) / 100)
End If
Next Cel
BerekenUrenPercentage = Uren
End Function
But I need some more flexibility and efficiency in my calculations so I reworked the whole thing, but can't figure out the formula I need to use.
It searches in a whole week of attendance (7 columns) for the desired Code (see below), if found it subtracts that code from the cell and only the hours remain.
It duplicates that with the percentage of Employability (searches in the correct week and person (on Pers ID)) and searches on.
I Would also like (later on) to enter multiple codes in 1 cell like: DAV4/VK4 or DAV4/DEV4 in the future and still find the two correct codes
We have an attendance schedule on my work:
Attendance Table where we note if someone is working, in which discipline and for how long.
Like: DAA8 -> DAA is a code and 8 is 8 hours
Examples of codes: DVP8, DVA,DVV,DPP,DPA,DPV,DAP,DAA,DAV,DEV,DLOG, VK8,ZK8,BK8,BL6 etc
VK = Vacation, ZK = Sick
There is also an Table for Employability in Percentage Where all the workers are displayed with the percentage of employability. We use this to calculate how many hours a person is helping towards our goal.
And the calculation of Hours available table: Here is where I will use the function I am searching for.
Can anyone help me?
Example: In the first cell of the attendance table is one of the cells i want to count.
I want the lookup function
cell (in the picture has the value 120) in the row with the code DVP
(left of that cell) to search for the code, Distill the numeric value
multiply that by the corresponding week in the Employability table.
And do that for every occurence of the code in the week the cell
stands (top of the tables).

How to use the Resize function with the offset function in VBA code for a User Defined Function in Excel

I have 10 years worth of monthly returns of an asset. I am trying to create a function that can give me the annualised returns of this series of monthly return data. I would like to use the Offset function to go to the last monthly returns date, select an array of periods that I choose (3 months back, 6 months back, 12 months back, 24 months back etc) so that I can get the annualised return of a series of returns from the end date back to a specific period.
The goal is to calculate the monthly average monthly returns of the last 3 months, 6 months, 12 months etc.
However, the parameters for the Offset function in VBA are different to those in normal Excel functions. I think I need to use the .Resize function to resize my Offset function.
Here is how the function works in Excel
=GEOMEAN(1+OFFSET($W$4,MATCH(LARGE($V$4:$V$10485,1),$V$4:$V$10485,0)-1,0,-$AJ17,1))-1
Rewritten so that you can understand my variables
=GEOMEAN(1+OFFSET(ref,MATCH(LARGE(Dates,1),Dates,0)-1,0,-period,1))-1
Here is the code that I have written so far...
Function Returns(ref As Range, Dates As Range, Period As Integer) As Variant
With Application.WorksheetFunction
Returns = .Geomean(1 + ref.Resize(-Period, 1).Offset(.Match(.Large(Dates, 1), Dates, 0) - 1, 0))-1
End With
End Function
Please, can someone help?
Okay, so I figured out a few of my errors.
A) I declared the variables incorrectly.
B) I used a negative number for resize as I wanted the function to go to the end of the series and count back (to get 6 month. 12 month, 24 month returns). This does not work.
As an alternative, I have used LARGE to find the nth largest date and select the array below that point.
See code below.
Function AnnReturns(Ref As Variant, Dates As Variant, Period As Variant, M As Variant) As Variant
With Application.WorksheetFunction
AnnReturns = .FVSchedule(1, (Ref.Offset(.Match(.Large(Dates, Period), Dates, 0) - 1, 0).Resize(Period, 1))) ^ (1 / M) - 1
End With
End Function

Need to change date into current work week (1-52), but skip to the next week if the day is Wed - Sat in VBA

I'm having trouble writing code in VBA that would allow me to input any given date then have an output of the current work week. I need a restriction of if the date is Sunday through Tuesday, it will keep that current work week and year but if the date is Wednesday through Saturday, then the next work week and year will show. For example, I'm looking to input (5/28/19) and have an output of 201922 or an input of (5/29/19) with an output of 201923 even though its technically the same work week.
Before getting too in depth, I do have a working function that provides the year and work week, but I'm trying to adapt the function or add a separate function that will change in to the next work week according to the given date.
I'm new to VBA but have tried to do a little research over the last few days. I was thinking that I could somehow have one input of the date then have two outputs where one would be the year and work week then the other would be the number associated with that date (1 for Sunday, 2 for Monday, and so on). I tried to create an if then statement that says if the number associated with that date is 1, 2, or 3 then the workweek would stay the same. If it was any other number then 1 would be added to that work week so it would move to the next one. I'm having trouble with trying to make two outputs and have them connected, if that makes any sense.
This is the code that I tried to create, but continuously failed at making. The function that gives the correct work week (without the adaptation of the work week based on the date weekday) is WWV1
Function WWV2(WeekdayName As Integer)
Dim WWV1 As Integer
If WeekdayName(Date) = 1 Or 2 Or 3 Then WWV1 = WWV1
Else: WWV1 = WWV1 + 1
End Function
This provides the cell with #NUM! when I use the function in that cell, which I assume is because I need to somehow connect the two functions.
how about this:
=YEAR(A1) & TEXT(WEEKNUM(A1,13),"00")
WeekNum returns the weeknumber with 13 saying it starts on Wednesday:
VBA
wkcd = Year(Range("A1")) & Format(Application.WeekNum(Range("A1")),"00")

Dates and Charting

I have three sets of data and each has two columns.
The first column is Date and second column is Price. The dates are formatted different with each data set eg. Gold's date(1951), Money Supply M2's date (1951-01), and Money Sup. M3 Date (9/01/1951)
What i need:
I want to chart these with dates on x-axis and price on y-axis
Questions:
do i need to make Gold's Date(YYYY) and Money Supply M2's Date(YYYY-MM) a date object?
if so how?
do i need to place all dates in one column and create a sub to help sort the Price with appropriate Date?
Does this make sense?
I have very little experience programming in VBA and was having a hard time finding info on using dates. I came across an Answer, given by the person who edited this (brettdj), that listed a few extremely helpful sights on VBA programming for excel. One of those had info on the DateSerial() function. I was then able to throw together some code to quickly fix my problem.
Sub CreateDates()
Dim dt As Date
Dim s As String
For Each c In Worksheets("Sheet1").Range("A7:A27080").Cells
s = Len(c.Value)
If s = 4 Then '(YYYY)
dt = DateSerial(s, 7, 1)
c.Value = dt
End If
If s = 7 Then '(YYYY-MM)
y = Left(s, 4)
m = Right(s, 2)
dt = DateSerial(y, m, 1)
c.Value = dt
End If
Next c
End Sub
I could probably spend some time and add some regular expressions and make a one-size fits most, but this will work as i want have to use it very often.

Resources