I'm attempting to display a button on a secondary form in vb based on what the date is (Trying to get a reset button to show only on the last day of the year).
I've tried a few different things with the code below...
I originally put it in the Form Load Event of Form 2, no msgbox displayed, button didn't display.
I cut the code out of my project and pasted it into the Form Load Event of a new project to test it on it's own... Msgbox displayed and button displayed!! :)
This got me thinking maybe I had to put the code into the Form Load Event of the Main Form. I pasted it there and made the modifications to point to form2 (Current version of the code)....
Once again , no msgbox, no button
What am I missing?
Private Sub Main_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim date1 As String = String.Format("{0:MM/dd/yyyy}", DateTime.Now)
Dim todaysdate As String = Format(Now, "Long Date")
Dim dayofweek = todaysdate.Substring(0, todaysdate.IndexOf(","))
Dim year As String = Now.Year
Dim datecheck As String = "12/29/"
Dim datecheck1 As String = "12/30/"
Dim datecheck2 As String = "12/31/"
' Add Current Year to Date to Check variables
datecheck = datecheck + year
datecheck1 = datecheck1 + year
datecheck2 = datecheck2 + year
Dim expenddt As Date = Date.ParseExact(date1, date1, System.Globalization.DateTimeFormatInfo.InvariantInfo)
Dim expenddt1 As Date = Date.ParseExact(datecheck, datecheck,
System.Globalization.DateTimeFormatInfo.InvariantInfo)
Dim expenddt2 As Date = Date.ParseExact(datecheck1, datecheck1,
System.Globalization.DateTimeFormatInfo.InvariantInfo)
Dim expenddt3 As Date = Date.ParseExact(datecheck2, datecheck2,
System.Globalization.DateTimeFormatInfo.InvariantInfo)
' If DEC 29 or 30 Falls Fiday, Display Reset Button
If date1 = datecheck And dayofweek = "Friday" Then
' MsgBox Used Only For Testing
MsgBox("THIS ONE WORKED!")
Form2.Reset.Visible = True
End If
If date1 = datecheck1 And dayofweek = "Friday" Then
' MsgBox Used Only For Testing
MsgBox("THIS ONE WORKED!!")
Form2.Reset.Visible = True
End If
' If it's Dec 31 and it's Not Saturday or Sunday, Display Reset Button
If date1 = datecheck2 and dayofweek <> "Saturday" and dayofweek <> "Sunday" Then
' MsgBox Used Only For Testing
MsgBox("THIS ONE WORKED!!!")
Form2.Reset.Visible = True
End If
End Sub
First things first, have a read through the documentation for the DateTime structure. You can do everything that you're trying to do without using Strings. The DateTime structure has a DayOfWeek property, and Month and Day properties that will help you here.
Secondly, the way you are using the ParseExact method is wrong (not that you should end up using it). The second parameter to the ParseExact method is the format string that you expect the date to be in (something like "MM/dd/yyyy"). Passing in a formatted date will not work, and from my experiments, will simply return the current date without any parsing occurring.
So, with all that in mind (and assuming you want to show the button on the last weekday in the year as your code suggests, and not just the last day in the year as your question stated), try something like this:
Private Sub Main_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Form2.Reset.Visible = ShouldShowResetButton(DateTime.Now)
End Sub
Private Function ShouldShowResetButton(currentDate As DateTime) As Boolean
Return GetLastWeekdayInYear(currentDate.Year) = currentDate.Date
End Function
Private Function GetLastWeekdayInYear(year As Integer) As Date
Dim lastDayInYear As Date
lastDayInYear = New Date(year, 12, 31)
Select Case lastDayInYear.DayOfWeek
Case DayOfWeek.Sunday
Return New Date(year, 12, 29)
Case DayOfWeek.Saturday
Return New Date(year, 12, 30)
Case Else
Return lastDayInYear
End Select
End Function
Related
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
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
I am very new to VBA, so please bear with me. I have a userform that is going to eventually create a 2 or 6 week schedule look ahead. The userform has a textbox which automatically populates the Monday of the current week as the lookahead start date. If the user inputs a date, it will use that date as the lookahead start date instead.
The part I can't seem to figure out, is the formula so that when the user inputs a date, it calculates the Monday of that week.
The code:
Private Sub UserForm_Initialize()
'Inserts date of Monday this week into "Start Date" field in UserForm
LookAheadDate1.Value = Date - Weekday(Date) + 2
End Sub
Private Sub Generate_Click()
Dim StartDate As Date
Dim EndDate As Date
Dim ws As Worksheet
Dim addme As Long
Set ws = Worksheets("Projects")
addme = ws.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
' Clears Look Ahead sheet - Row 5 and below
With Sheets("Look Ahead")
.Rows(5 & ":" & .Rows.Count).Delete
End With
'Force user to select either option button
If ((Me.OptionButton1.Value = 0) * (Me.OptionButton2.Value = 0)) Then
MsgBox "Please select 2 or 6 Week Look Ahead"
End If
'Force user to select either option button
If ((Me.OptionButton1.Value)) Then
ThisWorkbook.Worksheets("Look Ahead").Range("E6").Value = "2 Week Look Ahead"
End If
If ((Me.OptionButton2.Value)) Then
ThisWorkbook.Worksheets("Look Ahead").Range("E6").Value = "6 Week Look Ahead"
End If
' Set StartDate Variable - If Start Date field value is blank, use this weeks start date, otherwise use start date field value
If IsNull(Me.LookAheadDate1.Value) Or Me.LookAheadDate1.Value = "" Then
StartDate = Date
Else
StartDate = LookAheadDate1.Value
End If
' Option buttons / Code to create end date for 2 or 6 week look ahead
Dim res As Date
If OptionButton1.Value Then
EndDate = StartDate - Weekday(Date) + 16
ElseIf OptionButton2.Value Then
EndDate = StartDate - Weekday(Date) + 44
End If
'Write Look Ahead date range in cell "E7"
ThisWorkbook.Worksheets("Look Ahead").Range("E7").Value = StartDate - Weekday(Date) + 2 & " to " & EndDate
'Clear all fields in UserForm
Dim oneControl As Object
For Each oneControl In ProjectData.Controls
Select Case TypeName(oneControl)
Case "TextBox"
oneControl.Text = vbNullString
Case "CheckBox"
oneControl.Value = False
End Select
Next oneControl
'Close UserForm.
Unload Me
End Sub
Private Sub ToggleButton1_Click()
End Sub
Private Sub UserForm_Click()
End Sub
Private Sub LookAheadDate1_Change()
End Sub
Private Sub Cancel_Click()
'Close UserForm if "Cancel" Button is pressed
Unload Me
End Sub
'Checks for entry of valid date
Private Sub LookAheadDate1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
If LookAheadDate1 = vbNullString Then Exit Sub
If IsDate(LookAheadDate1) Then
LookAheadDate1 = Format(LookAheadDate1, "Short Date")
Else
MsgBox "Please Enter Valid Date"
Cancel = True
End If
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
'If the user clicks the "X" to close the UserForm, then cancel
If CloseMode = 0 Then Cancel_Click
End Sub
If I understand your question about the date correctly, you want to edit this block of your code:
If IsNull(Me.LookAheadDate1.Value) Or Me.LookAheadDate1.Value = "" Then
StartDate = Date ' <--- this is where you want Monday, right?
Else
StartDate = LookAheadDate1.Value
End If
If so, replace the marked line with
StartDate = Date - Application.WorksheetFunction.Weekday(Date,3)
to get the date of Monday of this week as the StartDate.
Date returns the current date (similar to Now, but without the time part)
The use of Weekday (=WEEKDAY()) to get Monday is from this answer by Paul
Edit
In the Else branch:
Dim enteredDate as Date
enteredDate = CDate(LookAheadDate1.Value)
StartDate = enteredDate - Application.WorksheetFunction.Weekday(enteredDate,3)
CDate converts from text to date according to the current locale. You may need to parse the date text manually if you need a more sophisticated conversion.
I believe LookAheadDate1 is a text box because I see you are giving it a value using Format(..., "Short Date"). If it is a date/time picker, you may not need the CDate call.
I got it working. I added a calendar date picker to input the date into the textbox. Thanks for the help!
I'm having an issue with DateTimePicker.
What I am currently trying to do is based off of what text is in lblPrevSem(Previous Semester), which is getting its selection from a drop down on a previous screen, i want to add a certain amount of time to the DateTimePicker.
Public Property CustomFormat As String
Dim SemesterMonths As Integer
Dim SemesterDays As Integer
Private Sub DeptCreatePrevSch_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim SemesterYear() As String = DeptPrevSch.CboSem.Text.Split(",")
lblPrevSem.Text = SemesterYear(0)
cboYear.Text = Date.Now.Year
For i As Integer = 0 To 5
cboYear.Items.Add(Date.Now.Year + i)
cboYear.SelectedIndex = 0
Next
If InStr(lblPrevSem.Text, "Fall") Then
SemesterMonths = 1
ElseIf InStr(lblPrevSem.Text, "Spring") Then
SemesterMonths = 1
ElseIf InStr(lblPrevSem.Text, "Summer") Then
SemesterDays = 14
End If
Call dtpStart_ValueChanged(sender, e)
End Sub
Private Sub dtpStart_ValueChanged(sender As Object, e As EventArgs) Handles dtpStart.ValueChanged
Dim StartDate As Date
Dim StartStringDate As String
Dim EndDate As Date
Dim EndStringDate As String
dtpStart.Format = DateTimePickerFormat.Custom
dtpStart.CustomFormat = "MMMM dd, yyyy dddd"
StartDate = dtpStart.Value.ToString
StartStringDate = StartDate.ToString("MMMM dd, yyyy dddd")
lblRegStartDate.Text = StartStringDate
EndDate = dtpStart.Value.AddMonths(SemesterMonths)
EndDate = dtpStart.Value.AddDays(SemesterDays)
EndStringDate = EndDate.ToString("MMMM dd, yyyy dddd")
lblRegEndDate.Text = EndStringDate
End Sub
I can get it to add in days just fine but when ever i try and add in 1 month, it doesn't seem to work at all.
I've tried multiple different ways to add in a 1 month but nothing so far has worked. The closet ive been was adding in 30 days but then that doesn't account for months that have 31 days.
Reg Start Date is what ever the DateTimePicker is and Reg End Date should be the added days based off of what lblPrevSem is
Both Reg Start/End Date are displayed as labels
(i.e. Fall = 1 Month, Spring = 1 Month, Summer = 2 Weeks)
Your problem is that you are resetting the value for EndDate after adding the SemesterMonths value. You should add the SemesterDays value to the EndDate variable, not reset the value of EndDate with dtpStart.Value.AddDays(SemesterDays):
EndDate = dtpStart.Value.AddMonths(SemesterMonths)
EndDate = EndDate.AddDays(SemesterDays)
Just get the datetimepicker value and put .AddYears(0) or .AddDays(0) or AddMonths(0) behind it.
But you can also use them all at the same time.
nextServiceDateTimePicker.Value.AddYears(0).AddDays(0).AddMonths(0);
Just replace the 0 with lets say i and give it the value you need it to be.
I am trying to valid user input in a textbox which will only takes dates or an empty value (hence the textbox vs a date time picker). Here are the conditions:
Only a date value ("dd-mm-yyyy" or "dd-mm-yy)
Must contain only slashes or numbers
The date has to be on the day it is being typed in
This is what I have so far:
Private Sub tbApp1_TextChanged(sender As System.Object, e As System.EventArgs) Handles tbApp1.TextChanged
If Not Me.tbApp1.Text = String.Empty Then
If Not DateTime.TryParseExact(tbApp1.Text.Trim, formats, New Globalization.CultureInfo("en-US"), Globalization.DateTimeStyles.None, dtTemp) Then
If Not tbApp1.Text.Trim = DateTime.Today.Date Then
ErrorProvider1.SetError(tbApp1, "This is not a valid date; Enter in this format ('M/d/yyyy' or 'M/d/yy')")
End If
Else
ErrorProvider1.Clear()
End If
ElseIf Me.tbApp1.Text.Trim = "" Then
ErrorProvider1.Clear()
End If
End Sub
Masked Textbox use
'Private Sub mtbApp1_TypeValidationCompleted(ByVal sender As Object, ByVal e As TypeValidationEventArgs) Handles mtbApp1.TypeValidationCompleted
If Not Me.mtbApp1.Text = String.Empty Then
If (Not e.IsValidInput) Then
ErrorProvider1.SetError(mtbApp1, "The data you supplied must be a valid date in the format mm/dd/yyyy.")
Else
' Now that the type has passed basic type validation, enforce more specific type rules.
Dim UserDate As DateTime = CDate(e.ReturnValue)
If (UserDate = DateTime.Now) Then
ErrorProvider1.SetError(mtbApp1, "The data you supplied must be today's date")
e.Cancel = True
End If
End If
ErrorProvider1.Clear()
End If
End Sub'
I noticed for a date like 03/18/2014 when it loaded back into the masked textbox it converts to 31/82/014. How could i fix this? The query pulls back the field as
CONVERT(VARCHAR(10),Date,101) AS Date
I set it in vb as :
Dim Approval1 As Date = Nothing
and then
If Not IsDBNull(((WorklistsDS.Tables(0).Rows(0).Item("Approval1")))) Then
Approval1 = ((WorklistsDS.Tables(0).Rows(0).Item("Approval1")))
End If
and then loaded into the masked textbox as:
If Approval1 <> Nothing Then
Me.mtbApp1.Text = Approval1
End If
You could also simplify your validation with
If IsDate(tbApp1.Text) Then
'valid date now just check if date falled within permitted range
Dim CompDate As Date = CDate(tbApp1.Text)
Dim MidDate As Date = *enter your min date here*
Dim MaxDate As Date = *enter your max date here*
If CompDate >= MinDate AndAlso CompDate <= MaxDate Then
'Date is within permitted range
......
Else
'Date outside range
'Display error
End If
Else
'text in tbApp1 is not a date
'Display Error
End If