Transforming month names to numbers - vba

I have a userform that askes to which month the data input is applicable. I have used a combibox with jan, feb, mar etc as possible answers.
Now I want to use these answers to refer to a sheet index number Jan is sheets(2), feb = sheets(3) etc.
How do I do this?
Private Sub Userform_Initialize()
'Empty maandbox1
MultiPage1.Value = 0
Maandbox.Value = ""
With Maandbox
.AddItem "Jan"
.AddItem "Feb"
.AddItem "Mar"
'etc
End With
'Set Focus on Monthbox
Maandbox.SetFocus
End Sub
And then something like:
dim ws as worksheet
dim i as integer
i = Monthbox.Value
Set ws = ActiveWorkbook.Worksheets(i + 1)

i = Monthbox.Listindex + 2
should do the trick, since the listindex starts at 0.

You could use MonthName(). It takes a Long value and it returns its month. Thus, 1 is January, 2 is February and etc. To get the first three letters of the month use Left(value, 3):
Public Sub TestMe()
Dim cnt As Long
For cnt = 1 To 12
Debug.Print MonthName(cnt)
Debug.Print Left(MonthName(cnt), 3)
Next cnt
End Sub
In your case:
Dim ws As Worksheet
Dim i As Long
i = Monthbox.Value
Set ws = ActiveWorkbook.Worksheets(Left(MonthName(cnt + 1), 3))

You can use the DateValue function to return a dummy date and pull the integer month number from there:
Dim dt as Date, i as Long
dt = DateValue(Maandbox.Value & " 1," & Format(Now(),"YYYY"))
i = Format(dt, "M") + 1
I usually just set the date to the first of the month. The Format(Now(),"YYYY") simply turns the current day's date into a year to complete the DateValue function parameters. I have found this method flexible because it creates a date that you can now format however else you need it. For instance, if you need the full month description, you now have the option of doing:
RunMonth = Format(dt, "MMMM")
since it's been saved in your variable.

Related

VBA: find second largest value

I have the following problem: I try to filter a date column (A) in a worksheet (HISTORICALS) to return the highest and second highest date value. Currently, there is dates ranging from the 25th to the 31st of December in this column. Unfortunately, below formula (using the Large function) returns the 31st two times (and not the 30th and 31st as intended).
Sub Select_Last_Two_Days()
With Worksheets("HISTORICALS")
Highest_Max = Format(WorksheetFunction.Large(Worksheets("HISTORICALS").Range("A:A"), 1), "Short Date")
Second_Highest_Max = Format(WorksheetFunction.Large(Worksheets("HISTORICALS").Range("A:A"), 2), "Short Date")
Debug.Print Highest_Max, Second_Highest_Max
End With
End Sub
The column has approx. 2000 rows, with dates occuring multiple times. So ideally I would want to filter for distinct values and then return the two highest dates. Any idea how I can do that?
Simply translate Barry Houdinis answer from How to find the first and second maximum number? to VBA:
Sub Select_Last_Two_Days()
With Worksheets("HISTORICALS")
Highest_Max = Format(WorksheetFunction.Max(.Range("A:A")), "Short Date")
Second_Highest_Max = Format(WorksheetFunction.Large(.Range("A:A"), WorksheetFunction.CountIf(.Range("A:A"), WorksheetFunction.Max(.Range("A:A"))) + 1), "Short Date")
Debug.Print Highest_Max, Second_Highest_Max
End With
End Sub
The recommendations given in the comments are probably the simplest and least amount of code way to do things but here is another sugggestion:
Sub test()
Dim wb As Workbook
Dim ws As Worksheet
Set wb = ThisWorkbook
Set ws = wb.Worksheets("HISTORICALS")
Dim lastRow As Long
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim loopArr()
loopArr = ws.Range("A1:A" & lastRow).Value
Dim maxVal As Date
maxVal = Application.WorksheetFunction.Large(ws.Range("A1:A" & lastRow), 1)
Dim i As Long
Dim secondVal As Date
For i = UBound(loopArr, 1) To LBound(loopArr, 1) Step -1
If loopArr(i, 1) < maxVal Then
secondVal = loopArr(i, 1)
Exit For
End If
Next i
End Sub

