vba type mismatch on my script - vba

So, I'm getting a type mismatch in the VBA script of a Word document, however there isn't any line signaled on the editor... Can any of you give me an hint of what it might be?
Private Sub bt_run_Click()
'set months array
Dim months As Variable
months = Array("Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro")
With ThisDocument.Tables(0)
Do While .Rows.Count > 2
.Rows(2).Delete
Loop
'Ask for year
Dim req As String
Dim yr As Integer
req = InputBox("Insere ano.")
If IsNumeric(req) Then
yr = CInt(req)
Else
MsgBox ("Erro")
Return
End If
'get previous year last week
'TODO
'Now generate current year months
For i = 1 To 12
'get number of mondays on the month (how many weeks belong here)
Dim mondays As Integer
mondays = MondaysOnMonth(i, yr)
'now generate a line for each monday
For k = 1 To mondays
.Rows.Add
Next k
Next i
'get next year first week
'TODO
End With
End Sub
Function MondaysOnMonth(ByVal month As Integer, ByVal year As Integer) As Integer
Dim mondays As Integer
mondays = 0
Dim d As Date
Dim dtStr As String
dtStr = "1/" & month & "/" & year
d = DateValue(dtStr)
Dim days As Integer
days = dhDaysInMonth(d)
For i = 1 To days
dtStr = i & "/" & month & "/" & year
d = DateValue(dtStr)
Dim w As Integer
w = Weekday(d, vbMonday)
If w = 0 Then
mondays = mondays + 1
End If
Next i
MondaysOnMonth = mondays
End Function
Function dhDaysInMonth(Optional ByVal dtmDate As Date = 0) As Integer
' Return the number of days in the specified month.
If dtmDate = 0 Then
' Did the caller pass in a date? If not, use
' the current date.
dtmDate = Date
End If
dhDaysInMonth = DateSerial(year(dtmDate), _
month(dtmDate) + 1, 1) - _
DateSerial(year(dtmDate), month(dtmDate), 1)
End Function
This pretty much generates how many lines as there're mondays in the entire year in the only table of the document.
I'm not really experienced in all this thing of Visual Basic for Applications, but I'm assuming it's some type casting that the compiler can't execute, however, I can't really see what it might be (and the compiler isn't giving me the necessary help), so what might it be?

In my (limited) experience, arrays are setup a little differently in VBA:
'set months array
Dim months(11) As String
months(0) = "Janeiro"
months(1) = "Fevereiro"
months(2) = "Março"
months(3) = "Abril"
months(4) = "Maio"
months(5) = "Junho"
months(6) = "Julho"
months(7) = "Agosto"
months(8) = "Setembro"
months(9) = "Outubro"
months(10) = "Novembro"
months(11) = "Dezembro"
Also, I could not address table 0, so changed it to table 1 and the code seemed to execute.
With ThisDocument.Tables(1)
Hope this helps!

Array Function
Returns a Variant containing an array!!!
Dim months As Variant

You were so close.
In your original code, you should be able to change Variable to Variant and the initialization will work as you expected.
Here I've copy/pasted your array initialization, swapped in Variant, and written a loop that confirms the array was properly initialized by printing the values to the Immediate Window (press Ctrl+G to view if it is not already visible):
Sub TestMonthArrayInitialization()
Dim months As Variant
months = Array("Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro")
Dim i As Integer
For i = 0 To 11
Debug.Print months(i)
Next i
End Sub

Related

VB.Net find last day of month with date format

