Generate "duplicate" row if between a date there is more than one month involved - excel

I'm asked to "automatize" some Excel tasks regarding medical licenses, what I mainly need right now is to identify if a license is longer than a month period, if so, duplicate the entire row data besides the date which needs to be adapted on the "next month" and also generate a period id that includes the year + month (e.g. 201801 for a license started in Jan/2018).
What I did first was checking and displaying if a license is longer than x period (did a loop that counts days and identify if it matches with the month above the cell), so if one started on Jan and ended in Feb it would show like this:
period id member start date end date jan feb
201801 john doe 09/01/2018 07/02/2018 23 7
=SUMAPRODUCTO(--(TEXTO(FILA(INDIRECTO($J9 & ":" & SI($K9="";HOY();$K9)));"MMM")=N$8))
The problem with the table above is that the file becomes humongous with the formula, so instead I'm thinking, for now, just the row duplication:
period id member start date end date
201801 john doe 09/01/2018 31/01/2018
201802 john doe 01/02/2018 07/02/2018
The thing is I can't figure how to compare months and print them the way I have to.
Sub CopyData()
Set hojatst = Sheets(Hoja5)
Dim d
Dim j
d = 1
j = 8
Do Until IsEmpty(hojatst.Range("D" & j))
If hojatst.Range("D" & j) < hojatst.Range("E" & j) Then
d = d + 1
End If
j = j + 1
End Sub

This is a 'sketch' of the code you will need to write. Stackoverflow is not a code request service and so you need to do your best to write it yourself. The community is happy to help you troubleshoot while you learn, but you should be using Google a lot. I wrote out the sketch to get you started because I remember how hard it was to learn the basics of coding. Feel free to ask clarifying questions.
First of all I cannot get Excel to recognize the DD/MM/YYYY format. It might be because mine is a US copy and that is not a standard time format here. You seem to be using a different version of Excel due to the formulas you listed. However be sure to double check that your code is correctly reading the DD/MM/YYYY format as you proceed.
Create a variable cl that is your current line. Create md which is the month difference.
If Month (Start Date) is less than Month(End Date) Then md = Difference of Months, insert that many lines below the current line. Range("E" & cl+md).Value = Range("E" & cl)which pastes your end date to the last slot.
Then for cl < cl+md fill in the periods by add +1 to the value if the last number is not 4 and +97 if it is.
Then fill in the blank cells for the dates with the Start of Month and End of Month dates.
Finally set cl = cl + md + 1 and loop to move on to the next 'original' line.

Related

Create a rolling date list in Excel

