excel macro deleting extra rows - vba

I have a macro that deletes the rows I don't want in excel. it deletes rows that have a time before 9:30 am and after 4:00 pm. For some reason, it also deletes the rows that have time of 10:00 am to 10:09 am, 11:00 am to 11:09 am, 12:00 pm to 12:09 pm, 1:00 pm to 1:09 pm, 2:00 pm to 2:09 pm, 3:00 pm to 3:09 pm
please help me so it does not delete those rows.
my code:
Sub DeleteRows()
Dim lastRow As Long
Dim Cell As Long
Dim dt As Date
'Work with the active sheet.
With ActiveSheet
'Find the last row of your dataset.
lastRow = .Range("A:A").Find("*", searchdirection:=xlPrevious).Row
'Format your time column to a readable time.
.Columns("B").NumberFormat = "[$-F400]h:mm:ss AM/PM"
'Loop through the rows, beginning at the bottom.
For Cell = lastRow To 2 Step -1
'Piece together the date.
dt = Mid(.Cells(Cell, 1), 5, 2) & "/" & _
Mid(.Cells(Cell, 1), 7, 2) & "/" & Left(.Cells(Cell, 1), 4)
'If the date is a Sat or Sun, delete the row.
If Weekday(dt) = 1 Or Weekday(dt) = 7 Then
.Rows(Cell).EntireRow.Delete
'If the time is before 9:30am or after 4pm, delete the row.
ElseIf CInt(Hour(.Cells(Cell, 2)) & Minute(.Cells(Cell, 2))) < 930 Or _
CInt(Hour(.Cells(Cell, 2)) & Minute(.Cells(Cell, 2))) > 1600 Then
.Rows(Cell).EntireRow.Delete
End If
Next Cell
End With
MsgBox "Done!"

You could try checking the value against an actual time:
'If the time is before 9:30am or after 4pm, delete the row.
ElseIf .Cells(Cell, 2) - Int(.Cells(Cell, 2)) < CDate("09:30:00") Or _
.Cells(Cell, 2) - Int (.Cells(Cell, 2)) > CDate("16:00:01") Then
.Rows(Cell).EntireRow.Delete
Note the upper bound 16:00:01 avoids a boundary evaluation error (probably due to rounding) at 16:00:00.

Instead of using
CInt(Hour(.Cells(Cell, 2)) & Minute(.Cells(Cell, 2)))
use
100*Hour(.Cells(Cell, 2)) + Minute(.Cells(Cell, 2))
You are hitting your problem because, for example, 11:08 is being converted into 11 hours and 8 minutes, which when concatenated together in your code yields 118 (which meets the deletion condition of being less than 930). The revised version (untested) should convert it to 1108 and avoid meeting the deletion condition.

Related

VBA: Why are the defined DAY values returning "30"?

I've created a worksheet on which a month can be generated by inserting the first day of the needed month. User inserts "01/01/2017" in B4, clicks a button, the month (January) is filled out and the values within the table (C4:I34) are removed. The VBA code linked to that button goes as follows:
Sub CalReset()
'
' CalReset Macro
'
'
Dim DayOne As Integer
Dim DayTwo As Integer
Dim DayThree As Integer
DayOne = Day(B32)
DayTwo = Day(B33)
DayThree = Day(B34)
MsgBox (DayOne & " " & DayTwo & " " & DayThree) 'I used this to check what values I was getting for the days, the message box returns "30 30 30".
Range("B4").AutoFill Destination:=Range("B4:B34"), Type:=xlFillSeries
Range("C4:I34").ClearContents
If DayOne <= "3" Then Range("B32").ClearContents
If DayTwo <= "3" Then Range("B33").ClearContents
If DayThree <= "3" Then Range("B34").ClearContents
End Sub
The idea is to avoid dates of the next month. For example, if 01/02/2017 is used as a starting point, it'll fill in February (28 days) so the macro should remove March 1, 2 & 3 in corresponding cells B32, B33 & B34 (is smaller than or equals 3).
Why is the definition "Day(B32)" returning "30" while I'm seeing "01/03/2017" in that cell? It should return "1".
Note that dates are in European format, DD/MM/YYYY. Thank you for your attention.
Excel uses a data system where day #1 is 0 January 1900 (or 31 December 1899 if you like), so day #0 is 30 December 1899.
So Day(B32), where the variable B32 has never been assigned a value and therefore still contains a default value of 0, will return 30 (i.e. the day portion of 30 December 1899).
You were probably wanting to use Day(Range("B32").Value), or Day([B32]).
Sub CalReset()
With ActiveSheet
.Range("B4").AutoFill Destination:=.Range("B4:B34"), Type:=xlFillSeries
.Range("C4:I34").ClearContents
If Day(.Range("B32").Value) <= 3 Then .Range("B32").ClearContents
If Day(.Range("B33").Value) <= 3 Then .Range("B33").ClearContents
If Day(.Range("B34").Value) <= 3 Then .Range("B34").ClearContents
End With
End Sub