I am trying to find the last day of the month and compare it to today's date
I do NOT want the integer number I would like the result in this format "MM-dd-yyyy"
Date Picker will not work for this project
Here is the code I using but the process seems overly complicated concocting strings
Side note when today is after the 4th Tue I write True and the Last Day of the month to a DB
when today is after the last day of the month and the bool is now True I write the new last day of the new month and false to the DB
Function FourthTueOfMonth(dt As Date) As Date
Dim currDate = New Date(dt.Year, dt.Month, 1)
Dim nTuesday = 0
While nTuesday < 4
If currDate.DayOfWeek = DayOfWeek.Tuesday Then
nTuesday += 1
End If
currDate = currDate.AddDays(1)
End While
Return New Date(dt.Year, dt.Month, currDate.Day - 1)
End Function
Private Sub btnFindDate_Click(sender As Object, e As EventArgs) Handles btnFindDate.Click
Dim tORf As Boolean = False
Dim dateToday = Date.Today
Dim dateFourthTue = (FourthTueOfMonth(Date.Today))
tbFourthTue.Text = dateFourthTue.ToString("MMM-dd-yyyy")
tbThree.Text = dateFourthTue.ToString("yyyy-MM-dd")
tbEndOFMonth.Text = Date.DaysInMonth(Date.Now.Year, Date.Now.AddMonths(0).Month).ToString
Dim dToday As Date
dToday = Date.Parse("10-01-2021")
Dim dtY = dateToday.ToString("yyyy")
Dim dtM = dateToday.ToString("MM")
Dim eom As String = Date.DaysInMonth(Date.Now.Year, Date.Now.AddMonths(0).Month).ToString
Dim dtALL As String
dtALL = dtM & "-" & eom & "-" + dtY
Dim testD As Date
testD = Date.Parse(dtALL)
If tORf = False And dToday > dateFourthTue Then
MessageBox.Show("Today > Fourth Tue")
'tORf = True'Write True
'tbMessage.Text = tORf.ToString
End If
If tORf = True And dToday > testD Then
MessageBox.Show("Today > End Of Last Month")
'tORf = False write False
'tbMessage.Text = tORf.ToString
End If
End Sub
The solution provided by #Albert D. Kallal is great for Visual Basic since DateSerial is in the Visual Basic namespace in the DateAndTime class. Here is a solution that should work in both vb and C#.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim dtToday As Date = Date.Today
Dim dtEndOfMonth = New Date(dtToday.Year, dtToday.Month + 1, 1).AddDays(-1)
Debug.Print(dtToday.ToString)
Debug.Print(dtEndOfMonth.ToString("MM-dd-yyyy"))
End Sub
A few things:
You want to use today - not "now()" as that includes a time portion. While a date type only has date, you should consider if you have datetime, and either way, no need to introduce and use a value that includes both date and time such as now does.
I reocmmend this code:
Dim dtToday As Date = Date.Today
Dim dtEndOfMonth As Date = DateSerial(dtToday.Year, dtToday.Month + 1, 0)
Debug.Print(dtToday)
Debug.Print(dtEndOfMonth)
Output:
Today happens to be the 1st, but any date would work. This includes end of year, and even leap years.
2021-10-01
2021-10-31
So, this is a long time old trick - goes back to old VB6, and even old VBA code from 20 years ago.
So, we use date serial to produce a date, but if you use 0 for the day, then you get the previous day, and thus gets you the last day of the current month.
So we toss in year, month + 1, and 0 for the date - that results in the last day of the current month.
I hate to admit I might have gave up the search too quick
found the answer here
Answer Here
Here is the code
Dim dateToday = Date.Now.AddMonths(0)
Dim dateEndOfMonth = New Date(dateToday.Year, dateToday.Month, DateTime.DaysInMonth(dateToday.Year, dateToday.Month))
tbMsg.Text = dateEndOfMonth.ToString("MM-dd-yyyy")
Code seems to be working ?
I have seen suggestions to use this format for comparing dates
TEST DATES use this format yyyyMMdd Please comment if you can add to the answer

Get same nth day of the month in x number of months

