calculate date add, but only weekdays - vb.net

I would like to calculate a new date simply by using the build-in dateadd function, but take into account that only weekdays should be counted (or 'business days' so to speak).
I have come up with this simple algorithm, which does not bother about holidays and such. I have tested this with some simple dates, but would like some input if this can be done in better ways.
This sample assumes a week with 5 business days, monday-friday, where first day of the week is monday. Dateformatting used here is d-m-yyyy, the sample calculates with a startdate of october 1, 2009.
Here is the simple form:
Dim d_StartDate As DateTime = "1-10-2009"
Dim i_NumberOfDays As Integer = 12
Dim i_CalculateNumberOfDays As Integer
If i_NumberOfDays > (5 - d_StartDate.DayOfWeek) Then
i_CalculateNumberOfDays = i_NumberOfDays
Else
i_CalculateNumberOfDays = i_NumberOfDays + (Int(((i_NumberOfDays + (7 - d_StartDate.DayOfWeek)) / 5)) * 2)
End If
MsgBox(DateAdd(DateInterval.Day, i_CalculateNumberOfDays, d_StartDate))
Which I try to explain with the following piece of code:
''' create variables to begin with
Dim d_StartDate as Date = "1-10-2009"
Dim i_NumberOfDays as Integer = 5
''' create var to store number of days to calculate with
Dim i_AddNumberOfDays as Integer
''' check if amount of businessdays to add exceeds the
''' amount of businessdays left in the week of the startdate
If i_NumberOfDays > (5 - d_StartDate.DayOfWeek) Then
''' start by substracting days in week with the current day,
''' to calculate the remainder of days left in the current week
i_AddNumberOfDays = 7 - d_StartDate.DayOfWeek
''' add the remainder of days in this week to the total
''' number of days we have to add to the date
i_AddNumberOfDays += i_NumberOfDays
''' divide by 5, because we need to know how many
''' business weeks we are dealing with
i_AddNumberOfDays = i_AddNumberOfDays / 5
''' multiply the integer of current business weeks by 2
''' those are the amount of days in the weekends we have
''' to add to the total
i_AddNumberOfDays = Int(i_AddNumberOfDays) * 2
''' add the number of days to the weekend days
i_AddNumberOfDays += i_NumberOfDays
Else
''' there are enough businessdays left in this week
''' to add the given amount of days
i_AddNumberOfDays = i_NumberOfDays
End If
''' this is the numberof dates to calculate with in DateAdd
dim d_CalculatedDate as Date
d_CalculatedDate = DateAdd(DateInterval.Day, i_AddNumberOfDays, d_StartDate)
Thanks in advance for your comments and input on this.

I used the .DayOfWeek function to check if it was a weekend. This does not include holiday implementation. It has been tested. I realize this question is old but the accepted answer didn't work. However, I did like how clean it was so I thought I'd update it and post. I did change the logic in the while loop.
Function AddBusinessDays(startDate As Date, numberOfDays As Integer) As Date
Dim newDate As Date = startDate
While numberOfDays > 0
newDate = newDate.AddDays(1)
If newDate.DayOfWeek() > 0 AndAlso newDate.DayOfWeek() < 6 Then '1-5 is Mon-Fri
numberOfDays -= 1
End If
End While
Return newDate
End Function

Public Shared Function AddBusinessDays(ByVal startDate As DateTime, _
ByVal businessDays As Integer) As DateTime
Dim di As Integer
Dim calendarDays As Integer
'''di: shift to Friday. If it's Sat or Sun don't shift'
di = (businessDays - Math.Max(0, (5 - startDate.DayOfWeek)))
''' Start = Friday -> add di/5 weeks -> end = Friday'
''' -> if the the remaining (<5 days) is > 0: add it + 2 days (Sat+Sun)'
''' -> shift back to initial day'
calendarDays = ((((di / 5) * 7) _
+ IIf(((di Mod 5) <> 0), (2 + (di Mod 5)), 0)) _
+ (5 - startDate.DayOfWeek))
Return startDate.AddDays(CDbl(calendarDays))
End Function

Your plan seems like it should work. Make sure you wrap it in a function instead of doing out the calculations every place you use it so that if/when you discover you need to account for holidays, you don't have to change it in tons of places.
The best way I can think of for implementing support for holidays would be to add days one at a time in a loop. Each iteration, check if its a weekend or a holiday, and if it is add another day and continue (to skip it). Below is an example in pseudocode (I don't know VB); no guarantees its correct. Of course, you need to provide your own implementations for isWeekend() and isHoliday().
function addBusinessDays(startDate, numDays)
{
Date newDate = startDate;
while (numDays > 0)
{
newDate.addDays(1);
if (newDate.isWeekend() || newDate.isHoliday())
continue;
numDays -= 1;
}
return newDate;
}
My first thought for the holiday thing was to simply look up the number of holidays between the start date and the end date and add that to your calculation, but of course this won't work because the end date is dependent on the number of holidays in that interval. I think an iterative solution is the best you'll get for holidays.

I'm using this code to calculate the date:
dayOfWeek = startDate.DayOfWeek
weekendDays = 2 * Math.Floor((dayOfWeek + businessDays - 0.1) / 5)
newDate = startDate.AddDays(businessDays + weekendDays)
The second line computes the number of full weekends that we have to add and then multiplies them by 2 to obtain the number of days.
The additional -0.1 constant is used to avoid adding days if (dayOfWeek + businessDays) is multiple of 5, and final date is friday.

Private Function AddBusinessDays(ByVal dtStartDate As DateTime, ByVal intVal As Integer) As DateTime
Dim dtTemp As DateTime = dtStartDate
dtTemp = dtStartDate.AddDays(intVal)
Select Case dtTemp.DayOfWeek
Case 0, 6
dtTemp = dtTemp.AddDays(2)
End Select
AddBusinessDays = dtTemp
End Function

please check this code for adding working days
Dim strDate As Date = DateTime.Now.Date
Dim afterAddDays As Date
Dim strResultDate As String
Dim n As Integer = 0
For i = 1 To 15
afterAddDays = strDate.AddDays(i)
If afterAddDays.DayOfWeek = DayOfWeek.Saturday Or afterAddDays.DayOfWeek = DayOfWeek.Sunday Then
n = n + 1
End If
Next
strResultDate = afterAddDays.AddDays(n).ToShortDateString()

Private Function AddXWorkingDays(noOfWorkingDaysToAdd As Integer) As Date
AddXWorkingDays = DateAdd(DateInterval.Weekday, noOfWorkingDaysToAdd + 2, Date.Today)
If Weekday(Today) + noOfWorkingDaysToAdd < 6 Then AddXWorkingDays = DateAdd(DateInterval.Weekday, 2, Date.Today)
End Function

One approach would be to iterate from the start date and add or subtract one day with each iteration if the date is not a Saturday or Sunday. If zero is passed as iAddDays then the function will return dDate even if that date is a Saturday or Sunday. You could play around with the logic to get the outcome you are looking for if that scenario is a possibility.
Public Function DateAddWeekDaysOnly(ByVal dDate As DateTime, ByVal iAddDays As Int32) As DateTime
If iAddDays <> 0 Then
Dim iIncrement As Int32 = If(iAddDays > 0, 1, -1)
Dim iCounter As Int32
Do
dDate = dDate.AddDays(iIncrement)
If dDate.DayOfWeek <> DayOfWeek.Saturday AndAlso dDate.DayOfWeek <> DayOfWeek.Sunday Then iCounter += iIncrement
Loop Until iCounter = iAddDays
End If
Return dDate
End Function

Easy way
function addWerktage($date,$tage){
for($t=0;$t<$tage;$t++){
$date = $date + (60*60*24);
if(date("w",$date) == 0 || date("w",$date) == 6){ $t--; }
}
return $date;
}

This produces the same result as the accepted answer, including starting on weekends, while handling negative offsets and without looping. It's written in c# but should work in any enviroment where numeric weekdays start at Sunday and end at Saturday, and where integer division rounds to 0.
public static DateTime AddWeekdays(DateTime date, int offset)
{
if (offset == 0)
{
return date;
}
// Used to calculate the number of weekend days skipped over
int weekends;
if (offset > 0)
{
if (date.DayOfWeek == DayOfWeek.Saturday)
{
// Monday is 1 weekday away, so it will take an extra day to reach the next weekend
int daysSinceMonday = -1;
// Add two weekends for every five days
int normalWeekends = (offset + daysSinceMonday) / 5 * 2;
// Add one for this Sunday
int partialWeekend = 1;
weekends = normalWeekends + partialWeekend;
}
else
{
// It will take this many fewer days to reach the next weekend.
// Note that this works for Sunday as well (offset -1, same as above)
int daysSinceMonday = date.DayOfWeek - DayOfWeek.Monday;
// Add two weekends for every five days (1 business week)
weekends = (offset + daysSinceMonday) / 5 * 2;
}
}
else
{
// Same as the positive offset case, but counting backwards.
// daysSinceFriday will be 0 or negative, except for Saturday, which is +1
int daysSinceFriday = date.DayOfWeek - DayOfWeek.Friday;
weekends = date.DayOfWeek == DayOfWeek.Sunday
? (offset + 1) / 5 * 2 - 1
: (offset + daysSinceFriday) / 5 * 2;
}
return date.AddDays(offset + weekends);
}
Since the pattern of 2 extra days per 5 days repeats after a full week, you can effectively exhaustively test it:
private static DateTime AddWeekdaysLooping(DateTime date, int offset)
{
DateTime newDate = date;
int step = Math.Sign(offset);
while (offset != 0)
{
newDate = newDate.AddDays(step);
if (newDate.DayOfWeek != DayOfWeek.Sunday && newDate.DayOfWeek != DayOfWeek.Saturday)
{
offset -= step;
}
}
return newDate;
}
void TestWeekdays()
{
DateTime initial = new DateTime(2001, 1, 1);
for (int day = 0; day < 7; day += 1)
{
for (int offset = -25; offset <= 25; offset += 1)
{
DateTime start = initial.AddDays(day);
DateTime expected = AddWeekdaysLooping(start, offset);
DateTime actual = AddWeekdays(start, offset);
if (expected != actual) {
throw new Exception($"{start.DayOfWeek} + {offset}: expected {expected:d}, but got {actual:d}");
}
}
}
}

Dim result As Date
result = DateAdd("d", 2, Today)
If result.DayOfWeek = DayOfWeek.Saturday Then
result = DateAdd("d", 2, result)
MsgBox(result)
ElseIf result.DayOfWeek = DayOfWeek.Sunday Then
result = DateAdd("d", 1, result)
MsgBox(result)
ElseIf result.DayOfWeek = DayOfWeek.Monday Then
MsgBox(result)
ElseIf result.DayOfWeek = DayOfWeek.Tuesday Then
MsgBox(result)
ElseIf result.DayOfWeek = DayOfWeek.Wednesday Then
MsgBox(result)
ElseIf result.DayOfWeek = DayOfWeek.Thursday Then
MsgBox(result)
ElseIf result.DayOfWeek = DayOfWeek.Friday Then
MsgBox(result)
End If

Related

vb.net find 4th Wednesday of month with visual basic

I am trying to find the fourth Wednesday of the current Month and Year when a form loads
I have converted numerous C# code to Visual Basic with no results
Would someone explain what is wrong with this code OR explain how to accomplish this in VB Code
Private Sub SurroundingSub()
Dim thisDate As Date = Today
tbMonth.Text = thisDate.ToString("MMMM")
tbYear.Text = thisDate.ToString("yyyy")
Dim month As Integer
month = tbMonth.Text
Dim year As Integer
year = tbYear.Text
Dim fourthWed As Date = New Date(year, month, 4)
tbFour.Text = fourthWed.ToLongDateString
While fourthWed.DayOfWeek <> DayOfWeek.Wednesday
fourthWed = fourthWed.AddDays(1)
tbFour.Text = fourthWed.ToShortDateString
End While
End Sub
This is a JavaFX statement that I am trying to implement in VB.Net
if(TorF.equals("F") && today.isAfter(fourthTUEofMONTH))
This sets the date
public void setDATES() throws IOException, SQLException{
today = LocalDate.now();
fourthTUEofMONTH = LocalDate.now();
fourthTUEofMONTH = fourthTUEofMONTH.with(TemporalAdjusters.dayOfWeekInMonth(4, DayOfWeek.TUESDAY));
endMONTH = LocalDate.now();
endMONTH = endMONTH.with(TemporalAdjusters.lastDayOfMonth());
}
For a more general solution, with my function you can easily find the first, second, third, forth or fifth sunday, monday, tuesday, wednesday or whatever you want:
Public Function GetXDayOfWeek(Day As DateTime,
DayOfWeek As DayOfWeek,
Optional Index As Integer = 1) As DateTime
Dim First As New Date(Day.Year, Day.Month, 1)
Dim Diff As Integer = (DayOfWeek - First.DayOfWeek + 7) Mod 7
Return First.AddDays(Diff + (Index - 1) * 7)
End Function
So if you want to find the forth wednesday of the current month, use it like:
Dim DateToFind As DateTime = GetXDayOfWeek(Today, DayOfWeek.Wednesday, 4)
Your while statement will stop on the first Wednesday it finds, not the fourth. Keep track of the number of Wednesdays you encounter as you iterate and once you find the fourth then you can update tbFour.
Also as mentioned in the comments you'll want to start at the first day of the year.
Dim fourthWed As Date = New Date(year, month, 1)
Dim wednesdayCursor As Integer = 0
While wednesdayCursor < 4
If fourthWed.DayOfWeek = DayOfWeek.Wednesday Then
wednesdayCursor += 1
End If
fourthWed = fourthWed.AddDays(1)
End While
'Subtract one day because we added one on loop:
fbFour.Text = fourthWed.AddDays(-1).ToShortDateString()
You should make the function of getting the fourth Wednesday into a separate method, perhaps generalizing it for any day of the week, but just for the fourth Wednesday...
Module Module1
Function FourthWedOfMonth(dt As DateTime) As Integer
Dim currDate = New DateTime(dt.Year, dt.Month, 1)
Dim nWednesdays = 0
While nWednesdays < 4
If currDate.DayOfWeek = DayOfWeek.Wednesday Then
nWednesdays += 1
End If
currDate = currDate.AddDays(1)
End While
Return currDate.Day - 1
End Function
Sub Main()
For mo = 1 To 12
Console.Write(FourthWedOfMonth(New DateTime(2020, mo, 17)) & " ")
Next
Console.ReadLine()
End Sub
End Module
Outputs the correct days for 2020:
22 26 25 22 27 24 22 26 23 28 25 23
If you wanted the DateTime of the fourth Wednesday, you could
Function FourthWedOfMonth(dt As DateTime) As DateTime
Dim currDate = New DateTime(dt.Year, dt.Month, 1)
Dim nWednesdays = 0
While nWednesdays < 4
If currDate.DayOfWeek = DayOfWeek.Wednesday Then
nWednesdays += 1
End If
currDate = currDate.AddDays(1)
End While
Return New DateTime(dt.Year, dt.Month, currDate.Day - 1)
End Function
and then Console.WriteLine(FourthWedOfMonth(DateTime.Today).ToString("dd-MMM-yyyy")) would output "22-Jul-2020" (at the time of writing).
I'd find the fourth Wednesday of the current month this way:
Private Sub FourthWednesdayOfCurrentMonth()
Dim firstOfMonth As DateTime = DateTime.Today.AddDays(-1 * (DateTime.Today.Day - 1))
Dim firstWednesday As DateTime = firstOfMonth.AddDays((7 + (DayOfWeek.Wednesday - firstOfMonth.DayOfWeek)) Mod 7)
Dim fourthWednesday As DateTime = firstWednesday.AddDays(21)
tbYear.Text = fourthWednesday.Year
tbMonth.Text = fourthWednesday.Month
tbFour.Text = fourthWednesday.Day
End Sub
Written generically for any day of the week, that would change to:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim fourthWednesday As DateTime = FourthWeekDayOfCurrentMonth(DayOfWeek.Wednesday)
tbYear.Text = fourthWednesday.Year
tbMonth.Text = fourthWednesday.Month
tbFour.Text = fourthWednesday.Day
End Sub
Private Function FourthWeekDayOfCurrentMonth(ByVal WeekDay As DayOfWeek) As DateTime
Dim firstOfMonth As DateTime = DateTime.Today.AddDays(-1 * (DateTime.Today.Day - 1))
Dim firstWeekday As DateTime = firstOfMonth.AddDays((7 + (WeekDay - firstOfMonth.DayOfWeek)) Mod 7)
Return firstWeekday.AddDays(21)
End Function

Special date formatted string to Date (VB.net)

If i have a string containing a date formatted like this:
1402-3
which means Year: 2014, Week: 02 and Day number 3 (monday is 1), how can i convert this to a normal date? (in this case the date above is today; 2014-01-08 - wednesday 8 jan 2014)
Edit: I came up with a function like this, can anyone tell if this is gonna fail or maybe have a better and better coded function/solution?
Private Function StrangeFormattedDateToRegularDate(ByVal StrangeDate As String) As Date
Dim Y As String = "20" & StrangeDate.Substring(0, 2) 'I'll be dead before this fails, haters gonna hate
Dim W As String = StrangeDate.Substring(2, 2)
Dim D As String = StrangeDate.Substring(5, 1)
'Get first day of this year
Dim RefDate As Date = New Date(CInt(Y), 1, 1)
'Get the first day of this week (can be the year before)
Dim daysOffSet As Integer = DayOfWeek.Monday - RefDate.DayOfWeek
RefDate = RefDate.AddDays(daysOffSet)
'Add as many days as the weeks is
RefDate = RefDate.AddDays(7 * CInt(W))
'now the date is the last day of this week (plus one day), remove the days that are ahead, and remove that extra day
Dim daysToRemove = ((7 - CInt(D)) * -1) - 1
RefDate = RefDate.AddDays(daysToRemove)
Return RefDate
End Function
This should be what you're looking for :) This looked challenging so I tried it. Tell me if it works for you or not :)
Function GetDate(InputDate As String) As DateTime
Dim FirstDayofYear As Date = CType("1/1/20" & Mid(InputDate, 1, 2), Date)
Dim LastDayofYear As Date = CType("12/31/20" & Mid(InputDate, 1, 2), Date)
Dim target As Date
For x = 0 To DateDiff(DateInterval.Day, FirstDayofYear, LastDayofYear)
Dim dfi = DateTimeFormatInfo.CurrentInfo
Dim calendar = dfi.Calendar
Dim weekOfyear = calendar.GetWeekOfYear(FirstDayofYear.AddDays(x), dfi.CalendarWeekRule, DayOfWeek.Sunday)
If CInt(Mid(InputDate, 3, 2)) = weekOfyear And CInt(Mid(InputDate, InStr(InputDate, "-") + 1)) = FirstDayofYear.AddDays(x).DayOfWeek Then
target = FirstDayofYear.AddDays(x)
GoTo skip
End If
Next x
skip:
Return target
End Function
This works up to Year 2099. We're probably all dead by then.

Get the number of months between two DateTimes

mnth = DateDiff(DateInterval.Month, 8/30/2012, 10/1/2012)
gives mnth = 2. But when we look, there is only 32 days between these dates. I am expecting a result mnth=1 as there is only 32 days between these days.
Pls help..
In my scenario i can consider a 15+ days to be a month but if it is less than 15, it should'nt be considered.
To get the number of complete months you can do different things depending on your interpretation,
Public Function CompleteMonthsBetweenA( _
ByVal start As DateTime, _
ByVal end As DateTime) As Integer
Dim invertor = 1
If (start > end) Then
Dim tmp = end
end = start
start = tmp
invertor = -1
End If
Dim diff = ((end.Year - start.Year) * 12) + end.Month - start.Month
If start.Day > end.Day Then
Return (diff - 1) * invertor
Else
Return diff * invertor
End If
End Function
With this function the number of complete months between 31/05/2011 (dd/mm/yy) and 30/06/2011 is 0 but between 30/06/2011 and 31/07/2011 is 1. Which may or may not be what you expect.
Public Function CompleteMonthsBetweenB( _
ByVal start As DateTime, _
ByVal end As DateTime) As Integer
Dim invertor = 1
If (start > end) Then
Dim tmp = end
end = start
start = tmp
invertor = -1
End If
Dim diff = ((end.Year - start.Year) * 12) + end.Month - start.Month
Dim startDaysInMonth = DateTime.DaysInMonth(start.Year, start.Month)
Dim endDaysInMonth = DateTime.DaysInMonth(end.Year, end.Month)
If (start.Day / startDaysInMonth) > (end.Day / endDaysInMonth) Then
Return (diff - 1) * invertor
Else
Return diff * invertor
End If
End Function
With this function the ratio Day / DaysInMonth is taken so the relative completion of the two months can be assessed.
Public Function CompleteMonthsBetweenC( _
ByVal start As DateTime, _
ByVal enddate As DateTime) As Integer
Dim invertor = 1
If (start > enddate) Then
Dim tmp = enddate
enddate = start
start = tmp
invertor = -1
End If
Dim diff = ((enddate.Year - start.Year) * 12) + enddate.Month - start.Month
Dim remainingDays = _
(DateTime.DaysInMonth(start.Year, start.Month) - start.Day) + enddate.Day
If remainingDays < 15 Then
Return (diff - 1) * invertor
Else
Return diff * invertor
End If
End Function
This function only rounds down if the surplus days are less than the magic number 15, which I think is what you are asking for in your update.
Public Function CompleteMonthsBetweenD( _
ByVal start As DateTime, _
ByVal end As DateTime) As Integer
Return end.Subtract(start).TotalDays \ 30.436875
End Function
This function takes the simpler approach of dividing the total number of days by the average number of days per month in the Gregorian Calendar.
The difference in months is calculated without regard to the day component of the dates.
For example, the difference in months between 8/31/2012 and 9/1/2012 is 1, eventhough it's only one day between the dates.
If you want to consider the day component you have to get the date difference in days instead of months, and calculate how many months you want that to be.
This is the class I use (it's C# but really easy to convert to VB.NET).
It is usefull for years, months, days... it is ideal for displaying ages in #Y-#M-#D format.
public class DateDifference
{
/// <summary>
/// defining Number of days in month; index 0=> january and 11=> December
/// february contain either 28 or 29 days, that's why here value is -1
/// which wil be calculate later.
/// </summary>
private int[] monthDay = new int[12] { 31, -1, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
/// <summary>
/// contain from date
/// </summary>
private DateTime fromDate;
/// <summary>
/// contain To Date
/// </summary>
private DateTime toDate;
/// <summary>
/// this three variable for output representation..
/// </summary>
private int year;
private int month;
private int day;
public DateDifference(DateTime d1, DateTime d2)
{
int increment;
if (d1 > d2)
{
this.fromDate = d2;
this.toDate = d1;
}
else
{
this.fromDate = d1;
this.toDate = d2;
}
///
/// Day Calculation
///
increment = 0;
if (this.fromDate.Day > this.toDate.Day)
{
increment = this.monthDay[this.fromDate.Month - 1];
}
/// if it is february month
/// if it's to day is less then from day
if (increment == -1)
{
if (DateTime.IsLeapYear(this.fromDate.Year))
{
// leap year february contain 29 days
increment = 29;
}
else
{
increment = 28;
}
}
if (increment != 0)
{
day = (this.toDate.Day + increment) - this.fromDate.Day;
increment = 1;
}
else
{
day = this.toDate.Day - this.fromDate.Day;
}
///
///month calculation
///
if ((this.fromDate.Month + increment) > this.toDate.Month)
{
this.month = (this.toDate.Month + 12) - (this.fromDate.Month + increment);
increment = 1;
}
else
{
this.month = (this.toDate.Month) - (this.fromDate.Month + increment);
increment = 0;
}
///
/// year calculation
///
this.year = this.toDate.Year - (this.fromDate.Year + increment);
}
public override string ToString()
{
//return base.ToString();
return this.year + " Year(s), " + this.month + " month(s), " + this.day + " day(s)";
}
public int Years
{
get
{
return this.year;
}
}
public int Months
{
get
{
return this.month;
}
}
public int Days
{
get
{
return this.day;
}
}
}
USAGE:
DateDifference diff = new DateDifference(date1, date2);
int months = (diff.Years*12) + diff.Months + diff.Days > 15 ? 1 : 0;
If you want the number of complete month, then you'll need to compare date that starts at the begining of the closet month.
Sub Main()
' mnth = DateDiff(DateInterval.Month, 8/30/2012, 10/1/2012)
Console.WriteLine(GetCompleteMonthCount(New DateTime(2012, 8, 30), New DateTime(2012, 10, 1)))
Console.ReadLine()
End Sub
Public Function GetCompleteMonthCount(ByVal d1 As DateTime, ByVal d2 As DateTime) As Integer
If d1.Day <> 1 Then
d1 = d1.AddMonths(1)
d1 = New DateTime(d1.Year, d1.Month, 1)
End If
If d2.Day <> 1 Then
d2 = New DateTime(d2.Year, d2.Month, 1)
End If
Return DateDiff(DateInterval.Month, d1, d2)
End Function
The solutions above are all very good but perhaps a little over-complicated, how about
Function wholeMonthsEd(d1, d2) As Integer
' determine the DateDiff function output
' which gives calendar month difference
initMonths = DateDiff("m", d1, d2)
' do calcs on the Day of the month to deduct/not a calendar month
If Day(d2) < Day(d1) Then
initMonths = initMonths - 1
End If
wholeMonths = initMonths
End Function

VB.NET - counting days between two dates with exclusions

I'm trying to count the days between two dates, excluding Saturdays and Sundays. I've written this code so far
Dim startDay As Integer
Dim endDay As Integer
Dim days As Integer
Dim count As Integer
startDay = dtpStartDate.Value.DayOfWeek
endDay = dtpEndDate.Value.DayOfWeek
For days = startDay To endDay
If days = 0 Or days = 6 Then 'Sunday = 0, Saturday = 6
count += 1
End If
Next
lblNoOfDays.Text = count
It works fine if you choose the two dates within the same week. (ex: 23rd Jan to 27th Jan, gives the result 5)
But if I set them to dates in different weeks, (ex : 23rd Jan to 30th Jan, gives the result 1), it gives incorrect results.
I know it happens because of the loop but I can't think of a way to overcome this. Can anyone give me a suggestion, solution??
Thank you
Dim count = 0
Dim totalDays = (dtpEndDate - dtpStartDate).Days
For i = 0 To totalDays
Dim weekday As DayOfWeek = startDate.AddDays(i).DayOfWeek
If weekday <> DayOfWeek.Saturday AndAlso weekday <> DayOfWeek.Sunday Then
count += 1
End If
Next
lblNoOfDays.Text = count
This function calculates the non-weekend days between two dates:
Public Shared Function WorkingDaysElapsed(ByVal pFromDate As Date, ByVal pToDate As Date) As Integer
Dim _elapsedDays As Integer = 0
Dim _weekendDays As DayOfWeek() = {DayOfWeek.Saturday, DayOfWeek.Sunday}
For i = 0 To (pToDate - pFromDate).Days
If Not _weekendDays.Contains(pFromDate.AddDays(i).DayOfWeek) Then _elapsedDays += 1
Next
Return _elapsedDays
End Function

Finding the date of monday in a week with VB.NET

I need to find a way to find the date (DD/MM/YYYY) of the Monday for any week we're on.
For example, for this week, monday would be 09/11/2009, and if this were next week it'd be 16/11/2009.
I managed to get somewhere in the forms of code, but all I got was 'cannot convert to Integer' errors. I was using Date.Today and AddDays().
Thanks for any help. :)
If Sunday is the first day of week, you can simply do this:
Dim today As Date = Date.Today
Dim dayDiff As Integer = today.DayOfWeek - DayOfWeek.Monday
Dim monday As Date = today.AddDays(-dayDiff)
If Monday is the first day of week:
Dim today As Date = Date.Today
Dim dayIndex As Integer = today.DayOfWeek
If dayIndex < DayOfWeek.Monday Then
dayIndex += 7 'Monday is first day of week, no day of week should have a smaller index
End If
Dim dayDiff As Integer = dayIndex - DayOfWeek.Monday
Dim monday As Date = today.AddDays(-dayDiff)
DateTime.DayOfWeek is an enum that indicates what day a given date is. As Monday is 1, you can find the Monday of the current week using the following code:
Dim monday As DateTime = Today.AddDays((Today.DayOfWeek - DayOfWeek.Monday) * -1)
=Format(DateAdd("d", (-1 * WeekDay(Date.Today()) + 2), Date.Today()), "dd/MM/yyyy")
A simple method should get you what you want:
private static DateTime GetMondayForWeek(DateTime inputDate)
{
int daysFromMonday = inputDate.DayOfWeek - DayOfWeek.Monday;
return inputDate.AddDays(-daysFromMonday);
}
You could also extend it for any day that you want as well:
private static DateTime GetDayForWeek(DateTime inputDate, DayOfWeek inputDay)
{
int daysAway = inputDate.DayOfWeek - inputDay;
return inputDate.AddDays(-daysAway);
}
To call the first example just use something like:
DateTime mondayDate = GetMondayForWeek(new DateTime(2009, 11, 15));
Console.WriteLine(mondayDate);
Another approach if Monday is the first day, is this:
Dim today As Date = Date.Today
Dim dayDiff As Integer = today.DayOfWeek - DayOfWeek.Monday
Dim monday As Date = today.AddDays(-dayDiff)
dayDiff = DayOfWeek.Saturday - today.DayOfWeek + 1
Dim sunday As Date = today.AddDays(dayDiff)
There is a day of week method that you can use
Dim instance As DateTime
Dim value As DayOfWeek
value = instance.DayOfWeek
see: http://msdn.microsoft.com/en-us/library/system.datetime.dayofweek.aspx
I just did this in a project I'm working on --I promise, it's correct. This is a method that returns the nth monday after the given date. If the given date is a monday, it returns the next monday.
Public Function GetSubsequentMonday(ByVal startDate As DateTime, ByVal subsequentWeeks As Integer) As DateTime
Dim dayOfWeek As Integer = CInt(startDate.DayOfWeek)
Dim daysUntilMonday As Integer = (Math.Sign(dayOfWeek) * (7 - dayOfWeek)) + 1
'number of days until the next Monday
Return startDate.AddDays(CDbl((daysUntilMonday + (7 * (subsequentWeeks - 1)))))
End Function
Following on from my comments to Meta-Knight's answer, here is a short function that makes the correction I mention in the comments:
Public Function GetFirstOfLastWeek() As DateTime
Dim today As DateTime, daysSinceMonday As Integer
today = DateTime.Today
daysSinceMonday = today.DayOfWeek - DayOfWeek.Monday
If daysSinceMonday < 0 Then
daysSinceMonday += 7
End If
Return today.AddDays(-daysSinceMonday)
End Function
And if your week starts from Monday then you can use something like this:
DateTime mondayDate = DateTime.Now.AddDays(((DateTime.Now.DayOfWeek == DayOfWeek.Sunday?7: (int)DateTime.Now.DayOfWeek) - 1)*-1);
DateTime sundayDate = DateTime.Now.AddDays(7 - (DateTime.Now.DayOfWeek == DayOfWeek.Sunday?7: (int)DateTime.Now.DayOfWeek ));
Dim dayOfWeek = CInt(DateTime.Today.DayOfWeek)
Dim startOfWeek = DateTime.Today.AddDays(+1 * dayOfWeek).ToShortDateString
Dim endOfWeek = DateTime.Today.AddDays(6 + dayOfWeek).AddSeconds(+1).ToShortDateString
MessageBox.Show(startOfWeek)
MessageBox.Show(endOfWeek)
Example:
If today is 03/09/2020,
startOfWeek will be 07/09/2020 and
endOfWeek will be 13/09/2020.