Getting specific dates from a date range in VBA

I have a sheet that have a range of dates in column A. I already found the way to get the last row with:
LastRow = Worksheets("TIME").Cells(Rows.Count, "A").End(xlUp).Row
Now I am trying to get specific dates. The range contains no weekends, but since the dates are proprietary, I could not use the WorkDay function to find what I need.
Case 1:
From the last date available, I am trying to get the date 1 year before (if the date is not available, pick the next available one).
What I did here was to use the date function and subtract 1 year..
day1Y = date(year(LastRow)-1,month(LastRow),day(LastRow))
To match, I transformed the date range into an array, and used a function do determine if it is in the array. If it is, get it, but if it is not, I don't know how to get the next available.
Dim DateArray() as Variant
Dim WantedDate1 as date
Dim WantedDate2 as date
DateArray() = Worksheets("TIME").Range("A2:A" & LastRow).Value
If IsInArray(day1Y) = True then
WantedDate1 = .Cells(1,LastRow).Value
End if
Case 2:
From the last available date, I am trying to get the first date in the same year (if last date is 10/08/2015, it gets the first available date of 2015, according to the dates available in the range).
WantedDate2 = Year(.Cells(1,LastRow).Value)
I got the year of the last date, but again, I can't find the first date of that year.
Any help will be deeply appreciated.
Use a loop to increase the days 1 by 1 and test if it is the array on the go :
Option Explicit
Sub DGMS89()
Dim wsT As Worksheet
Dim LastRow As Double
Dim DateArray() As Variant
Dim LastDate As Date
Dim Day1y As Date
Dim WantedDate1 As Date
Dim WantedDate2 As Date
Set wsT = ThisWorkbook.Sheets("TIME")
LastRow = wsT.Cells(wsT.Rows.Count, "A").End(xlUp).Row
DateArray() = wsT.Range("A2:A" & LastRow).Value
LastDate = DateArray(UBound(DateArray, 1))
Day1y = DateAdd("yyyy", -1, LastDate)
WantedDate1 = Day1y
If IsInArray(WantedDate1) Then
Else
Do While Not IsInArray(WantedDate1)
WantedDate1 = DateAdd("d", 1, WantedDate1)
Loop
End If
WantedDate2 = DateSerial(year(LastDate), 1, 1)
Do While Not IsInArray(WantedDate2)
WantedDate2 = DateAdd("d", 1, WantedDate2)
Loop
End Sub

Calculating Due Dates based on Frequency using VBA