I am needing some help converting a function from access vba to vb.net.
The script generates a new date, based on the date entered, and the number of months to be added.
“If today is the second Tuesday in March, what will be the second Tuesday in 4 months?”
Public Function NdNwk(dType As String, _
dtSpan As Integer, sDate As Date) As Variant
' This Function RETURNS the DAY of WHICH WEEK
' (e.g. Second Tuesday of the Month).
' FUNCTIONS to be passed to Variables:
' gtDoW: Day of the WEEK of the START DATE.
' (1 for Sunday, 2 for Monday, etc.)
' gtWoM: WEEK of the MONTH of the START DATE.
' (1 for First, 2 for Second, etc.)
' gtDSTdt: Desired DATE
' (generated by the [DateAdd] Function).
' CALL EXAMPLE: If TODAY is Tuesday, March 10, 2020,
‘ (second Tuesday of March), then using
' NdNwk(m, 2, #5/21/2020#)
' Would generate the DATE 5/12/2020,
' As the SECOND TUESDAY of MAY.
Dim gtDSTdt As Date, gtWoM As Integer, gtDoW As Integer
Dim iLoop As Integer, iPick As Integer, dstDTdom As Date
gtDoW = Weekday(sDate)
gtWoM = (Int((Day(sDate) - 1) / 7) + 1)
gtDSTdt = DateAdd(dType, dtSpan, sDate)
For iLoop = 1 To Day(DateSerial(Year(gtDSTdt), _
Month(gtDSTdt) + 1, 0))
dstDTdom = DateSerial(Year(gtDSTdt), _
Month(gtDSTdt), iLoop)
If Weekday(dstDTdom, 1) = gtDoW Then
iPick = iPick + 1
If iPick = gtWoM Then
NdNwk = dstDTdom
Exit Function
End If
End If
Next
End Function
Any and all help is appreciated here.
I used several of the properties and methods of the .net DateTime structure. https://learn.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.1
The arithmetic in the Function used the Mod operator which returns the remainder of the division. The integer division (the formard slash \) returns the integer portion of the division.
The only other thing that might be unfamiliar is the interpolated string, a string starting with $"". This allows you to directly embed variables in the string surround by { }.
Private Function NdNwk(InputDate As Date, MonthsAhead As Integer) As String
Dim newDate As Date
Dim DofWeek = InputDate.DayOfWeek
Dim Day = InputDate.Day
Dim OfInputMonth As Integer
If Day Mod 7 = 0 Then
OfInputMonth = Day \ 7
Else
OfInputMonth = (Day \ 7) + 1
End If
Dim TempDate = InputDate.AddMonths(MonthsAhead)
Dim NewMonth = TempDate.Month
Dim NewYear = TempDate.Year
Dim FirstWeek As Date
Dim NewDay As Integer
For d = 1 To 7
FirstWeek = New Date(TempDate.Year, TempDate.Month, d)
If FirstWeek.DayOfWeek = DofWeek Then
NewDay = d
Exit For
End If
Next
Dim DaysToAdd = (OfInputMonth - 1) * 7
newDate = New Date(NewYear, NewMonth, NewDay).AddDays(DaysToAdd)
Dim NewDateString = $"{newDate.ToString("MM/dd/yyyy")} is the {GetOrdinalString(OfInputMonth)} {DofWeek} of {TempDate.ToString("MMMM")}, {TempDate.Year}"
Return NewDateString
End Function
Private Function GetOrdinalString(input As Integer) As String
Dim output As String
Select Case input
Case 1
output = "1St"
Case 2
output = "2nd"
Case 3
output = "3rd"
Case 4
output = "4th"
Case 5
output = "5th"
Case Else
output = ""
End Select
Return output
End Function
Usage...
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim InputDate As Date
Dim MonthsToAdd As Integer
If Not Date.TryParse(TextBox1.Text, InputDate) Then
MessageBox.Show("Please enter a valid date in Date")
Return
End If
If Not Integer.TryParse(TextBox2.Text, MonthsToAdd) Then
MessageBox.Show("Please enter a valid number in Months To Add")
Return
End If
Dim d = NdNwk(InputDate, MonthsToAdd)
MessageBox.Show(d)
End Sub
First of all, thanks for all the feedback.
The solution that I was able to parse together is as follows:
A text box to show the number of months.
A text box to show the new date.
A button click action to run the following code:
Private Sub BtnMonth_Click(sender As Object, e As EventArgs) Handles BtnMonth.Click
Dim WrkDt As Date = Now
Dim QtyMnths As Integer = CType(TxtMntCount.Text, Int32)
Dim newFoM = New Date(WrkDt.Year, WrkDt.Month, 1).AddMonths(QtyMnths)
Dim DoWDt As Integer = WrkDt.DayOfWeek
Dim newMntdate = newFoM.AddDays(Enumerable.Range(0,
Date.DaysInMonth(newFoM.Year, newFoM.Month) - 1).Where(Function(i) newFoM.AddDays(i).DayOfWeek = DoWDt).Skip(1).First())
TxtNewDate.Text = Format(newMntdate, "MMMM dd, yyyy (ddd)")
End Sub
This works perfectly fine for me!
Mary's solution looks great, and I will give it a shot in the future when I need a modular input.
Thanks again for all the help!
I tested your solution, and it doesn’t produce the described results.
See test and correct solution at: https://dotnetfiddle.net/v5wGng
A couple of things from your original problem, you should prefer calculation to loops wherever possible, and you should use the required types wherever possible. If you have date in one format (string) and need it in another for your calculations, you should do the conversion and then call a function that does your calculations where all of the parameters are of the correct type.
Public Function GetSameWeekAndWeekDay(dt as date, months as integer) as Date
Dim newMonth =(new date(dt.year, dt.month, 1)).AddMonths(Months)
Dim week = getweek(dt)
Dim sameWeekDay = GetNthDayOfWeek(newMonth, week, dt.DayOfWeek)
Return SameWeekday
End Function
Public Function GetWeek(dt as date) as integer
Return(dt.day - 1) \ 7
End Function
Public Function GetNthDayOfWeek(dt as date, week as integer, weekDay as System.DayofWeek) as Date
Dim first = new Date(dt.year, dt.month, 1)
Dim baseDate = first.AddDays(-(first.DayOfWeek - system.dayofweek.Sunday))
Dim newDate = baseDate.AddDays((week * 7) + weekday)
If(newdate.DayOfWeek < first.DayOfWeek) then
newDate = newDate.AddDays(7)
End If
Return newdate
End Function