Search Excel Sheets for dates to consolidate data by month using VBA

I have an unknown number of Sheets in a workbook but each sheet shares identical formating. Each sheet represents a work week. These weeks can straddle calendar months. Each column has a row which reflects a day of the week and has a date cell. Date format is dd/mm/yr
My code currently finds the number of sheets and parses through the sheets to consolidate specific information to a summary sheet. This information is in a year to date (YTD) format.
In addition to YTD format, I need to be able to pull out the data on a calendar month basis.
Each sheet has up to 5 cells of data (one per day of the week) and two groups of up to 5 cells (ie. Route Hours and Total Hours, up to 5 entries- Mon-Fri, if with in the active month) The cells will be summed together resulting in two sums. This needs to be done for each working week in a calendar month and the total values then output to my summary sheet.
The code below is what I am using to go through each data sheet and grab YTD data. I want to add code to cover the monthly data extraction as well but I am having extreme difficulty implementing such code--I keep going in mental circles.
Dim I As Integar
Dim WS_Count As Integar
Dim ConsolidationArrayYTDTotalDailyAve() 'Array storage YTD Tot Daily Ave
WS_Count = ActiveWorkbook.Worksheets.Count ' last worksheet
ReDim ConsolidationArrayYTDTotalDailyAve(WS_Count-2)
For I = 2 to WS_Count 'check from 2nd WS as first sheet is the summary
ConsolidationArrayYTDTotalDailyAve(I - 2) = Worksheets(I).Name & "!R54C3:R56C8" 'Grab the data from each sheet and save in the array
Next I
Sheets("Summary").Range("B4").Consolidate sources:=(ConsolidationArrayYTDTotalDailyAve), Function:=xlAverage
I am thinking somewhat of the following design(with the do while loop to be inside the above For loop--not actual code just trying to express thought process):
Dim Im As Integer 'Same function as I when parsing through sheets
Dim FirstDay As Date 'first day of the month
Dim LastDay As Date 'last day of the month
Dim Month as Integer 'tracks active month 1 through 12
Dim RouteHrsSum As Single 'stores the sum of monthly Route Hours
Dim TotalHrsSum As Single 'stores the sum of monthly Total Hours
Month = 1 'set default month to January
Do While (ActiveCell >= FirstDay & ActiveCell <= LastDay) & Month <= 12
For Im = 2 to WS_Count
IF Month = 1 Then
FirstDay = 1/1/2016 & LastDay = 31/1/2016
ElseIF Month = 2 Then
FirstDay = 1/2/2016 & LastDay = 29/02/2016
ETC...
Else
FirstDay = 1/12/2016 & LastDay = 31/12/2016
Action: Scan a range of cells for dates for the active month
IF Date of Active Month found then sum cells A2, B2, C2 together, sum cells A9,B9,C9 together and write both sums to a pair of storage vairables (RouteHrsSum and TotalHrsSum respectively)
Else
Output RouterHrsSum & TotalHRsSum to respective cells on sheeet 1
Month = Month + 1 'Make next month active
'need to be able to recheck the last worksheet for a calendar month straddle and get data if so for new month's days
Next Im
Loop
Sample of a data worksheet: (week ending 19-Aug)
Driver Bob Monday Tuesday Wednesday Thursday Friday
15-Aug 16-Aug 17-Aug 18-Aug 19-Aug
Kilometres 318 91 119 219 394
Route Hours 5.74 4 2.5 4.25 6
Total Hours 9 9 9 9 10
Sample of a data worksheet: (week ending straddling calendar months)
Driver Bob Monday Tuesday Wednesday Thursday Friday
29-Aug 30-Aug 31-Aug 1-Sept 2-Sept
Kilometres 300 110 119 89 394
Route Hours 7 4 2.5 4.25 6
Total Hours 9 9 9 9 9
I feel I'm on the right track, conceptually, but I keep getting bogged down when it comes to the actual code and design. Any assistance is appreciated. I apologise if this is vague, but I cannot see the forest for the trees.
I will readily edit this question for content as greater clarity presents.
I think that it would be just as easy to compile the data as to use consolidate.
Sub ProcessData()
Dim arTemp
Dim d As Date
Dim x As Long, y As Integer
Dim ws As Worksheet
Dim list As Object
Set list = CreateObject("System.Collections.SortedList")
For Each ws In Worksheets
If ws.Name <> "Summary" Then
With ws
For y = 2 To 6
d = DateSerial(Year(.Cells(2, y)), Month(.Cells(2, y)), 1)
If list.ContainsKey(d) Then
arTemp = list(d)
Else
ReDim arTemp(2)
End If
arTemp(0) = arTemp(0) + .Cells(3, y)
arTemp(1) = arTemp(1) + .Cells(4, y)
arTemp(2) = arTemp(2) + 1
list(d) = arTemp
Next
End With
End If
Next
With Worksheets("Summary")
.Cells.Delete
.Range("A1:F1") = Array("Year", "Month", "Avg. Kilometres", "Avg. Route Hours", "Sum Kilometres", "Sum Route Hours")
For x = 0 To list.Count - 1
d = list.GetKey(x)
.Cells(x + 2, 1) = Year(d)
.Cells(x + 2, 2) = Month(d)
.Cells(x + 2, 3) = list(d)(0) / list(d)(2)
.Cells(x + 2, 4) = list(d)(1) / list(d)(2)
.Cells(x + 2, 5) = list(d)(0)
.Cells(x + 2, 6) = list(d)(1)
Next
.Rows(x + 2).Columns("C:D").FormulaR1C1 = "=Average(R[-" & x & "]C:R[-1]C)"
.Rows(x + 2).Columns("E:F").FormulaR1C1 = "=Sum(R[-" & x & "]C:R[-1]C)"
.Columns("C:F").NumberFormat = "0.00"
.Columns.AutoFit
End With
End Sub