So, right now I have this Excel sheet where there is a last revision date. I have named this column "LastRevisionDate". And then I have a column named "RevisionFrequency" . The "RevisionFrequency" contains a drop-down menu (data validation) consisting of terms, Annually, Semi-Annually, and Quarterly. And then I have a column where it states the "NextRevisionDate".
So I want to write some VBA code that would calculate the NextRevisionDate from the LastRevisionDate and the RevisionFrequency.
For example. Say in column "A" I have the RevisionFrequency to be Semi-Annually, And the last revision date was Mar-14 in column "B", then I would want the NextRevisionDate in column "C" to state September. That's basically saying that the item gets revised twice a year.
So I would want to create a macro where Column "C" is based off the RevisionFrequency and LastRevisionDate. I realize I could do this with a formula, but I have new items being added constantly so I do not want to keep copying formulas into each cell. Also for some items, they do not need revision, I would also like to have a blank cell if there is no LastRevisionDate.
So far, I have this code:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim ws As Worksheet
Set ws = Sheets(1)
'For this reference of the Column Named LastCalDate I am getting an error
If Not Intersect(Target, ws.Range("LastCalDate").Value) Is Nothing Then
Dim Lastdate As Date
Dim DueDate As Variant
Dim Frequency As String
Dim R As Variant
Dim C As Variant
Dim R1 As Variant
Dim C1 As Variant
Dim R2 As Variant
Dim C2 As Variant
R = Range("LastCalDate").Row
C = Range("LastCalDate").Column
R1 = Range("CalDueDate").Row
C1 = Range("CalDueDate").Column
R2 = Range("CalFrequency").Row
C2 = Range("CalFrequency").Column
Lastdate = Cells(R, C).Value 'Last Cal Date
DueDate = Cells(R1, C1).Value 'Cal Due Date
Frequency = Cells(R2, C2)
If Frequency = "Annually" Then
DueDate = DateAdd("mmm", 12, Lastdate)
End If
If Frequency = "Semi-Annually" Then
DueDate = DateAdd("mmm", 6, Lastdate)
End If
If Frequency = "Quarterly" Then
DueDate = DateAdd("mmm", 3, Lastdate)
End If
End Sub
This is what I have so far. I'm not sure If I am doing this correctly?
Using the Worksheet_Change method is a great way to create the new cell value without having to copy and paste a formula. I included checks in my code as well to make sure if the date or frequency is not set, then the value is cleared out.
Private Sub Worksheet_Change(ByVal Target As Range)
' declare and set worksheet
Dim ws As Worksheet
Set ws = Sheets(1)
' declare and set default date
Dim DefaultDueDate As Date
' declare needed variables
Dim StartDate As Date
Dim Frequency As String
Dim DueDate As Date
' make sure the change only occured on the "A" or "B" column
If Target.Column = 1 Or Target.Column = 2 Then
StartDate = ws.Range("A" & Target.Row)
Frequency = ws.Range("B" & Target.Row)
' if start date does not equal the default due date and the frequency is not blank, set due date variable
If StartDate <> DefaultDueDate And Frequency <> "" Then
' add months to the provided start date
If Frequency = "Annually" Then
DueDate = DateAdd("m", 12, StartDate)
ElseIf Frequency = "Semi-Annually" Then
DueDate = DateAdd("m", 6, StartDate)
ElseIf Frequency = "Quarterly" Then
DueDate = DateAdd("m", 3, StartDate)
End If
' Make sure frequency selection is correct and due date was set
If DueDate <> DefaultDueDate Then
ws.Range("C" & Target.Row) = DueDate
End If
Else
' clear Next Revision Date when Frequency or Start Date is blank
ws.Range("C" & Target.Row) = ""
End If
End If
End Sub

Excel: Enter dates in specific column

My requirement is:
I want to enter date from 1st Jan to 31st Jan in columns E5 to AI5. Currently using the below code which is not working.
Secondly year i m taking as user input which should change every time.
Sub LoopA()
Call Using_InputBox_Method
Dim i As Integer
Dim j As Integer
Dim PH As Integer
i = 5
For j = 5 To 35
Cells(i, j).Value = "=Date(E1,1,j)"
Next j
End Sub
Public Function Using_InputBox_Method() As Integer
Dim Response As Integer
' Run the Input Box.
Response = Application.InputBox("Enter a Year.", _
"Number Entry", , 250, 75, "", , 1)
' Check to see if Cancel was pressed.
If Response <> False Then
' If not, write the number to the first cell in the first sheet.
Worksheets(1).Range("E1").Value = Response
End If
Using_InputBox_Method = Response
End Function
A)
Anything within " will be considered as a String. So "=Date(E1,1,j)" is just a string. What you want, I guess is
"=Date(E1,1," & j & ")"
B)
For j = 5 To 35
Are you sure you want to go up till 35? The max you can have in any month is 31 :)
Syntax of =Date() is DATE(year,month,day)
Also you would need an additional check here to see if it is a valid date. For example 30th Feb will give you an error.
C)
InputBox should be avoided to accept dates. It can generate errors. You may want to use THIS. If you still want to use InputBox then you will have to do validations to ensure that there are no errors.
D)
Regarding, the Year changing automatically, You will have to increment the Year in Column E once the user automatically enters the date.
Is this what you are trying?
Sub Sample()
Dim Yr As Long, i As Long
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
Yr = Application.InputBox("Enter a Year.", _
"Number Entry", , 250, 75, "", , 1)
'~~> Set it to whatever Year Range you want
If Yr < 1900 Or Yr > 9999 Then
MsgBox "Incorrect Year"
Exit Sub
End If
With ws
.Range("E1").Value = Yr
For i = 5 To 35
.Cells(5, i).Formula = "=Date(E1,1," & (i - 4) & ")"
Next i
End With
End Sub