The program will know the time span if else vb.net

I dont know how it is called thats why I called it time span.
I don't have any idea yet how to code it but this is what i want to do
Dim sy as String
If (June 2015) to (March 2016) Then
sy = "2015-2016"
End if
I know it is simple but i dont know how to code the June 2015 to 2016
Thanks in advance for the help
Edit :
Now i got to this code
I uses to do this
Dim value as DateTime = New DateTime(2017, 4, 1)
Dim value1 as DateTime = New DateTime(2018, 4, 1)
Dim sy as String
If my.computer.clock.localtime <= value then
sy = "2016-2017"
ElseIf my.computer.clock.localtime <= value1 then
sy = "2017-2018"
Else
msgbox("Check your current date")
End if
But when the computer's time changed to 2015 it shows "2016-2015"
So I use 4 textboxes to supply the data you need as variables. 2 for the years and 2 for the months. Also you need to think of how many moths left in the yeae and add the month number of the next year. If you span more than one year you have to account for this as well. O.K here is the snippet without error checking in a button event:
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
Dim firstÝear As Integer = CInt(TextBox3.Text)
Dim secondYear As Integer = CInt(TextBox4.Text)
Dim firstmonthnumber As Integer = CInt(TextBox5.Text) 'months number in first year
Dim secondmonthnumber As Integer = CInt(TextBox6.Text)
Dim d1 As DateTime = New DateTime(firstÝear, firstmonthnumber, 1)
Debug.Print(d1.ToString)
Dim d2 As DateTime = New DateTime(secondYear, secondmonthnumber, 1)
Debug.Print(d2.ToString)
Dim M As Integer = Math.Abs((d1.Year - d2.Year)) - 1
Debug.Print(M.ToString)
Dim myYear As Integer = 12 - firstmonthnumber 'month left to the end of first year
Dim months As Integer = ((M * 12) + Math.Abs((d1.Month - d2.Month))) + myYear
Debug.Print(months.ToString)
End Sub

Monthview Bolding Every Value

I created a Monthview and TimePicker in a form. I want the user to pick the time, and select a month which will bold the value selected each time, then select OK which will insert the value. I have all of this working fine. The issue is that if a user selects a date, then selects another date, or another date, all the dates are getting Bolded. I want the BOLD to only follow each most recent click.. if that makes sense, so that the user knows what value he chose.
Here is my click code:
Private Sub MonthView1_DateClick(ByVal DateClicked As Date)
Dim x As Date
x = MonthView1.value
MonthView1.DayBold(x) = True ' Bold the date
End Sub
What method do I need? Is there some kind of most-recent clicked property?
Try the following code:
Private Sub MonthView1_DateClick(ByVal DateClicked As Date)
Dim x As Date
Dim MaxDate As Date
Dim MinDate As Date
MinDate = DateSerial(Year(DateClicked), Month(DateClicked), 1) 'Get first date of current month based on clicked date
MaxDate = DateSerial(Year(DateClicked), Month(DateClicked) + 1, 0) 'Get last date of current month based on clicked date
x = ActiveCell.Value 'Retreive value of last Bold date
If x >= MinDate And x <= MaxDate Then 'If last Bold date is in the current month then unbold it
MonthView1.DayBold(x) = False
End If
MonthView1.DayBold(DateClicked) = True 'Bold the clicked date
ActiveCell.Value = DateClicked 'Store current date in a sheet
End Sub
The idea is to save the Bold date in a sheet (you may hide it if you wish) and retrieve it when another date is selected. The Bold formatting is removed from the previous date and applied to the current one.
a bit more on bolding in a MonthView
'<code>
Private Sub CommandButton1_Click()
Dim Ss(50) As Boolean
'put in module DaysToBold$ and DatesToBold$ as public variables
DaysToBold = "713" ' sat Sun Tue
' DaysToBold = "" ' for none
DatesToBold = "x,1,2,12,22,30"
' DatesToBold = "x" ' if none
MonthView21_GetDayBold Now, 49, Ss
End Sub
Private Sub MonthView21_GetDayBold(ByVal StartDate As Date, _
ByVal Count As Integer, State() As Boolean)
Dim I As Integer, Mi%, DTB, DI%, DAd%
On Error Resume Next ' seem to be negative indices into State() even if declared ( -10 to 50)
For Mi = 1 To Len(DaysToBold) ' mark of the Days of week to bold
I = Mid(DaysToBold, Mi, 1) ' single digits 1 ..7 excel translate to integer
While I < Count
State(I - MonthView21.StartOfWeek) = True
I = I + 7 ' down the column
Wend
Next Mi
DTB = Split(DatesToBold, ",")
If UBound(DTB) > 0 Then
With MonthView21
For I = 1 To UBound(DTB) ' mark the date numbers to bold
DI = Weekday(DateSerial(Year(.Value), Month(.Value), 1), .StartOfWeek)
If DI = 1 Then DAd = 5 Else DAd = -2 ' 7 days of last month there if Di=1
State(DTB(I) + DI + DAd) = True
Next I
End With
End If
End Sub
'</code>