VBA - How to remove string of characters in a range cell

This is the value of my date Mar 30 2016 4:46:34:256PM i want to remove the Time to make it like this Mar 30 2016.
I've tried various ways to format this if value with the format like mm-dd-yyyy , mm-dd-yyyy , yyyy-mm-dd etc. it's working but if tried this Mar 30 2016 4:46:34:256PM as value it's not working. can someone please tell me why?
I tried a simple code to test all the formats but it's not working with this value Mar 30 2016 4:46:34:256PM so i decided to remove the 4:46:34:256PM and that's how i got stock....
Sub formateDate()
Dim lastrow As Long
lastrow = Sheet1.Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To lastrow
Cells(i, 2).NumberFormat = ("dd-mm-yyyy")
Next i
End Sub
from your example you seem to have two consecutive spaces after the year number
should it always be so you could go like follows
Cells(i, 2) = Left(Cells(i, 2), InStr(Cells(i, 2), " ") - 1)
and then you can also assign it date formats since IsDate WorksheetFunction returns True if called on the resulting values

Employee serial Number based on hiring date

Please assist amending the code below. what I want to do is creating unique serial number for each employee based on their hiring date eg. on was hired on 1/13/2016 the serial number comes with the last two digital number of (year,month,day+00) that means (16011300) for the one who hired in the same day and (year,month,day+01) that means (16011301)for the second one who hired in the same day. and do the same thing for those hired on different days. see pic below first what the code do but the second what I want it to be. thanks in advance for assistance
the used code:
Dim myDate As Date, i As Long, dayPart As String
Application.EnableEvents = False
For i = 2 To Rows.Count
If Cells(i, 5).Value > 1 And Not IsEmpty(Cells(i, 5).Value) Then
myDate = Cells(i, 5)
dayPart = Format(Year(myDate), "00") - 2000 & _
Format(Month(myDate), "00") & _
Format(Day(myDate), "00") & 1
Cells(i, 2) = dayPart
End If
Next i
Application.EnableEvents = True
If your list stays sorted by Hiring Date you can just put the following formula in B2 and draw it down:
=IF(E2=E1,B1+1,VALUE(TEXT(E2,"YYMMDD")&"00"))
EDIT:
In case of unsorted lists use the following formula in B2 and draw it down:
=TEXT(E2,"YYMMDD")&TEXT(COUNTIF($E$1:E1,E2),"00")
or (if you want it as a number instead of text):
=VALUE(TEXT(E2,"YYMMDD")&TEXT(COUNTIF($E$1:E1,E2),"00"))
You cannot apply a format mask (see Number Format Codes) that included both date/time characters as well as a regular integer character, but if you convert the integer to the number of hours then your Emp no can be created in one shot.
Dim i As Long, seq As Long, dayPart As String
With Worksheets("employees")
For i = 2 To .Cells(Rows.Count, "E").End(xlUp).Row
seq = Application.CountIf(.Columns(5).Resize(i - 1, 1), .Cells(i, "E").Value)
dayPart = Format(.Cells(i, "E").Value2 + TimeSerial(seq, 0, 0), _
"yymmddhh")
.Cells(i, "B") = dayPart
Next i
End With
After collecting the number of previous matching dates with a COUNTIF function, the returned integer is converted to hours with TimeSerial and added to the hiring date. A format mask of yymmddhh generated the entire Emp no.
Granted, this is limited to 24 new employee hires per day.
        