I want to create a rolling list of dates in Excel like so:
Day Date
Day 1 01-Jul-19
Day 1 02-Jul-19
Day 1 03-Jul-19
Day 1 04-Jul-19
Day 1 05-Jul-19
Day 1 06-Jul-19
Day 1 07-Jul-19
Day 2 02-Jul-19
Day 2 03-Jul-19
Day 2 04-Jul-19
Day 2 05-Jul-19
Day 2 06-Jul-19
Day 2 07-Jul-19
Day 2 08-Jul-19
Day 3 03-Jul-19
Day 3 04-Jul-19
Day 3 05-Jul-19
Day 3 06-Jul-19
Day 3 07-Jul-19
Day 3 08-Jul-19
Day 3 09-Jul-19
Day 4 04-Jul-19
. .
. .
. .
So essentially what's happening is that the 7-day range moves forward by one day each time, from a specific start date (in the example above, 01-07-19) until it reaches an end date. Is there an automated way of doing this?
#ashvin10 you can do this in vba, but you can also accomplish this with 2 formulas without using vba at all, here's how:
for illustration purposes we'll just assume you are starting with 07/01/2019 on the first row and your information will be displayed in columns A and B.
in A1 enter the string Day 1
in B1 enter your starting date, like 07/01/2019
in A2 enter this formula: ="Day " & IF(MOD(ROW(A2),7)<>0, MID(A2,5,(LEN(A2)-4)), MID(A2,5,(LEN(A2)-4))+1)
in B2 enter this formula: =IF(A2=A1,B1+1,OFFSET(B2,-7,0)+1)
highlight cells A2 and B2
click on the cross that becomes available on the bottom right hand corner of cell B2
drag down the formula till you hit the end date you desire
the cells are populated with the values you requested in the format you requested
If you absolutely have to have it done using vba please let me know and I can show you how to do it that way as well, but this way is much easier.
EDIT: #ashvin10 I'm so sorry, the original formula I instructed you to put into A2 only works for Day 1 through Day 9, if you go into days past 9 it won't display correctly. I've fixed the formula that should be pasted into A2 so now it will work no matter how many days you go down. I'm so sorry for the confusion.
Alternatively, this can also be done in Python.
import datetime
start_date = '01-07-2019'
end_date = '31-01-2020'
output_file_name = 'rolling dates'
output_file_extension = '.CSV'
delimiter = '\t'
with open((output_file_name + output_file_extension.lower()), 'w+') as file:
header = "Day" + delimiter + "Date" + '\n'
file.write(header)
start_date_object = datetime.datetime.strptime(start_date, '%d-%m-%Y').date()
end_date_object = datetime.datetime.strptime(end_date, '%d-%m-%Y').date()
number_of_days = abs((end_date_object - start_date_object).days)
next_day = start_date_object
for i in range(1, number_of_days + 2):
for j in range(7):
file.write(("Day {0}" + delimiter + next_day.strftime('%d-%m-%Y') + '\n').format(i))
next_day += datetime.timedelta(days=1)
start_date_object += datetime.timedelta(days=1)
next_day = start_date_object
After running the code above, I simply created a blank Excel file and then imported the data from the CSV file output by this code.
This is arguably more complicated than #gharbad-the-weak's answer but thought I'd include this anyway.

Excel formula to calculate elapsed minutes between 2 date timestamps only counting minutes during work hours

