Excel VBA Deleting Rows of Dates - vba

I have a column of dates in Column D in the mm-dd-yyyy format. Below is the code that I am trying to use to delete the entire row of data if the Active Cell in Column D is either Blank, Today's Date, or older than 8 days (i.e. today is 3/13/14, so it would erase blank entries, today's date, and anything older than 3/5/14).
Dim lastrow As Long
lastrow = Range("A65536").End(xlUp).Row
Range("D" & lastrow).Select
Do
If (ActiveCell = "" Or ActiveCell = Format(Now, "mm/dd/yyyy") Or ActiveCell < Format(Now -8, "mm/dd/yyyy")) _
Then ActiveCell.EntireRow.Delete
ActiveCell.Offset(-1, 0).Select
Loop Until ActiveCell = "Completed Date)"
If I use the "<" symbol, it erases everything basically, and if I use the ">" symbol, then it doesn't erase the rows with dates in February, etc. Can anyone suggest a method that will work, or why mine isn't?

I'm just thinking off the top of my head, but the moment you use the Format keyword in Excel, it probably converts the date to a text value, so you can't perform comparison operations on it...
Try this instead:
If (ActiveCell = "" Or (ActiveCell = Format(Now, "mm/dd/yyyy")) Or (Cdate(ActiveCell) < (Now -8))) _
In effect, rather than changing NOW()-8 to text, converting Activecell to a date you can use for comparison's sake.
Again, I didn't do this with VBA, but I'm guessing it should do the trick.
Good luck!!

Try use DateDiff:
If not isempty(activecell)
If DateDiff("d", Now(), ActiveCell.Value) < -8 then
'do your stuff
endif
endif

Paste the following code into a module:
Sub ScrubData()
Dim i As Long
Dim numRowsWithVal As Long
Dim myActiveCell As Range
Dim todaysDate As Date
Dim cutoffDate As Date
'Use a custom function to delete all blank rows in column specified
Call DeleteAllBlankRowsInColumn("D")
'Use VBA's Date() function to get current date (i.e. 3/13/14)
todaysDate = Date
'Set the cutoff date to anything older than 8 days
cutoffDate = todaysDate - 8
'***** Loop through all rows and clear values if rows are equal to today's date or older than 8 days ******
'Count the number of rows with values (subtract one because sheet has headers)
numRowsWithVal = (Range("D" & Rows.Count).End(xlUp).Row) - 1
'Start at Range("D2")
Set myActiveCell = ActiveSheet.Range("D2")
For i = 0 To numRowsWithVal - 1
Select Case True
'If value of cell is today's date OR older than 8 days clear the values
Case myActiveCell.Offset(i, 0).Value = todaysDate, myActiveCell.Offset(i, 0).Value <= cutoffDate
myActiveCell.Offset(i, 0).ClearContents
'Value is valid, do nothing
Case Else
End Select
Next
'***********************************************************************************************************
'Now that values are cleared, delete all blank rows again
Call DeleteAllBlankRowsInColumn("D")
End Sub
Public Function DeleteAllBlankRowsInColumn(ByVal columnLetter As String)
'Delete all blank rows in column specified (suppress errors just in case there aren't any blank cells)
On Error Resume Next
Columns(columnLetter).SpecialCells(xlCellTypeBlanks).EntireRow.Delete
'Set error handling back to normal
On Error GoTo 0
End Function
Before:
After:

Related

Date Comparison Issue VBA

I am trying to compare Dates in a vba script. I believe the main issue is my formatting however I am not sure how to solve it.
Sub Rem9()
Dim i As Long
Dim lr As Long
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
wsName = ws.Name
lr = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
FirstDateRead = CDate("1, 1,2018") 'Initialize the first Day of the year as the last day
For i = 1 To lr
Debug.Print FirstDateRead
Debug.Print ws.Cells(i, 1).Value
If FirstDateRead > ws.Cells(i, 1).Value Then
ws.Cells(i, 3).Value = 121325
End If
Next i
End Sub
According to my output the First Date Read is never greater than the values I am pulling, Which it is for all cases. I have included here an example of the debug.print from the script I am running to show the date formats. Additionally I want to confirm the values I am drawing from are indeed datevaluse as when I run them through the IsDate() Function it returns True.
One other issue if that my date format for the value I call is swapping the year and day. Does anyone know how to solve that. When I use the format function it returns the date as.
Assuming the cells containing the dates are in text format, try wrapping the comparison value in a cDate:
If FirstDateRead > Cdate(ws.Cells(i, 1).Value) Then
ws.Cells(i, 3).Value = 121325
End If
Try using the DateDiff function instead:
Sub dateDifference()
Dim d1 As Date, d2 As Date
d1 = CDate("1, 2,2018")
d2 = Range("A1").Value ' insert a date in A1 to test
Debug.Print DateDiff("d", d1, d2) ' first parameter set to days
End Sub
Edit #1
Use Format to compare apples with apples, so to speak:
d2 = Format(Range("A1").Value, "dd/mm/yyyy")