cleaning excel sheet with vba

I have an excel sheet with lots of data. As you may know, this comes with lots of problems. One major one is having too much data. I am not familiar with vba, but I wanted to know how to clean data.
I have a sheet with 3 fields: date, time, and temp. The temperature is recorded on a minute by minute basis. The temperature is only recorded from 7 am to 10 pm, but the sheet is on a 24 hour basis. So my sheet has a lot of blank cells. So, I want to write a code that states:
if ((time < 7am) or (time > 10pm)):
delete row
Can I do this?
Also, another problem is that the data is not collected on weekends. I am not given a day field, only a date field in this format: 20130102 which is January 02 2013. I want to:
if ((date = saturday) or (date = sunday)):
delete row
Are either of these doable?
My sheets looks like the following:
A .............. B ......... .... C
date........ time ......... temp
Since both your dates and times are formatted differently than normal, we need to manipulate the values to get something to test against. Consider the following example (I've commented each line to help you follow along):
Sub DeleteRows()
Dim lastRow As Long
Dim Cell As Long
Dim dt As Date
'Work with the active sheet.
With ActiveSheet
'Find the last row of your dataset.
lastRow = .Range("A:A").Find("*", searchdirection:=xlPrevious).Row
'Format your time column to a readable time.
.Columns("B").NumberFormat = "[$-F400]h:mm:ss AM/PM"
'Loop through the rows, beginning at the bottom.
For Cell = lastRow To 2 Step -1
'Piece together the date.
dt = Mid(.Cells(Cell, 1), 7, 2) & "/" & _
Mid(.Cells(Cell, 1), 5, 2) & "/" & Left(.Cells(Cell, 1), 4)
'If the date is a Sat or Sun, delete the row.
If Weekday(dt) = 1 Or Weekday(dt) = 7 Then
.Rows(Cell).EntireRow.Delete
'If the time is before 7am or after 10pm, delete the row.
ElseIf Hour(.Cells(Cell, 1)) < 7 Or Hour(.Cells(Cell, 1)) > 22 Then
.Rows(Cell).EntireRow.Delete
End If
Next Cell
End With
MsgBox "Done!"
End Sub
A few things to note about the code. First, we must start at the bottom of the list because as we delete rows, the remaining rows shift upwards. If we were to go from top to bottom (e.g. A1 to A10), if we deleted row 5, row 6 would slide into its place, and the loop would skip row 5 (previously row 6) and go on to row 6. In other words, looping from top to bottom when deleting rows will ultimately skip rows unintentionally.
Second, I had to guess on your time format. While I believe I guessed correctly, I may not have. If I was wrong and my code doesn't change the time column into a readable time, record a macro while changing the format of that column and substitute the new format with mine ("[$-F400]h:mm:ss AM/PM"
).
And lastly, since your date column is an abnormal format (for Excel), we need to reorder the date so that Excel can read it. Once we've done that, we can use the resulting date to see if the date was a Sat. or Sun.
You can do it this way, assuming the column that contains your date is the 2nd (B) :
Dim i As Integer
for i = 1 to cellsCount
If Hour(Cells(i, 2)) < 7 Or Hour(Cells(i, 2) > 22 Then
Rows(i).Delete
Else If WeekDay(Cells(i, 2)) = 7 Or WeekDay(Cells(i, 2)) = 1 Then
Rows(i).Delete
End If
next
You can have more information about the WeekDay function here :
http://msdn.microsoft.com/en-us/library/82yfs2zh%28v=vs.90%29.aspx