changing a value to next value in an array

I am developing a routine to calculate the proper futures contract front month
If i have a array of integers denoting month numbers ie, "1,4,7,10,12"
and I have a variable integer that is 2.
How do i test the variable against the array and change the variable to the next highest available in the array if the variable itself wasn't in the array? ie in this case the variable's value of 2 would become 4.
I've tried various ways but am stuck now
If datenum >= (targetdayofmonth + adjdays) Then
currentmonth = currentmonth + 1
Dim currmonthname As String = MonthName(currentmonth, True)
For x As Integer = 0 To contractmonths.Count - 1
If GetMonthNumberfromShortMonthName(contractmonths(x)) = currentmonth Then
currmonthname = currmonthname
Else
End If
Next
Else
Dim currmonthname As String = MonthName(currentmonth, True)
End If
So based on Tim's comments I've updated the code to;
Dim contractmonthNos As New List(Of Int32)
For Each childnode As XmlNode In From childnode1 As XmlNode In root Where childnode1.SelectSingleNode("futures/symbol/Code").InnerText = commodcode
'get the available contract months for this contract
Dim contractmonthnodes As XmlNode = childnode.SelectSingleNode("ContractMonths")
contractmonthNos.AddRange(From subnode As XmlNode In contractmonthnodes Select GetMonthNumberfromShortMonthName(subnode.Name))
Next
If datenum >= (targetdayofmonth + adjdays) Then
currentmonth = currentmonth + 1
Dim currmonthname As String = MonthName(currentmonth, True)
Else
Dim nextmonth = From month As Integer In contractmonthNos Where month > currentmonth
If nextmonth.Any() Then
currentmonth = nextmonth.First()
End If
Dim currmonthname As String = MonthName(currentmonth, True)
End If
but I am getting a VS2012 squiggly under nextmonth in the If Then Else warning of "Possible multiple enumeration of IEnumerable"
I think this is what you want:
Dim intVar = 2
Dim months = { 1,4,7,10,12 }
Dim higherMonths = months.Where(Function(month) month > intVar).ToArray()
If higherMonths.Any() Then
intVar = higherMonths.First()
End If
If you don't want the next available month in the array but the nearest you have to sort before:
Dim higherMonths = months.Where(Function(m) m> intVar).
OrderBy(Function(m) m).
ToArray()
If higherMonths.Any() Then
intVar = higherMonths.First()
End If
Something like
Module Module1
Sub Main()
' N.B. this needs to the array to be sorted.
Dim a() As Integer = {1, 4, 7, 10, 12}
Dim toFind As Integer = 2
Dim foundAt As Integer = -1
For i = 0 To a.Length() - 1
If a(i) >= toFind Then
foundAt = i
Exit For
End If
Next
If foundAt >= 0 Then
Console.WriteLine(String.Format("Looked for {0}, found {1}.", toFind, a(foundAt)))
Else
Console.WriteLine(String.Format("Did not find {0} or higher.", toFind))
End If
Console.ReadLine()
End Sub
End Module
Or you might want to look at using the Array.BinarySearch Method.