Calculate difference in month and years between two date in vb.net - vb.net

i have a question for you, my first one. Im trying to calculate the difference in years and months between 2 dates using vb.net. I'm just started working with vb and im new to programming, so i might sound really dumb. This is my expected output:
date1 1/6/2015 date2 1/1/2019 3 years 7 months and so on.
if date2 is < than data1 then the program should return a negative value in months/years. day number are irrelevant, i just want to know how many months/years.
This is the code that i found and it works if data1 is > than data2 but doesn't if data2 is > than data1.
Dim data1 As DateTime = ("1/3/2021") # working examples
Dim data2 As DateTime = ("1/5/2022")
Public Shared Function GetDateSpanText(fromDate As DateTime, toDate As DateTime) As String
Dim years As Integer = 0, months As Integer = 0, days As Integer = 0
Do Until toDate.AddYears(-1) < fromDate
years += 1
toDate = toDate.AddYears(-1)
Loop
Do Until toDate.AddMonths(-1) < fromDate
months += 1
toDate = toDate.AddMonths(-1)
Loop
Do Until toDate.AddDays(-1) < fromDate
days += 1
toDate = toDate.AddDays(-1)
Loop
Return String.Format("{0} Year(s) {1} Month(s) {2} Day(s)", years, months, days)
End Function
how can i make it work the other way? there are functions that can do this?
thanks to everyone

The simplest way to deal with dates and time intervals is using the TimeSpan struct.
Take a look at this snippet:
Sub Test()
Dim startDate As New Date(2022, 8, 17)
Dim endDate As New Date(2023, 10, 15)
Dim timeBetween As TimeSpan = endDate - startDate ' TimeSpan objects represents a time interval
Dim yearsBetween As Double = timeBetween.TotalDays / 365
Dim monthsBetween As Double = yearsBetween * 12
' Try using simplified string interpolation, like this:
Console.WriteLine($"Years between: {yearsBetween}; months between: {monthsBetween}") ' Note the $ sign at string beginning
End Sub
Using TimeSpan is conveninent because it gives you access to wathever time fraction you want to use:
timeBetween.TotalDays ' Represents the whole time interval in days (double)
timeBetween.TotalHours ' Represent the whole time interval in hours (double)
timeBetween.Days ' Represents the days part only (integer)
As you may guess, you need to substract the oldest date from the newest date to get a positive TimeSpan.
Note: the TimeSpan struct can not provide you .TotalMonths or .TotalYears methods because months and years are not always of the same length (months can vary between 28 and 31 days and years can be 365 or 366 days). That's why you need to do the calculation yourself like in the code I posted.

This is a perfect example of why you need to think logic first and code second. You already have all the code you need. All you have to do is check the relative order of the dates and switch them before the calculation if necessary, then negate the numbers at the end if you switched them. All the rest of the code is exactly the same. If you'd thought about the logic first then you wouldn't have had to ask the question at all.
Public Shared Function GetDateSpanText(fromDate As DateTime, toDate As DateTime) As String
Dim swapped = False
If fromDate > toDate Then
Dim temp = fromDate
fromDate = toDate
toDate = temp
swapped = True
End If
Dim years As Integer = 0, months As Integer = 0, days As Integer = 0
Do Until toDate.AddYears(-1) < fromDate
years += 1
toDate = toDate.AddYears(-1)
Loop
Do Until toDate.AddMonths(-1) < fromDate
months += 1
toDate = toDate.AddMonths(-1)
Loop
Do Until toDate.AddDays(-1) < fromDate
days += 1
toDate = toDate.AddDays(-1)
Loop
If swapped Then
years = -years
months = -months
days = -days
End If
Return String.Format("{0} Year(s) {1} Month(s) {2} Day(s)", years, months, days)
End Function

Related

How do I calculate Hours between dates with a 8-hour work day and accounting for weekends? (VB.net)

