Inserting a column conditionally based on date using VBA - excel

I'm trying to find a way to automatically insert a column based on a date. Here's some context:
The top row of my spreadsheet (Row 1) contains dates in the format yyyy/mm/dd
The dates aren't day-by-day; they are weekly (i.e. one cell may say 2015/09/21 the next will say 2015/09/28 and the next will say 2015/10/05) so this can change from year to year
I need to find a way to automatically insert ONE column at the end of each quarter and TWO columns at the end of each half (i.e. ONE column between March and April, TWO between June and July, ONE between September and October, and TWO between December and January)
So far, this is what I am using to traverse the top row and see if the date is before October but after September. The dates start from cell I1. Although the code executes without any error, it does not actually do anything. Any help you all can offer will be appreciated.
With Sheets("Sheet1")
Range("I1").Select
Do Until IsEmpty(ActiveCell)
If ActiveCell.Value < DateValue("2015/10/1") And ActiveCell.Offset(0, 1).Value > DateValue("2015/9/28") Then
Range(ActiveCell).EntireColumn.Insert
End If
ActiveCell.Offset(0, 1).Select
Loop
End With

I think you're off to a good start with your method. You should be able to just check if the day of the month is less than or equal to 7. That should indicate the first week in a month. If that month is 4 or 10, insert a column. If it's 1 or 7, insert two.
Dim r As Range
Set r = Range("I1")
Do Until IsEmpty(r)
If Day(r) <= 7 Then
Select Case Month(r)
Case 4, 10
r.EntireColumn.Insert
Case 1, 7
r.Resize(1, 2).EntireColumn.Insert
End Select
End If
Set r = r.Offset(0, 1)
Loop

Going strictly on a change in months bewteen two cell in the header row may be the easiest logic.
Sub insert_quarter_halves()
Dim c As Long
With Worksheets("Sheet8") 'set this worksheet reference properly!
For c = .Cells(1, Columns.Count).End(xlToLeft).Column To 2 Step -1
If (Month(.Cells(1, c - 1).Value2) = 3 And Month(.Cells(1, c).Value2) = 4) Or _
(Month(.Cells(1, c - 1).Value2) = 9 And Month(.Cells(1, c).Value2) = 10) Then
.Cells(1, c).EntireColumn.Insert
ElseIf (Month(.Cells(1, c - 1).Value2) = 6 And Month(.Cells(1, c).Value2) = 7) Or _
(Month(.Cells(1, c - 1).Value2) = 12 And Month(.Cells(1, c).Value2) = 1) Then
.Cells(1, c).Resize(1, 2).EntireColumn.Insert
End If
Next c
End With
End Sub
When inserting columns, always travel from right to left or you risk skipping an entry that was pushed forward.,

Related

Why does my IsDate() If statement ignore "31/12/1019"