Create a list of dates and avoid variable not set (VBA error 91)

I have financial data about certain stocks in five sheets and am trying to create a function which will calculate the exponential moving average of a given range.
[columns(1) = date ; columns(2) = closing price]
The arguments of this function are the number of days taken into account to calculate the EMA, and an integer kol to calculate several EMAs on several columns, side by side (no use for now). Here is my code so far:
Public Function MME(Lmme As Double, kol As Long)
Dim Cmme As Range
Dim Todate, rcell As Range
Dim alpha, period, Udate, i, j, k As Long
Dim Ustock As String
Dim wsDest As Worksheet
Udate = ThisWorkbook.Worksheets("UserForm").Range("B2").Value
period = ThisWorkbook.Worksheets("UserForm").Range("B3").Value
Ustock = ThisWorkbook.Worksheets("UserForm").Range("B4").Value
' MsgBox (Udate)
Set wsDest = ThisWorkbook.Sheets(Ustock)
wsDest.Activate
With wsDest.Range("A2:A392")
Set Todate = Cells.Find(What:=Udate, _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Todate Is Nothing Then
MsgBox ("todate wasn't found")
Else
End If
End With
i = Todate.Row
j = i + period
k = i - Lmme
Set Cmme = Range(Cells(i, 9 + kol), Cells(j, 9 + kol))
alpha = (2 / (Lmme + 1))
With Cmme
For Each rcell In Cmme
If rcell.Row <> i Then
rcell.Formula = "=B" & rcell.Row & "*" & alpha & "+I" & rcell.Row - 1 & "*" & 1 - alpha & ""\
Else: rcell.Formula = "=AVERAGE(B" & k & ":B" & i & " ) "
End If
Next rcell
End With
End Function
I created a list on a separate sheet which allows the user to select a date in 2008, and another which lets him select a Stock. So I did set new variables in order to do the trick but it doesn't work.
Usaction, USdate and Uperiod are the name ranges in which the values selected by the user are stored. But I got "error 91 or object required" on the set = period.
I really want the EMA to be calculated only for a specific period, starting the date selected.
EDIT: I updated the code with the latest version i have. I still have an error 91 on endate
EDIT2: Code updated. I don't understand why the date is not found. On the sheet UserForm the date selected by the user is in "B2" (USdate). It is in format general, but with the CDate in the find function it should be considered a date right? I tried with the date format, it didn't change anything ...
EDIT3: Thanks to Branislav I managed to make the find works by switching every date to General format. Since the Find is working, anyway to make it work using date format? So that the user can see actual date, instead of the integer associated.
Another question: How can i bypass the Cells.Formula to operate directly within vba, and makes it so formula shows in the formula bar in excel once the code ran, except the result of SMAs and EMAs operation within the range?
ToDate is already a range
Set Endate = Todate.Row + period
Also, before you get to that point, you set ToDate by using .Find(). Since it's entirely possible that someone would enter an invalid date or a date that you don't have data for, I'd strongly recommend adding:
if ToDate is Nothing then
'do some date not found stuff here
else
'do your date found stuff here
End If
You may also want to consider changing LookIn:=xlFormulas to LookIn:=xlValues because I believe you're looking for a cell value, not a cell formula.

Select sheet defined as date

I do have a workbook where multiple sheets are named based on date (in format MMDDD). This macro should loop trough all date sheet (like 01OCT, 02OCT, .... 30OCT) select range and copy it into new sheet.
Selecting cells, copying them and so is not really problem, and that is working perfectly. However I do have a problem defining sheet name. I would like user in the beginning define month and number of days in month and month using InputBox.
So if user select month = "FEB" and DaysMonth = 28, I would like macro to loop trough sheets named 01FEB, 02FEB, 03FEB, .... 28FEB.
Sub Merge_whole_month()
Application.ScreenUpdating = False
Dim month As String
month = InputBox(Prompt:="Please enter month in format MMM", _
Title:="Month")
Dim DaysMonth As Long
DaysMonth = InputBox(Prompt:="Please enter number of days in month", _
Title:="Days")
'create new sheet for results
Sheets.Add.Name = "Merge"
'loop
For i = 1 To DaysMonth
i = Format(i, "##")
Sheets(i & month).Activate 'here is the problem
'select cell G3, then all "non-empty" cells to the right and down and COPY
Range(Range("G3", Range("G3").End(xlToRight)), Range("G3", Range("G3").End(xlToRight)).End(xlDown)).Select
Selection.Copy
Sheets("Merge").Activate 'activate sheet where cells needs to be copied
'find last cell in 2nd row in sheet
lastCol = Cells(2, Columns.Count).End(xlToLeft).Column
lastCol = lastCol + 1
Cells(1, lastCol) = i & month 'log date and month in cell above
Cells(2, lastCol).Select
ActiveSheet.Paste 'Paste
Next i
Application.ScreenUpdating = True
End Sub
Many thanks in advance for any help!
The problem lies in the facto that i = Format(i, "##") does not make i less than 10 appear as 01 etc. To fix this i would do this:
Dim sDate As String
sDate = CStr(i)
If Len(sDate) < 2 Then
sDate = "0" & sDate
End If
Place that code within your for-loop before Sheets(i & month).Activate and remove i = Format(i, "##").
EDIT:
It also seems that for me using Format(i, "0#") gives the string you were looking for. However you will still need to assign this to a String variable or change Sheets(i & month).Activate to Sheets(Format(i, "0#") & month).Activate.
Here is the documentation on the Format() function. I suggest reading it.

Select first Empty Cell from a selected cell (or range), then add a Value (date), then offset and inputext

I have been looking around to find good examples, but can't find what I need.
Here is the context: The code is for a sales tracker worksheet with around 50 vendors (each of them can add value and most of them didn't know anything about Excel).
I want to select the first empty cell (where the first they can enter a value is B5, not higher, because the top of the sheet includes some instructions). In fact, from this cell (Date value is in Column B, and begin in Row 5) the second date value is in B6
Add the Date (date or now) as activecell.value
Then 2 cells to the right activecell.offset(0,2)
And insert the value of the textbox (their ID).
For now, I can add the date and the Textbox ID.
Here what I have so far:
Sub CommandButton1_click()
Dim Input_ID As String, Date_in As String
Date_in = Format(Now, "DD-MMM")
ActiveCell.Value = Date_in
Input_ID = InputBox("SVP entré votre ID ", "Data Entry Form")
ActiveCell.Offset(0, 2) = Input_ID
End Sub
But is it possible to make that command/button only available for column "B?" Because I don't what them add a date and their ID to another Column.
PS: I More or less begin in VBA, I learn from a bit of everywhere, So if you could add some explanation in your code, i appreciate it. Thanks
Edit1: Post from comment
Sub Date_insert_click()
Dim Input_ID As String, Date_in As String
Dim ws As Worksheet
Set ws = ActiveSheet 'change to your actual worksheet
'Dim Date_in As Date
Date_in = Format(Now, "DD-MMM")
With ws.Range("B" & ws.Rows.Count).End(xlUp)
If .Row >= 4 Then .Offset(1, 0).Value = Date_in Else Exit Sub
Input_ID = InputBox("SVP entré votre ID ", "Data Entry Form")
If Input_ID <> "" Then .Offset(1, 1).Value = Input_ID Else .Offset(1, 0).Value = ""
End With
End Sub
But I found a weakness. If I select a cell anywhere down like K378,
I Still can add the value (date_In or value of the inputbox) but can't see it because the cell isn't active.
Try this as commented:
Sub CommandButton1_click()
Dim Input_ID As String, Date_in As String
Dim ws As Worksheet
Set ws = Thisworkbook.Sheets("Sheet1") 'change to your actual worksheet
Date_in = Format(Now, "DD-MMM")
With ws.Range("B" & ws.Rows.Count).End(xlUp)
If .Row >= 4 Then .Offset(1, 0).Value = Date_in Else Exit Sub
Input_ID = InputBox("SVP entré votre ID ", "Data Entry Form")
If Input_ID <> "" Then .Offset(1, 2).Value = Input_ID Else .Offset(1, 0).Value = ""
End With
End Sub
Edit1: Explanation as requested
Q: Why pass Worksheet object to a variable?
A: HERE is some explantion for this question. Also it makes your code a lot more readable and easy to debug.
Explaining the code:
'This line simply finds the last cell in Column B
With ws.Range("B" & ws.Rows.Count).End(xlUp)
'other code here
End With
Why use With? I used with because all the coding focuses on Column B and other data input is also reference to it. You can also see explanation on the advantages of using it in the link I provided above.
With ws.Range("B" & ws.Rows.Count).End(xlUp)
'Since we used With, you can directly access the Range properties
'The following line uses the Row and Offset property
'Row returns the row number of the range you're workning on
'Offset literally offets the range you are currently working on
If .Row >= 4 Then .Offset(1, 0).Value = Date_in Else Exit Sub
'This next line is already known to you, no need to explain
Input_ID = InputBox("SVP entré votre ID ", "Data Entry Form")
'Next line checks if Input_ID is supplied
'If yes, we use offset to get to the 2nd column from the current range
'If no, we delete the Date_In value
If Input_ID <> "" Then .Offset(1, 2).Value = Input_ID Else .Offset(1, 0).Value = ""
End With
I hope I explained it enough.
But if ever you still need more explanation, just comment it out.
If you encounter dificulties somewhere just post another question.

How to split dates with VB in Excel

Facing such a problem when hadling with excels again...
I have an excel table with such cloumns
People Date
-------------------------
A 01/01/2013 - 05/01/2013
B 03/05/2013
C 08/06/2013
What I want to produce (For example A)
People Individual Date
-------------------------
A 01/01/2013
A 02/01/2013
A 03/01/2013
A 04/01/2013
A 05/01/2013
The year will be constant at 2013 and month are more or less kept constant as well.
Can someone give idea on how to achieve this?
Sub ExpandDates()
Dim rCell As Range
Dim i As Long
Dim vaDates As Variant
Dim rNext As Range
'Loop through the cells that contain dates or date ranges
For Each rCell In Sheet1.Range("B2:B4").Cells
'If there's a space, hyphen, space in the cell, it's a date range
If InStr(1, rCell.Value, " - ") > 0 Then
'Split the cell contents on space, hyphen, space
vaDates = Split(rCell.Value, " - ")
'Loop through the days of the range of dates
For i = CDate(vaDates(0)) To CDate(vaDates(1))
'Find the next blank cell in column E to record the results
Set rNext = Sheet1.Cells(Sheet1.Rows.Count, 5).End(xlUp).Offset(1, 0)
'Write column A to column E
rNext.Value = rCell.Offset(0, -1).Value
'Create a new date in column B using the month that the loop is currently processing
rNext.Offset(0, 1).Value = CDate(i)
Next i
'If no hyphen, it's just a date, so create one line in column E
Else
Set rNext = Sheet1.Cells(Sheet1.Rows.Count, 5).End(xlUp).Offset(1, 0)
rNext.Value = rCell.Offset(0, -1).Value
rNext.Offset(0, 1).Value = rCell.Value
End If
Next rCell
End Sub
Theory: Check the length of the cell. If the cell is longer than 10 characters, use the SPLIT function to get the 2 dates. Set the months equal to a variable, and do a loop based on those months to calculate the dates between them. You would probably store those dates in an array. Then write the array to the spreadsheet and move to the next cell to start the process over.
EDIT:
Sub prSplit()
If len(ActiveCell.Value) > 10 Then
Dim arr() As String
arr = Trim(Split(ActiveCell.Value, "-"))
For i = LBound(arr) To UBound(arr)
MsgBox arr(i)
Next
End If
End Sub
You can start with this and tweak the code until you get it. I just don't have the time to do the whole thing. Sorry. :o(