I need some help calculating hours worked between two dates, but with an 8-hour work day. I also need to adjust for weekends so I don't say someone took longer then they actually did. I am using VB.net
For example, date1 is 1/23/2020 9:00:00 AM, the start date, and date2 is 1/27/2020 1:30:00 PM, the finish time.
If I run this code:
Dim hours As double = DateDiff(DateInterval.hour, date1, date2)
it would give me the total hours, but would include weekends and not filter it for an 8 hour day.
How can I filter out workday times and weekends? Any help in refining this would be appreciated
One possible option
'Get all days between the start date and the end date
Dim midDays As Date() = Enumerable.Range(0, endDate.Subtract(startDate.AddDays(1)).Days).Select(Function(offset) startDate.AddDays(offset)).ToArray
'Filter out any weekend days
Dim weekdays As Date() = midDays.Where(Function(day) day.DayOfWeek <> DayOfWeek.Saturday AndAlso day.DayOfWeek <> DayOfWeek.Sunday).ToArray
'Assume all days are a full 8 hours
Dim hoursWorked As Decimal = weekdays.Count * 8
This essentially creates a list of all days between the start and end date. Remove weekends from the list and calculates 8 hours for each remaining day.
Of course you would then add the hours from the first and last day to the total.
Simple loop
Dim td As DateTime
If endDate < startDate Then
'switch
td = endDate
endDate = startDate
startDate = td
End If
Dim hours As Integer = 0
td = startDate
While td < endDate
If td.DayOfWeek <> DayOfWeek.Saturday AndAlso td.DayOfWeek <> DayOfWeek.Sunday Then
hours += 8
End If
td = td.AddDays(1)
End While

Find the day given date and number of days

Am looking a function that would aid me to auto detect due date when duration period number is entered in duration textbox.Am having challenge since all the months do not end with same date number i.e. 31 as some end on 30.
NOTE: The function should be able to automatically calculate up to next year if lets say user inputs 3 while in November 2018 its means the duration period will go up January 2019
See the picture below
Dim start_date As Date = dtpStart.Value
Dim totalDays As Integer = 3 * 30
Dim ts As TimeSpan = start_date.Add(totalDays)
Dim end_date As Date = ts
I have tried the above but its giving me an error "value of type integer can not be converted to system.TimeSpan."
If i understand you correctly, if a user enters 3 you want to advance 3 times 30 days later from the start_date.
Dim start_date = dtpStart.Value
Dim end_date = start_date.AddDays(3* 30)
In terms of a function, you could have:
private function AddDays(Byval start_date as Date, Byval amount as integer) as Date
Dim end_date = start_date.AddDays(amount)
return end_date
end function
The usage would be:
Dim new_date = AddDays(dtpStart.Value, 3*30)

Accurate Time Math For VB Including Division

The Problem I am having is with doing time mathematics in VB.
I am currently volunteering at a school and Helping with their Before/Aftercare system
So the goal for before care would be to take a time stamp and compare it to the time school starts that day and find how many half hours are in that given time difference rounding up to the nearest half hour.
For Example. A child Gets to Morning Care at 7:36 School starts at 9:30.
What I want my program to do is
9:30-7:36 = 1 hour 54 minutes
1 hour 54 minutes / 30 minutes = 3.XXX
round that up to 4 multiply by price per hour and my cost is 12
The code I have seems to be off by 15 minutes. I will display the code I use below. Please help by letting me know if there are logic issues or if the method chosen for time math is Poor
'Creating all my variables including half constant half variable times to
compare against
Dim DateIn As DateTime = System.DateTime.Now
Dim Month As Integer = Microsoft.VisualBasic.DateAndTime.Month(DateIn)
Dim Year As Integer = Microsoft.VisualBasic.DateAndTime.Year(DateIn)
Dim Day As Integer = Microsoft.VisualBasic.DateAndTime.Day(DateIn)
Dim DateMorning As New Date(Year, Month, Day, 7, 30, 0)
Dim DateSchoolStart As New Date(Year, Month, Day, 9, 30, 0)
Dim halfHour As System.TimeSpan = New TimeSpan(0, 0, 30, 0)
Dim ticksHalfHour As Long = halfHour.Ticks
Dim count As Integer
Dim cost As Integer
'Portion of a function that calculates cost if the time is in the right zone
If (DateIn >= DateMorning And DateIn < DateSchoolStart) Then
CareTime = DateSchoolStart.Subtract(DateIn)
Dim CareTicks As Long = CareTime.Ticks
count = ReturnCount(CareTicks, ticksHalfHour)
cost = count * price
WriteReport(cost, Year, Month, Day, name)
MessageBox.Show("Welcome to morning care " & name & "!")
Return cost
End If
' function that divides the two longs and does a mod calculation
Function ReturnCount(ByVal tick1 As Long, tick2 As Long) As Integer
If (tick1 Mod tick2 = 0) Then
count = tick1 / tick2
Return count
Else
count = 1 + (tick1 / tick2)
Return count
End If
End Function
I believe this is the relevant portion of the code. If you see a flaw in my logic or have a simpler way of achieving my goal your input would be much appreciated.