I am attempting to remove all dates before a certain time period, as well as anything that is not a date from my data set. I have roughly 4000 entries in column A dating back the last 10 years, with some typo's mixed in. There are no blanks spots between the data.
I have cobbled together the below code, which almost works. However there is one entry 31/12/1019 which is not being picked up as an old date, or a typo.
Sub deleterows()
lastRow = Sheets("ConData").Cells(Rows.Count, 1).End(xlUp).Row
bankingDate = DateSerial(Year(Date), Month(Date), 0)
For i = lastRow To 1 Step -1
If IsDate(Cells(i, 1)) = False Or _
Cells(i, 1).Value <= bankingDate Then Rows(i).EntireRow.Delete
Next
End Sub
Any help would be appreciated.
Let's break it down, this is a wonderful inconsistency between Excel and VBA:
According to THIS article:
In Windows, the range of valid dates is January 1, 100 A.D., through December 31, 9999 A.D.; the ranges vary among operating systems.
so IsDate will return TRUE for 31/12/1019
But
Since Excel actually stores "dates" as a double with 1900-01-01 being 1.00 the date would be stored as a string in the worksheet and the Cells(i, 1).Value <= bankingDate would return False because a string is larger than a number.
But as #BigBen stated:
Cast to a date first before comparing to bankingDate.
If Not IsDate(Cells(i, 1).Value) Then
Rows(i).EntireRow.Delete
ElseIf CDate(Cells(i, 1).Value) <= bankingDate
Rows(i).EntireRow.Delete
End If
IsDate will give true but you can check then for
isNumeric(Cells(i, 1).value2
If not IsDate(Cells(i, 1)) or not isNumeric(Cells(i, 1).value2) or ...
Value2 gives a double for Date Cells which are later then 0.1.1900
And I believe your banking date will always be later 😀

Sum a cell based on unique value and unique date using vba

I have a data dump in Excel that consists of monthly crew member hours worked data. Currently, there are multiple rows of data for the same date.
I want to run a macro that keeps unique names and unique dates but delete rows that have duplicated dates (keep one row for each crew member per date). In the "hours" column, I wish to combine multiple shifts from the same day into one.
Here is my code so far and result.
Sub mcrCombineAndScrubDups()
For Each a In Range("A1", Cells(Rows.Count, "A").End(xlUp))
For r = 1 To Cells(Rows.Count, "A").End(xlUp).Row - a.Row
If a = a.Offset(r, 0) And a.Offset(0, 1) = a.Offset(r, 1) And a.Offset(0, 2) = a.Offset(r, 2) Then
a.Offset(0, 6) = a.Offset(0, 6) + a.Offset(r, 6)
a.Offset(r, 0).EntireRow.Delete
r = r - 1
End If
Next r
Next a
End Sub
With the current code, it combines all the hours worked for the entire month into one field rather than a row for each crew member for each date. I know a pivot table can be run but my boss wants more automatic. Thanks!

VBA Excel Code to delete entire row if date equals

I need some help with some VBA Excel code to format a spreadsheet please.
I have to run a report that give me an excel spreadsheet which has an invoice date in column P. I need to delete the entire row if the invoice date in the cell in column P is less than or equal to 60 days from todays date, and also delete any row that has an invoice date in column P of 4 years or more from todays date.
I normally have to do this manually each time I run the report so I would like to automate the process with some VBA code. Can anyone help me with this please.
Dim x As Long
For x = [a1].SpecialCells(xlCellTypeLastCell).row To 1 Step -1
Debug.Print Cells(x, "P").Value
If CDate(Cells(x, "P")) > Date - 60 Then
Cells(x, "P").EntireRow.Delete
Else
Exit Sub
End If
Next x
I got the above code to work
Dim LastRow as Integer
Dim row as Integer
LastRow = ActiveSheet.UsedRange.Rows.Count
For row = 2 To LastRow
If Cells(row, 16).Value < Date - 59 OR Cells(row, 16).Value > Year(Cells(row, 16)) + 4 Then
Rows(row).Select
Application.CutCopyMode = False
Selection.Delete Shift:=xlUp
End If
Next row
I had this more or less lying around, and tweaked it a bit. Let me know if this works for you.

Dates for each month in separate sheets

I am trying to create dates for each month individually. I have done my bit of work but looking for optimised code.
Steps
Create a Spreadsheet and change the name from "Sheet1" to "Year"
Column A ColumnB
2014 January
February
March
April
May
June
July
August
September
October
November
December
Now copy the below to VBA module
Sub GenerateDate()
Dim amonth As String
Dim col, cola As String
Dim ayear As Integer
For x = 1 To 12
Worksheets("Year").Select
Worksheets("Year").Activate
'//this will add every month worksheet
Worksheets.Add(After:=Worksheets(Worksheets.Count)).Name = Cells(x, 2)
Worksheets("Year").Activate
'//get month name to string called amonth//
amonth = Cells(x, 2).Value
'//get year to variable type int called ayear//
ayear = Cells(1, 1).Value
'//activate month sheet
Worksheets(amonth).Activate
'//insert date 1st day of each month in cell A1
Cells(1, 1).Value = DateSerial(ayear, x, 1)
'//select 'A1' cell values
Cells(1, 1).Select
'// pass A1 value to a my_date
my_date = Cells(1, 1).Value
'//change the format of the date in A1 cell
Selection.NumberFormat = "d/mm/yyyy;#"
'//count number of days in month for the date in A1
numof_days = Day(DateSerial(Year(my_date), Month(my_date) + 1, 1) - 1)
'// col a and cola are two strings holds sting values "A" and "A1" respectively
col = "A"
cola = "A1"
'//Final value is range to be used to fill the dates
Final = col & numof_days
'//fill dates from A1 to Final cell values
With Range("A1")
.AutoFill Destination:=Range(cola, Final), Type:=xlFillDays
End With
'//auto fit the entire "A" column
Columns("A:A").EntireColumn.AutoFit
Next x
End Sub
My output
Creates new sheet for each month and generates dates for that month only.
As a first step you may find it more effective to add application.screenupdating = false at the beginning of your code and then application.screenupdating = true at the end. This will speed up your code. You may also consider doing the same for application.displayalerts.

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