I have a report that will generally be run everyday just after 7am, but occasionally could be run later during the day. In col D are ticket update times/dates. If the ticket was updated yesterday, then the cell should be left alone; if the ticket was not updated yesterday (IE, if today is the 3rd, and it has not been updated since X o'clock on the 1st) the cell should highlight. Since the report will occasionally not be run until later in the day, I can't do a simple CurrentTime - 24 hours to figure this out. I need the function to always look for the previous day and before 7am.
Without knowing exactly how to code this, I know it should be something like:
If ticketUpdateTime < currentDay at 0700 - 24
Then highlight (I know the code for this part already)
End If
Hopefully this makes sense
If DateDiff("h", CDate(ticketUpdateTime), CDate(Format(Now(), "mm/dd/yy")) + TimeSerial(7, 0, 0)) > 24 Then
highlight
End If
In plain English:
If the time elapsed between ticketUpdateTime and today's date at 07:00AM is more than 24 hours, highlight
It's a bit out of scope for the original question, but here's usage example as well:
Sub CheckTimes(rng As String)
Dim someRange As Range, someCell As Range
Set someRange = Range(rng) ' Convert input string to an actual range object
For Each someCell In someRange
If DateDiff("h", CDate(someCell.Value), CDate(Format(Now(), "dd/mm/yy")) + TimeSerial(7, 0, 0)) > 24 Then
Debug.Print "Highlight"
End If
Next cell
End Sub
To call it, input Call CheckTimes("D2:D100") or whatever range you need
Mind that there's no error-checking/-handling or data validation here - you'll have to do that yourself. ;-)
You may use dateserial(Year as integer, month as Integer, day as Integer) and TimeSerial(Hour as Integer, Minute as Integer, Second as Integer). I don't know how exactly you ticketUpdateTime looks like, so its hard to write expression. However, previous day 7 am would be:
dateserial(year(date-1), month(date-1), day(date-1)) & " " ×erial(7, 0, 0)
Appears to be an of issue. All of the dates/times are yesterday except for the value in D2 which is 11/01/2017 10:47:02, and that value is not highlighting.
Call CheckTimes("D2:D" & lastRow)
Sub CheckTimes(rng As String)
Dim someRange As Range, someCell As Range
Set someRange = Range(rng) ' Convert input string to an actual range object
For Each someCell In someRange
If DateDiff("h", CDate(someCell.Value), CDate(Format(Now(), "dd/mm/yy")) + TimeSerial(7, 0, 0)) > 24 Then
someCell.Interior.Color = 16750899
End If
Next someCell
End Sub
Related
This is a little background. In Army Aviation we have to conduct a Night Goggle (NG) flight at least once every 60 days. This date is gathered from the last time an NG flight is conducted in order to display and track currency with the mode.
With the picture linked above as reference (screenshot of actual book), I'm trying to UPDATE the date on another tab (Display Panel) with the DATE (B COLUMN) (B28) based on the INPUT (> or = 1.0) placed in the CELL (P COLUMN) (P28).
And with that, any time another NG hour entry is made below in the same column, it'll perform the script again, provided the aforementioned applies.
I've tried banging out a few VBA lines, but I'm not having any luck.
This is the shell of what I think you need which goes in the code pane associated with the sheet which you are monitoring column P of...
It fires if there is a change in column P and if the value is >=1
There is 1 further bit of logic. I am only updating C32 if the new value is greater than the existing.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim updateCell As Range
Dim lastDateCell As Range
Set updateCell = ThisWorkbook.Worksheets("Display Panel").Range("C32")
Set lastDateCell = ThisWorkbook.Worksheets("Display Panel").Range("AA32")
If Target.Column = 16 And Target.Value >= 1 Then
If Target.Offset(, -14) > updateCell Then
lastDateCell = updateCell
updateCell = Target.Offset(, -14) 'only update if greater than existing
End If
End Sub
Code in code pane of Flight Log sheet:
(Posted the solution on behalf of the question author).
Below is what I added.
Private Sub Worksheet_Change(ByVal Target As Range)
Sheets("Flight Log").Unprotect "Password Here" 'This unprotects the sheet to allow changes
Dim updateCell As Range
Dim lastDateCell As Range
Set updateCell = ThisWorkbook.Worksheets("Computations").Range("A36") 'This is the primary date location
Set lastDateCell = ThisWorkbook.Worksheets("Computations").Range("A40") 'This is the backup date location
If Target.Column = 16 And Target.Value >= 1 Then 'This check P column for the value
If Target.Offset(, -14) > updateCell Then 'If "P" returns the value, date in "B" is grabbed
lastDateCell = updateCell 'This updates the primary date cell
updateCell = Target.Offset(, -14) 'This ensures date is not overridden by lesser value
End If
End If
Sheets("Flight Log").Protect "Password Here" 'This line reprotects the sheet
End Sub
Additionally, I use two LOOKUP functions to evaluate the HOUR(s) in reference to the dates grabbed by the VBS:
=IFERROR(LOOKUP(A36,'Flight Log'!B:B,'Flight Log'!P:P),"/// NG DATE ERROR ///")
and,
=IFERROR(LOOKUP(A40,'Flight Log'!B:B,'Flight Log'!P:P),"/// NO B/U DATE ///")
after this, I use another IF function to verify the HOUR wasn't miss-entered
=IF(A37>=1,A36,IF(A41>=1,A40,"NG HOUR ERROR"))
The simple IF functions check and verify the HOUR wasn't entered incorrectly by the Pilot--which would prompt the VBS script to grab that DATE--and then re-entered to it's intended "correct" value. For instance, "Pilot enters time into block, pilots realizes time he entered was wrong, and corrects it." This will keep his error, from being an overall error.
I have a column of data (C) that has many cells that contain dates. I am trying to create a macro that checks to see if each cell contains a date and if it does then advance the date on month. I have the code to advance the date one month from here http://excel.tips.net/T002180_Automatically_Advancing_by_a_Month.html and it works fine but I am not sure how to replace the range with a dynamic range that evaluates all cells in column C. If possible I would also like to eliminate the need for a loop. Here is what I have so far.
Sub IncreaseMonth()
Dim dDate As Date
Dim NumberofTasks As Integer
NumberofTasks = ThisWorkbook.Worksheets("Dashboard").Range("Number_of_Tasks")
Dim x As Integer
For x = 1 To NumberofTasks
dDate = Range("C30").Value
Range("C30").Value = _
DateSerial(Year(dDate), _
Month(dDate) + 1, Day(dDate))
Next x
End Sub
Try something like the code below (I use DateAdd function to add 1 Month to the current date value)
Sub IncreaseMonth()
Dim dDate As Date
Dim NumberofTasks As Long
Dim x As Long
With Worksheets("Dashboard")
' I suspect you want to get the last row with data in Column C
NumberofTasks = .Cells(.Rows.Count, "C").End(xlUp).Row
For x = 1 To NumberofTasks
If IsDate(.Range("C" & x).Value) Then '<-- check if current cell at Column C is Date
.Range("C" & x).Value = DateAdd("m", 1, .Range("C" & x).Value) '<-- add 1 Month to current date in Column c, use DateAdd function
End If
Next x
End With
End Sub
This snippet should put you on the right track. I'm making a couple of assumptions here. The first is that you have a named range called "Number_of_Tasks" on which you wish to operate. Second is that all values in this range are a valid date. If values could be an invalid date (like a blank) you should check for this before setting the value.
You will also wish to ensure that the month does not become invalid. Incrementing the month past December will not be a valid date.
Sub IncreaseMonth()
Dim tempCell As Range
For Each tempCell In ThisWorkbook.Worksheets("Dashboard").Range("Number_of_Tasks")
tempCell.Value = DateSerial(Year(tempCell.value), Month(tempCell.value) + 1, Day(tempCell.value))
Next tempCell
I am trying to perform an action that will see if the date in range (dateRng) is less than today's date, and then, if it is, perform the for loop to hide the rows w.here a value in the column is zero. (I am paying off loans, and every month I want it to hide any loans that have been paid off.) Months are across columns, loans are in rows. Loan balance is (i, j).
The problem is that it never exits the for loop to go back and check the date after every new 'j' (column). It just stays in the for loop. I have tried break, exit, continue, etc. None seem to work, at least where I place them. How do I get it to check for the date, compare to 'today', THEN run the for loop to check each cell in the column, before moving on to column 2, checking the date and performing the same for loop.
It would be good to have it be dynamic, but that is not necessary, as every month I could just change the ranges in the code. This is strictly for my personal use. Any help is appreciated. thank you.
Sub hidePaid()
Dim day As Range, loanRng As Range, loanSum As Worksheet, dateRng As Range, cel2 As Range, i As Long, j As Long, col As Range
Set loanSum = ThisWorkbook.Worksheets("Loan Sum")
loanSum.Activate
Set dateRng = ActiveSheet.Range("D2:R2")
Set loanRng = ActiveSheet.Range("D4:R16")
For Each day In dateRng
If day.Value < Date Then
For j = 1 To loanRng.Columns.Count
For i = 1 To loanRng.Rows.Count
If loanRng.Cells(i, j).Value < 1 Then
loanRng.Cells(i, j).EntireRow.Hidden = True
End If
Next i
Next j
End If
Next
End sub
I added comments in the code to show my changes.
You were close, but had one to many loops and like you say, needed to find the right place for the exit.
Sub hidePaid()
Dim day As Range
Dim loanRng As Range
Dim loanSum As Worksheet
Dim dateRng As Range
Dim i As Long
Set loanSum = ThisWorkbook.Worksheets("Loan Sum")
loanSum.Activate
Set dateRng = ActiveSheet.Range("D2:R2")
Set loanRng = ActiveSheet.Range("D4:R16")
'This loop processes by column
For Each day In dateRng
'Once the date in the column is greater than today, it will stop processing
'It assumes the values in dateRng are valid dates
'(I.e. '01/01/2016' not just 'Jan', you can use number format in Excel to
'get a date to show as 'Jan' if that is better for you)
If DateDiff("d", Now(), day.Value) > 0 Then Exit For
'The line of code you had should have worked in sense,
'it would have touched every column but only procesed those before today
'It also assumes that value in the cell to be an actual date
'If day.Value < Date Then
'You do not need a column loop here as you are already in one in the
'previous loop
'For j = 1 To loanRng.Columns.Count
'This loop processes all the rows that are not already hidden and if
'the value is equal to 0 then it hides the row
'Note: you had the check to be less than 1, .50 is less than 1 and you don't
'want to get caught out on a loan!
For i = 1 To loanRng.Rows.Count
If (loanRng.Cells(i, day.Column - 3).Value = 0) And (loanRng.Cells(i, day.Column - 3).EntireRow.Hidden = False) Then
loanRng.Cells(i, day.Column - 3).EntireRow.Hidden = True
End If
Next i
Next
'Its good practice to clear out resources when finishing
Set dateRng = Nothing
Set loanRng = Nothing
Set loanSum = Nothing
End Sub
So I have a procedure that I thought was working last time I checked it but apparently it is not. The problem I am having is with 24:00 and the hour check. Yes a classic problem apparently. When entering 24:00 and I use =hour(A1) where A1 has 24:00 in it, I get the answer of 0, and that part I am ok with. I even have some other code that says if timehour = 0 then timehour = 24 and I carry on from there and all is peachy.
Today when I went to enter my 24:00 and used the hour function in VBA it returned run-time error '13': Type mismatch instead of 0.
SET UP
Cell E4 and E5 in excel has validated data list for the user to pick from in a drop down that ranges from 01:00, 02:00, 03:00, ..., 24:00. All formatted as text. If the user has selected 12 hour clock in set up then the times are listed 1:00 AM, 2:00 AM, 3:00 AM, ..., 11:00 PM, 12:00 AM.
CODE
Private Sub Set_Work_Hours()
Dim setStartHour As Integer
Dim setEndHour As Integer
Dim sht As Worksheet
'setting the worksheet to be working with
Set sht = ThisWorkbook.Worksheets("Daily")
sht.Activate
'hardcode location of start and end times from daily sheet
setStartHour = Hour(Cells(4, 5).Value)
setEndHour = Hour(Cells(5, 5).Value)
Call Display_Work_Hours(setStartHour, setEndHour)
End Sub
I get the error at setStartHour or setEndHour when I select 24:00 from the list.
In another cell in the spreadsheet, I had the formula =HOUR(E4) and =HOUR(E5) and they both return 0 when 24:00 is selected.
Why is the VBA version of HOUR not returning zero?
Clarification on the question.
Why am I getting two different results from excel formula to VBA function?
My work around
Private Sub Set_Work_Hours()
Dim setStartHour As Integer
Dim setEndHour As Integer
Dim sht As Worksheet
'setting the worksheet to be working with
Set sht = ThisWorkbook.Worksheets("Daily")
sht.Activate
'hardcode location of start and end times from daily sheet
If Cells(4, 5).Value = "24:00" Then
setStartHour = 0
Else
setStartHour = Hour(Cells(4, 5).Value)
End If
If Cells(5, 5).Value = "24:00" Then
setEndHour = 0
Else
setEndHour = Hour(Cells(5, 5).Value)
End If
Call Display_Work_Hours(setStartHour, setEndHour)
End Sub
Just expanding upon my comments. Excel stores dates and times as a serial number. The integer portion of the serial number is the number of days since 1/1/1900, and the decimal portion is the hours.
When you use hours as a string (e.g. "24:00"), Excel converts it to a serial number, in this case 1.0, or 1/1/1900 0:00. VBA does not implicitly convert invalid times like this, which is why you were seeing an error. The correct way to represent "24:00" in VBA is "00:00".
As a general suggestion, why don't you just run all of your DateTime variables in UNIX time on the backend, and just simply convert to a user-readable date on the spreadsheet?
This way no errors!!
Convert from human readable date to epoch
DateDiff("s", "01/01/1970 00:00:00", time field)
How to get the current epoch time
DateDiff("s", "01/01/1970 00:00:00", Now())
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