Week number input returns crazy full week output

I would like some feedback on what's wrong with these codes. I'm trying to output a full week based on a week number. For instance if I input "2014/45" I would like to output all dates spanning from November 2nd to November 8th. Now I need to figure out the first date in that week (hence November 2nd) before grabbing the rest of the days and this is where everything gets messed up for me. This is what I've come up with:
' getyear = 2014, getweek = 45
Dim DateOfFirstWeekDay As DateTime = GetDateOfFirstDayOfWeek(getyear, getweek)
Dim FirstDateInSequence As DateTime = CDate(DateAdd("d", _
CInt(Abs(Integer.Parse(Weekday(DateOfFirstWeekDay, WeekStartsWith))) * -1) + 1, _
DateOfFirstWeekDay)).ToShortDateString()
Protected Friend Shared Function GetDateOfFirstDayOfWeek(ByVal getyear As Nullable(Of Integer), _
ByVal getweek As Nullable(Of Integer)) As DateTime
Dim firstWeekDay As DateTime = GetFirstDayOfWeek(newYearDay)
If getweek = 1 Then
getweek -= 1
End If
Return DateAdd(DateInterval.WeekOfYear, CInt(getweek), firstWeekDay)
End Function
Protected Friend Shared Function GetFirstDayOfWeek(ByVal dt As DateTime) As DateTime
If dt.DayOfWeek = DayOfWeek.Sunday Then
Return dt.AddDays(-6)
Else
Return dt.AddDays(1 - CInt(dt.DayOfWeek))
End If
End Function
As my question implies November 2nd is not the result I get. Instead FirstDateInSequence returns December 22, 2013 when I input 2014/45. It's pretty safe to assume something fails me here. I just can't get my head around it. I'd like your point of view to this. Where should I focus my attention in the code above?
I'm having a hard time quickly following your code logic. So here's mine.
You could start by finding the first day of the first week of that year
Dim d As New DateTime(year, 1, 1)
d = d.AddDays(-d.DayOfWeek)
And then add the number of days (week_number -1) * 7
d = d.AddDays((week_number - 1) * 7)
I do a -1 since I assume that week_number will be equal to 1 to get the first week. Since d is already equal to the first week, we start counting at 0.
To get the last day, just add 6 (or 7) days to the result

VB.NET Make a Date out of just Day

My user will typically enter some trip info including a day and month but typically they just enter the day. For example they would enter "TRIP1500/31" where the 31 is implied that its in JULY. The trip date can be at most 7 days in the past or 7 days in the future. So now what Im trying to do is guess what month that day is meant to be. So far I have:
Dim diff As Integer = CInt(tripDay) - Date.Now.Day
Select Case diff
Case 0
'same day so its probably current month
End Select
What I'm having trouble with is the other cases where the current day and the trip day overlap month-to-month. If the current day and trip day are in current month then the most difference they can be is +/-7 days but what about the other cases? Any help appreciated.
Function GetTripDate(day As Integer) As Date
Dim today As Date = Date.Today
For i As Integer = -7 To 7
Dim dt As Date = today.AddDays(i)
If dt.Day = day Then Return dt
Next
Throw New ArgumentOutOfRangeException("Invalid trip day.")
End Function
This gives you the date(incl. month) of the nearest date with the given day:
Dim maxDiffDays = 7
Dim tripDay = 31
Dim today = Date.Today
Dim tripDate = New Date(today.Year, today.Month, tripDay)
Dim tripDates = {tripDate.AddMonths(-1), tripDate, tripDate.AddMonths(1)}
Array.Sort(Of Date)(tripDates, Function(d1, d2) ((today - d1).Duration).CompareTo((today - d2).Duration))
Dim nearestDate = tripDates.First()
If ((today - nearestDate).Days <= maxDiffDays) Then
Console.WriteLine("Nearest month for trip date is: " & nearestDate.Month)
End If
It creates a Date from a given day, then it creates the two surrounding dates one month after and previous this date. This array will be sorted from the positive timespan from today(TimeSpan.Duration). So the firs't date in the array is the nearest date with the correct month.