Excel VBA script for loop with dates

I am calculating the number of work hours (8am to 8pm) between the 2 given dates, excluding Weekends and Public holidays, but my code syntax is incorrect.
Sample data:
Start day: 17/06/2011 08:00:00 AM
End day: 19/06/2011 08:00:00 PM
Sub SLA_Days_Resolved_F()
Dim x As Integer
' Set numrows = number of rows of data.
NumRows = Range("F2", Range("F2").End(xlDown)).Rows.Count
Dim total As Integer 'to count the total hours
Dim st As String 'start date cell
Dim en As String 'end date cell
Dim destCell As String
Dim d As Date ' for the loop
total = 0
' Establish "For" loop to loop "numrows" number of times.
For x = 2 To NumRows + 1
st = "G" & CStr(x) 'reference to the cells
en = "D" & CStr(x)
'loop from start date to end date
For d = Date(Range(st)) To Date(Range(en))
'check if the current date is found is a Public holiday in the range or if a weekend
If ((Vlookup(d,lookups!$o$3:$p$26,2,false))=1) or (weekend(d))Then
'minus 8 to remove hours before 8am.
total = (total + Hour(d) + minutes(d) / 60) - 8
End If
Next
Next
End Sub
You are not assigning any values to variables st or en.
Date is not a function available in VBA. You will probably need to use DateSerial function. Here is a simple example of looping over dates which you should be able to modify.
Sub LoopDates()
Dim d As Date
'Loop the days beteween today and March 1, 2013.
For d = DateSerial(Year(Now), Month(Now), Day(Now)) To DateSerial(2013, 3, 1)
Debug.Print d 'Prints the "d" value in the immediate window.
Next
End Sub
Also, you can't just put worksheet formulae in VBA. This line is definitely wrong syntax for Vlookup, and Weekend is not a formula that I'm aware of (testing it seems to confirm it is not a valid call on worksheet or in VBA.
If ((Vlookup(d,lookups!$o$3:$p$26,2,false))=1) or (weekend(d))Then
Rewrite as:
If Application.WorksheetFunction.Vlookup(d,Sheets("lookups").Range("$o$3:$p$26"),2,false)=1 _
or Not Application.WorksheetFunction.Weekday(d) Then
ANOTHER EXAMPLE of a date loop where I have dimensioned the variables in what I believe to be a more efficient manner:
Sub Test()
Dim st As Range
Dim x As Integer
Dim stDate As Date
Dim enDate As Date
Dim d As Date
Dim numRows as Long
NumRows = Range("F2", Range("F2").End(xlDown)).Rows.Count
For x = 0 To NumRows-2
'SET YOUR VARIABLES HERE
' This may seem redundant or unnecessary for this case, but it makes structuring nested
' loops easier to work with, and then there are fewer places to make changes,
' if you need to make changes.
Set st = Range("G2").Offset(x, 0)
Set en = Range("D2").Offset(x, 0)
stDate = DateSerial(Year(st), Month(st), Day(st))
enDate = DateSerial(Year(en), Month(en), Day(en))
'Then, loop through the dates as necessary
For d = stDate To enDate
Debug.Print d
'Do your code here.
Next
Next
End Sub