I have an excel sheet with about 50,000 records where I need to find the number of minutes between two date timestamps but I need to exclude any minutes that occurred during the times we are not working.
Our schedule is M-F 8:30am-5:30pm, Saturdays 8:30am-1:30pm
We don't work Sundays or holidays.
As an example
Cell B2: [7/3/2020 2:16:21 PM]
Cell C2: [7/6/2020 9:20:23 AM]
The manually calculated answer for this one should be about 244 minutes. Task started Friday afternoon, Saturday was a holiday, don't work Sundays, task completed at 9:20am on Monday.
Usually, I come here and start writing a question and by the time I've understood my own problem well enough to post a question I have figured it out on my own but not this time! Help!
Update:
#ForwardEd shared this...
=((I2-H2)
-MAX(0,(NETWORKDAYS.INTL(H2,I2,"0000011",$M$2:$M$12)-1+(WEEKDAY(I2,1)=7)))*TIME(15,0,0)
-MAX(0,(NETWORKDAYS.INTL(H2,I2,"1111101",$M$2:$M$12)-(WEEKDAY(I2,1)=7)))*TIME(19,0,0)
-NETWORKDAYS.INTL(H2,I2,"1111110",$M$2:$M$12)-(NETWORKDAYS.INTL(H2,I2,"0000000")
-NETWORKDAYS.INTL(H2,I2,"0000000",$M$2:$M$12)))*24*60
Where H:H is the Start Date Timestamp and I:I is the Response Date Timestamp and M2:M12 contains my holiday list.
It worked beautifully until I ran into an example like this:
H2 - 07/26/2020 7:48:45 PM
I2 - 07/27/2020 8:57:58 AM
The net result was -650.78333. It looks like anything that starts one one day and ends on the next is coming back as negative.
We want to measure the average response time in minutes for the applications that require manual underwriting. These start timestamps are times that loan applications were received online so they could come in any time of day. The stop times are timestamps that represent the system recorded response time. i.e. the timestamp where an underwriter first did something with the loan application. If a loan application was received at 7pm and was not auto-decisioned then a manual underwriter will need to do something with it the next day when we start working.
If that application came in at 7pm on Wed and is decisioned by an underwriter at 8:46am on Tuursday, we would want to document 16 minutes for that application - not 826 counting the hours between 7pm and 8:30am.
What you want to look at is NETWORKDAYS.INTL. Use this in conjunction with the custom settings to determine the number of Saturdays, Sundays and for the number of days in between your start and end time. You know you have X amount of time per day that is non working time, and Y amount per Saturday.
Then you formula in essence becomes
(End time - start time) - X * No. Weekdays - Y * No. Saturdays - No. Sundays - No. Holidays
Now there will be some tricks in there in order to count your days. but that is the gist of what it boils down to in a formula.
The formulas that are doing the brunt of the work are:
WORKDAY
NETWORKDAYS.INTL
TIME
I avoided the use of an if statement by using a boolean operation that excel will resolve from TRUE/FALSE to 1/0 when sent through a math operator. Side note: I read somewhere that this is also faster than an IF statement, but have no way of proving it and really does not matter on a small number of calculations.
WORKDAY
This formula will return the day of the week for a given date, and a set day of the week to be 1. It will be need in this solution to determine if the end date is a Saturday which has a value of 7 in default setup up as well when option 1 is picked. The format for the formula is:
WORKDAY(Excel Serial date, day 1 of the week)
For this solution
WEEKDAY(B3,1)
NETWORKDAYS.INTL
This formula will be used to count the number of specific days a start and an end date. It can exclude a custom weekend or count a custom week. If it is supplied with a list of dates that are holidays they can be excluded as well. The basic format of the formula is:
NETWORKDAYS.INTL(Start Date, End Date, Custom week choice or workweek pattern, range of holiday dates)
When entering the formula it will give you a list of predefined options for the weekend choices. It will not talk about the pattern.
The pattern is a string 7 digits long consisting of 1 or 0. 0's represents the days you want to count and 1's are days you want to ignore. An important part of the pattern is that the first entry is MONDAY. "1010111" would count only Tuesdays and Thursdays.
TIME
Excel stores date as an integer. 1 represents 1st of January 1900, 2 the 2nd of January 1900 and so on. Time is stored as a decimal or if you prefer the percentage/fraction of a day or 24 hour period. So rather than figuring out the math to determine what percentage of a day X number of hours is, it is simpler to let excel calculate it for us and make the number a little more understandable to someone who may be deciphering the formula later. The basic format of the formula is:
TIME(Hours, Minutes, Seconds)
So as stated earlier, 6 key components need to be determined:
X - Amount of non working time after a weekday
Y - Amount of non working time after a Saturday
Number of weekdays
Number of Saturdays
Number of Sundays
Number of holidays
1) Determine Weekday Non-Working Hours
Based on the supplied information that work day stops at 1730 and starts as 0830. There are a couple of ways of doing the math. Subtract the working hours from 24 hours or count the non work hours at the end of the day and add them to the non work hours at the start of the day.
24 - (17.5 - 8.5) = 15
or
(24 - 17.5) + (8.5 - 0) = 15
For this example 15 will be hard coded into the final formula
2) Determine Saturday Non-Working Hours
Similar to above. Note that we are ignoring Sunday as it is a designated non working day which we already know is 24 hours or 1 day. We are just interested in the time between end of shift Saturday and start of the next normal working Monday. So it really gets calculated the same with just with difference end of shift time.
24 - (13.5 - 8.5) = 19
or
(24- 13.5) - (8.5 - 0) = 19
For this example 19 will be hard coded into the final formula
3) Determine Number of Weekdays
Based on the description earlier of of NETWORKDAYS.INT and working with the assumption that holidays are stored in the range F2:F2, and using a pattern of "0000011" the number of weekdays the formula will be as follows:
=NETWORKDAYS.INTL(B2,B3,"0000011",F2)
For this example the formula is place in cell F6
4) Determine Number of Saturdays
Similar 3) adjust the pattern to only select Saturdays by using "1111101"
=NETWORKDAYS.INTL(B2,B3,"1111101",F2)
For this example the formula is place in cell F7
5) Determine Number of Sundays
Similar 4) adjust the pattern to only select Saturdays by using "1111110"
=NETWORKDAYS.INTL(B2,B3,"1111110",F2)
For this example the formula is place in cell F8
6) Determine Number of Holidays
To get the number of holidays there is not a direct way of doing it. Instead take the difference between all days counted without holidays being factored in and all days counted with holidays counted in.
=NETWORKDAYS.INTL(B2,B3,"0000000")-NETWORKDAYS.INTL(B2,B3,"0000000",$F$2:F2)
For this example the formula is place in cell F9
Now at this point I would love to say just substitute all of the above into the generic formula, but there are a couple of special cases that need to be taken care of. You may have also noted I have not used the WEEKDAY formula yet.
So in order to count the number of days to which X is going to apply, its really the number of days minus 1. The minus 1 is because you want to cont the intervals between days, not the number of days themselves. This gets a little bit more trickier when the end day is a Saturday because there is still an interval there but Saturday is not counted as a weekday. So the True count for number of weekday intervals is:
=MAX(0,(F6-1+(WEEKDAY(B3,1)=7)))
I originally had the MAX(0, calc) in there to prevent the posibility of the day count being negative. After arriving at this final format it may not be needed and you might get away with the following but its untested:
=F6-1+(WEEKDAY(B3,1)=7)
This same concept needs to be applied to your Saturday count. If you job ends on Saturday you do not need to subtract the non working hours after the last Saturday. You formula will look like:
=MAX(0,(F7-(WEEKDAY(B3,1)=7)))
and again further testing is required to make sure MAX can be removed, but if it can then the formula would look like:
=F7-(WEEKDAY(B3,1)=7)
So now with the understanding how dates and times are stored, determine the time difference between start end end time and subtract all the non working hours.
=(B3-B2)-MAX(0,(F6-1+(WEEKDAY(B3,1)=7)))*TIME(15,0,0)-MAX(0,(F7-(WEEKDAY(B3,1)=7)))*TIME(19,0,0)-F8-F9
Now you will not want to use helper cells, so you can take each of the individual formula from F6 to F9 and wind up with:
=(B3-B2)-MAX(0,(NETWORKDAYS.INTL(B2,B3,"0000011",F2)-1+(WEEKDAY(B3,1)=7)))*TIME(15,0,0)-MAX(0,(NETWORKDAYS.INTL(B2,B3,"1111101",F2)-(WEEKDAY(B3,1)=7)))*TIME(19,0,0)-NETWORKDAYS.INTL(B2,B3,"1111110",F2)-(NETWORKDAYS.INTL(B2,B3,"0000000")-NETWORKDAYS.INTL(B2,B3,"0000000",$F$2:F2))
The formula looks unruly, but is easier to understand when broken down into its parts.
Now the last step is to get the answer to display in minutes. There are two choices.
You can leave it as it is in an excel serial date format and change the formatting of to a custom format of [m]. The [ ] will force it into minutes and prevent spill over to hours. It will also round to the nearest minute.
You can convert the results to minutes by multiplying by 24*60 and the value will be in minutes and decimal of minutes.
Note that:
A11 has Time formatting applied
A12 has General formatting applied
A14 has custom formatting of [m] applied
It should be something like this:
Create a calendar table with the workinghours for each days in the year you have data in
Date | StartTime | End time
1/1/2020 1/1/2020 8:30:00 PM 1/1/2020 5:30:00 PM
...
7/3/2020 7/3/2020 8:30:00 PM 7/6/2020 5:30:00 PM
...
12/31/2020
Then paste this code in a module
Function CalcDays(dStart As Date, dEnd As Date, daysCalendar As Range)
Dim Cell As Range
Dim MinDaysCalendar As Date, MaxDaysCalendar As Date
Dim aWSF As WorksheetFunction
Set aWSF = Application.WorksheetFunction
'check the minimum en the maximum date in the calendar
With aWSF
MinDaysCalendar = .Min(daysCalendar)
MaxDaysCalendar = .Max(daysCalendar)
End With
'if the date you check is not in the calendar, exit the function
If dStart < MinDaysCalendar Or dStart > MaxDaysCalendar Then
MsgBox "Date not in calendar"
Exit Function
End If
If dEnd < MinDaysCalendar Or dEnd > MaxDaysCalendar Then
MsgBox "date not in calendar"
Exit Function
End If
'sum the time of all the dates between the start and the end
'pick min and max in order to start and stop at the right time per day
Dim tempTime As Integer
With daysCalendar
For i = 1 To .Rows.Count
If .Cells(i, 2).Value >= CLng(dStart) And .Cells(i, 3).Value <= CLng(dEnd) Then
daytime = aWSF.Max(.Cells(i, 2).Value, dStart) - aWSF.Min(.Cells(i, 3).Value, dEnd)
End If
tempTime = tempTime + daytime
Next i
End With
'return the total time
CalcDays = tempTime
End Function
You can call the function by typing =calcdays in a cell and then give the startDay, endDay and calendar column as parameters.
There might still be some flaws in this code but I think we can manage those.

