I have many financial reports, not always ending on Dec 31.
The function I'm working on should take the year-end date and return the number of days between the present date and the next year-end date, divided by 365. (Forward-looking, so if the year-end date was yesterday then the function should return 364 days, rather than 1.)
The attempt below returns 1. I believe it has to do with DateDiff.
Function dateCalc(ye As Date)
Dim today As Date
Dim x As Integer
today = Date
If ye < today Then
x = (365 - DateDiff("d", ye, today)) / 365
ElseIf ye > today Then
x = DateDiff("d", ye, today) / 365
Else
x = 0
End If
dateCalc = x
End Function
Using the below derivative of your code,
Function dateCalc(ByVal YE As Date) As Double
If YE < Today Then
dateCalc = (365 - DateDiff("d", YE, Date)) / 365
ElseIf YE > Today Then
dateCalc = DateDiff("d", YE, Date) / 365
Else
dateCalc = 0
End If
End Function
On the date 6/14/2022, we see the following:
?dateCalc(#6/15/2022#) produces -0.00273972602739726
?dateCalc(#6/13/2022#) produces 0.997260273972603
Note that in the YE > Today case, the DateDiff is -1. If you wanted a positive, negate it. It wasn't clear from the question if this was the desired output, but the primary problem appears to be the use of Integer as opposed to Double.
Related
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
I've got the following formula
number_of_years = DateDiff("yyyy", Date_days_back, Current_Date)
where
Date_days_back = 17/10/2020
Current_Date = 02/08/2021
for some reason this returns "1" when there aren't 365 days apart between these two dates, is something wrong with my formula or is DateDiff calculating this wrong? I would like to get "0" returned as there aren't enough amount of days between these two dates for a year to have passed between the two dates.
Comment: As Scott Stated, if I'm looking from December 31st 2020 and 1st of January 2021, then this function will count this as a year has passed. is there another function that calculates if a years has passed in between two dates where it doesn't do what DateDiff does and instead counts if 365 have passed in between the two dates?
Try to use YearFrac(). By setting the third argument to 1, the function uses the actual number of days in years (taking into account leap years) in its calculations:
Int(WorksheetFunction.YearFrac("2020-12-31", "2021-12-31", 1))
Comparison:
Sub Example()
start_date = CDate("2020-12-31")
end_date = CDate("2021-01-01")
Debug.Print Int(WorksheetFunction.YearFrac(start_date, end_date, 1))
' prints 0
Debug.Print DateDiff("yyyy", start_date, end_date)
' prints 1
End Sub
This seems to work
function yeardiff(d1 as date, d2 as date) as integer
yeardiff = datediff("yyyy", d1, dateadd("yyyy", -1, dateadd("d", 1, d2)))
end function
Tests
print yeardiff("2020-12-31", "2021-12-30")
0
print yeardiff("2020-12-31", "2021-12-31")
1
Of course it will also give,
print yeardiff("2020-12-31", "2020-12-30")
-1
And if something different is desired then a conditional would be needed.
I have the following code which calculates business minutes from 2 dates given. Where 9am is the start time and 5.30pm is finish time. However, how can I also incorporate a rule where I can prevent weekend hours being included? I am having such a mind block here :/
Function ElapsedBusinessMinutes(StartDateTime As Date, StopDateTime As Date) As Single
Dim dteAdjStart As Date
Dim lngElapsedMinutes As Long
Dim lngMinutesInWorkDay As Long
lngMinutesInWorkDay = 510
dteAdjStart = TimeValue(StartDateTime)
If dteAdjStart > #5:30:00 PM# Then
dteAdjStart = TimeSerial(7, Minute(StartDateTime), Second(StartDateTime))
lngElapsedMinutes = DateDiff("d", StartDateTime, StopDateTime - 1) * lngMinutesInWorkDay
Else
lngElapsedMinutes = DateDiff("d", StartDateTime, StopDateTime) * lngMinutesInWorkDay
End If
ElapsedBusinessMinutes = lngElapsedMinutes + DateDiff("n", dteAdjStart, TimeValue(StopDateTime))
End Function
I want to use the Days360 function in VB.Net. I need to know the difference in days between two dates assuming 360 days in a year (not 365 days the DateDiff function uses).
For example DateDiff(DateInterval.Day,"16/10/2015", "04/02/2016") = 111 days, but Days360 should return 109 days.
Days360 function in Excel calculates the days between two dates using a fictional calendar that has 30 days in each month. This method is used for some financial purposes.
You can write a function to do the same calculation.
[Edit]
Excel supports two versions of the calculation: one common in the US (this is the default) and the other common in Europe (see the documentation of the DAYS360 function for details).
The code I originally posted implemented the European version. I have updated it to support both versions. Thanks to Nikhil Vartak for pointing this out.
Function Days360(startDate As DateTime, endDate As DateTime, euMethod As Boolean) As Integer
Dim months As Integer = (endDate.Year - startDate.Year) * 12 + endDate.Month - startDate.Month
If euMethod Then
'Use European method (start or end dates after the 30th of the month are changed to 30th)
Return months * 30 + Math.Min(30, endDate.Day) - Math.Min(30, startDate.Day)
Else 'Use US method
'If the start date is the last day of the month, change it to the 30th
Dim startDay As Integer = startDate.Day
startDay = If(startDate.Day >= DateTime.DaysInMonth(startDate.Year, startDate.Month), 30, startDate.Day)
'If end date is last of the month, change it to the 30th
Dim endDay As Integer = endDate.Day
endDay = If(endDate.Day >= DateTime.DaysInMonth(endDate.Year, endDate.Month), 30, endDate.Day)
'If end date is last of the month and start date is before 30th, change end date to 1st of the next month
If endDate.Day >= DateTime.DaysInMonth(endDate.Year, endDate.Month) And startDay < 30 Then
endDay = 1
months += 1
End If
Return months * 30 + endDay - startday
End If
End Function
I have seen how to loop through weeks of a year, w1301,w1302,w1303, I can get the week number if i loop through + on week number but I believe there is a way to directly loop weekly with vba, i hope at least.
DateSerial(Year(Now), Month(Now), Day(Now)) To DateSerial(2013, 3, 1)
StartDate = #1/1/2013#
EndDate = #12/31/2013#
For DateLooper = StartDate To EndDate
I got the function for a week number from date
Public Function IsoWeekNumber(d1 As Date) As Integer
Attributed to Daniel Maher
Dim d2 As Long
d2 = DateSerial(Year(d1 - WeekDay(d1 - 1) + 4), 1, 3)
IsoWeekNumber = Int((d1 - d2 + WeekDay(d2) + 5) / 7)
End Function
You could just use the DateAdd function
For i = 1 To 52
Debug.Print DateAdd("ww", i, Now())
Next i
A day has an integer value of 1, so you could iterate by week like this:
startDate = #1/1/2013#
endDate = #12/31/2013#
For d = startDate To endDate Step 7
'do stuff
Next
The week number can be determined with the DatePart function, e.g.:
WScript.Echo DatePart("ww", Now)
This will work in both vbscript and vba.
I tried this solution and it seems to work, am not 100% sure of how it handles the 28,30,31 days of different months but i trust vba. i know am making a mistake probably :))
currentDate = "2013-01-02" ' coz i wanted to start on a wednesday
for week = 1 to 52
debug.print currentDate
currentDate = DateAdd("ww",1,currentDate)
next week