Creating flags for calculating rolling averages in excel

I have a data sheet which looks like:
year month
2017 2017-01
2017 2017-02
2017 2017-03
......
2018 2018-04
2018 2018-05
Note the column month contains text string. I need to create a new column flag in excel which filters which months are to be used in calculating rolling 12M averages for current month and which months are to be used for calculating rolling 12M averages for previous year.
For example today's date is 5/24/2018, so month 2018-05 will be marked as "current". months between 2018-04 to 2017-05 will be marked as "both". month 2017-04 will be marked as "previous". Rest all months will be marked as NA. My final data should look like this:
year month flag
2017 2017-01 NA
2017 2017-02 NA
2017 2017-03 NA
2017 2017-04 Previous
......
2018 2018-04 Both
2018 2018-05 Current
I am having trouble implementing this logic in excel as the column month is a text string and simply using IF condition doesn't works for me. Any leads on this is appreciated.
Edit:
I tried converting the months to a number by using =DATEVALUE(B2 & "-01").
I stored the number for current month in a variable curr.
Now I am using the following formula =IF(B22=curr,"Current", IF(B2=curr-395,"Previous","Both")).
This creates the flag column which I require although there's still an issue based on whether the month has 30 or 31 days. Any solutions for this please?
One way to do it is to use DATDIF.
=DATEVALUE(B2 & "-01") will give you the first of each month in column B.
To return the month number use =DATEDIF(C2,TODAY(),"m") where column C holds the DATEVALUE formula. This will return 0 for this month, 1 for last month... 13 for April 2017.
Now check to see if the count of months = 0 then it's current, if it's greater than 11 it's NA, otherwise it's both. =IF(D2=0,"Current",IF(D2>11,"NA","Both"))
... Edit ....
That's wrong - forgot the "Previous" and "Both" isn't 12 months ....
=IF(D2=0,"Current",IF(D2>13,"NA",IF(D2=13,"Previous","Both")))
As considering your column month format = "YYYY-MM" this code may be helpful
this is Excel function, to use it you need to save this function in the module and use it. `
Function MyDateCal(cell As Range) As String
Dim YearCurrent, YearCell, monthCurrent, MonthCell As Integer
Dim cellVal As String, DiffMonth As Integer[![enter image description here][1]][1]
cellVal = cell.Value
MyDateCal = "NA"
'cellVal = Cells(1, 1).Value
YearCurrent = Year(Now())
monthCurrent = Month(Now())
YearCell = CInt(Left(cellVal, 4))
MonthCell = CInt(Right(cellVal, 2))
DiffMonth = 12 * (YearCurrent - YearCell) + (monthCurrent - MonthCell)
If DiffMonth = 0 Then
MyDateCal = "Current"
ElseIf DiffMonth > 0 And DiffMonth <= 12 Then
MyDateCal = "Both"
ElseIf DiffMonth = 13 Then
MyDateCal = "Previous"
End If
End Function
`

How to calculate

My question is almost identical to this one: Calculating number of days between two dates dependent on month
But I have data that is a rolling 12-months and I need to have additional coding added to the formula:
=IFERROR(IF(AND(MONTH($D2)=F$1,MONTH($E2)=F$1),$E2-$D2,
IF(MONTH($D2)=F$1,1+EOMONTH($D2,0)-$D2,
IF(MONTH($E2)=F$1,$E2-DATE(YEAR($E2),F$1,1),
IF(AND(MONTH($D2)
F$1,MONTH($E2)>F$1),DAYSINMONTH(DATE(YEAR($D2),F$1,1)),0)))),0)
to allow for a reservation that is for February 2018, for example, to show in its own column, and not be included in February 2017.
For example, my data might have:
John Smith, arr 2/21/17 dep 2/18/17
& Matt Jones, arr 2/21/18 dep 2/18/18
and currently the way I have my document built, it would show 2 for column "2", aka February. I need it to show 1 for Feb-17 and 1 for Feb-18.
Can you help please and thank you!
It took me a while to work out what you're looking for but here's what I think you need.
I started from scratch on the formula so I take a different approach to the one in your question.
=IF(AND(A3<E3,D3<EDATE(A3,1)),IF(AND(A3>D3,E3>(EDATE(A3,1))),(E3-D3)-((E3-(EDATE(A3,1)))+(A3-D3)),IF(E3>(EDATE(A3,1)),(E3-D3)-(E3-(EDATE(A3,1))),IF(A3>D3,(E3-D3)-(A3-D3),E3-D3))),0)
The month that you want to check should be entered as a date, the 1st of the month.
How it works
It's easier to show by example
month to be checked date 01/02/2017
arr date: 27/02/2017
dep date: 02/03/2017
get the end of the month period to be checked date + 1 month EDATE(01/02/2017,1) = 01/03/2017
is the dep date later than the end of the period to be checked? YES
02/03/2017 - 01/03/2017 = 1 (1st value)
get days between arr and dep date 02/03/2017 - 27/02/2017 = 2 (2nd value)
2nd value - 1st value = 1
the example calculation only describes when the arr and dep dates overlap the end of the period to be checked but the formula check for an overlap at the start and also when the entire period to be checked is overlapped and arr date in Jan and dep date in Mar.
The first IF(AND(A3
I hope that explanation helps you to pick the formula apart.

Week number to Month number

I have a date with this format : 14w01 (year : 2014 week number : 1)
I want to convert this date in month like this : 14m01
Is there a function which converts a week number in a month number ?
Maybe something like this (in vba, not in formula) :
Format(weekNumber, "mm")
Thank you
It depends on how the weeks are defined. One way is to say that the first day of week#1 of a year is 1 January of that year. For this definition, a typical UDF is:
Public Function MonthFromDt(s As String) As Integer
Dim yr As Integer, wk As Integer, d As Date
ary = Split(s, "w")
yr = CInt(ary(0)) + 2000
wk = ary(1)
MonthFromDt = Month(DateSerial(yr, 1, 1) + 7 * (wk - 1))
End Function
There are other definitions of week number.
The DateFormat function is quiet comfortable, however the DateValue function, which parses a date, won't probably support your week format.
I suggest a trick with DateAdd, as DateAdd can handle weeks.
First split your date in year and week number:
Dim parts
parts = Split("2014w33", "w")
Dim year
Dim week
year = CInt(parts(0))
week = CInt(parts(1))
Then, add both to a "zero-date" to add up to the final date. Note that if you give "0" as year for DateAdd, VBA compiler interprets 2000.
dim DateResult
DateResult = dateAdd("yyyy", (year - 2000), DateValue("Jan 1, 0"))
Debug.Print dateResult
DateResult = dateAdd("ww", week, dateResult)
Debug.Print dateResult
Then show the result reformatted:
Debug.Print Format(DateResult, "yyyy\mm")
This prints on my side:
01.01.2014
20.08.2014
2014m08
August 2014, there is week 33 if I look up in the calendar. Seems correct.
I found a way to do it without VBA (and only using Formulas). This assumes A1 contains the "14w01" format
=LEFT(A1,2)&"m"&TEXT(MONTH(DATE(20&LEFT(A1,2),1,1)+(RIGHT(A1,2)*7)),"00")
Heres a breakdown of what the code does..
LEFT(A1,2) returns "14" (year)
MONTH(DATE(20&LEFT(A1,2),1,1)+(RIGHT(A1,2)*7)) converts the week # to the month # and it takes in the year 20&LEFT(A1,2) as well as week # RIGHT(A1,2)
TEXT(...,"00") pads the month # with a 0 if necessary (i.e. 3 becomes 03)
Then we just combine everything together to get "14m01"

Resources