I am trying to get 2 days behind the current date provided Saturday, Sunday and Holidays or not included.
Table where my holidays are stored - [DateTable[Holidays]]
I know it requires the usage of Application.NetworkDays_Intl, but I am not able to get the logic going.
Does Anyone know what is the easy way to achieve this >
The function NetworkDays_Intl takes a start date and an end date and calculates the number of workdays in the range. This forces a slightly cumbersome approach:
Dim StartDate As Date
Dim EndDate As Date
Dim Duration As Integer
Duration = 2
EndDate = CDate("2017-07-08")
' Pick theoretically latest start date
StartDate = DateAdd("d", -Duration + 1, EndDate)
' Step one day back until we get it right
Do While Application.NetworkDays_Intl(StartDate, EndDate) <> Duration
StartDate = DateAdd("d", -1, StartDate)
Loop
Debug.Print StartDate
Related
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
I am trying to write a query in Access to poll year to date sales records to build a report. I think I need to write a VBA module to calculate these dates.
I need a date range for Year to Date from Last Saturday (ex. from 1/1/2015 to 10/24/2015 for this week's report). I also need to poll the records from Last Year To Date (ex. from 1/1/2014 to 10/25/2014 for this week's report).
Any suggestions on how I can query this date range?
Thanks!
Consider using a temporary table such as a YTDDates of two fields (ID, SalesDate) that holds the date range which can be cleaned out per needed use. Then join your sales data to this table for daily reporting.
VBA can run a loop through all days from beginning (1/1/2015) to end (10/24/2015) and iteratively append to temp table using the DateAdd() function.
Dim db As Database
Dim startDate As Date, endDate As Date, d As Date
Dim diff As Integer, i as Integer
Set db = CurrentDb()
startDate = #1/1/2015#
endDate = #10/24/2015#
diff = DateDiff("d", startDate, endDate)
' CLEAN OUT PRIOR DATE RECORDS
db.Execute "DELETE FROM YTDDates", dbFailOnError
For i = 0 To diff
d = DateAdd("d", i, startDate)
db.Execute "INSERT INTO YTDDates ([SalesDate]) VALUES (#" & d & "#);", dbFailOnError
Next i
Set db = Nothing
Instead of a temp table I would just use a formula in your query using a BETWEEN clause on your date field with a formula like this:
vba.DateSerial(Year(Now()),Month(Now()),Day(Now())-Weekday(Now(),vbSunday))
The Weekday function returns an integer from Sunday (vbSunday). So on a Monday it will return '2' and on Saturday it will return '7' which will give you the previous week's Saturday date.
For getting the beginning of the year date you could use a function like this:
vba.DateSerial(Year(Now()),1,1)
I want to set a specific date (October 06 , 2014) to be the 1st Week of the year. So when I use the =weeknum() formulaR1C1 it will return the week number.
I'm currently working on a worksheet that gets updated daily so the week number will be updated every week only. In column ("D") indicates the week number. and column ("B") indicates the daily date.
If i use the =weeknum() formula on it returns the value of 41, but it needs to be week number 1.
How about creating your personalized function?
It just consists of counting how many days there are between the date you insert (myDate) and the date which is considered to be the first day of the year (first_day), dividing this number by 7, taking its integer and adding up 1. It will always give you the right one.
Public Function special_weeknum(ByVal myDate As Date) As Integer
Dim first_day As Date: first_day = #10/6/2014#
Dim myWeek As Integer: myWeek = Int((myDate - first_day) / 7) + 1
special_weeknum = myWeek
End Function
Please note that this approach would allow you also to pass the first day as a user input:
Public Function special_weeknum(ByVal myDate As Date, ByVal first_day As Date)
Dim myWeek As Integer: myWeek = Int((myDate - first_day) / 7) + 1
special_weeknum = myWeek
End Function
so that you will always be able to decide which is the day you must consider as first day of the year.
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.
Given the following database table:
StartDate DATETIME -- day that the reminder period starts
LastReminderDate DATETIME -- the last time the reminder triggered
DayOfMonth INT -- the day of the month to remind the user
Interval INT -- how often in months to remind the user
How can I figure out the next reminder date based on these values? For example:
StartDate = '6/1/2011'
LastReminderDate = '6/5/2011'
DayOfMonth = 5 -- remind on the 5th of the month
Interval = 2 -- remind every other month
For this particular example, the next reminder date should be 8/5/2011 because it reminds on the 5th of the month every two months. How would I write a function to figure this out?
If LastReminderDate is NULL, then LastReminderDate should be equal to StartDate
UPDATE:
StartDate = '6/1/2011'
LastReminderDate = NULL
DayOfMonth = 5
Interval = 2
In this case, there was no last reminder date. The first time the reminder would occur would be 6/5/2011. The solutions below seem to be returning 8/5 in this case.
Here are some specific rules:
The Reminder should always occur on whatever DayOfMonth is. If DayOfMonth would be illegal for the given month then it should be the last day of that month. For example....if DayOfMonth is 31 and the next reminder date would fall on June 31, then it should be June 30th instead.
The next reminder date should always be based off of the Last Reminder Date plus the Interval. If Last Reminder Date does not match the Day of Month, then it could potentially be more than what the interval was. For example...if Last Reminder was 6/1/2011 and the interval is 2 months, but the reminder is for the 20th of the month, then the next reminder will be 8/20/2011.
If there is no last reminder date, then use the Start Date instead of last reminder date...but this will use the earliest date in the future. If start date was 6/1/2011 and day of month is 5, then this will be 7/5/2011 since today is 6/22/2011. If Day of Month was 25 then it would be 6/25/2011
DECLARE
#StartDate AS datetime, -- day that the reminder period starts
#LastReminderDate AS datetime, -- the last time the reminder triggered
#DayOfMonth AS integer, -- the day of the month to remind the user
#Interval AS integer -- how often in months to remind the user
SET #StartDate = '6/1/2011'
SET #LastReminderDate = '6/5/2011'
SET #DayOfMonth = 5 -- remind on the 5th of the month
SET #Interval = 2 -- remind every other month
SELECT
CASE
WHEN #LastReminderDate IS NULL
THEN
CASE WHEN Day(#StartDate) <= #DayOfMonth
THEN DateAdd( month, ((Year( #StartDate ) - 1900) * 12) + Month( #StartDate ) - 1, #DayOfMonth - 1 )
ELSE DateAdd( month, ((Year( #StartDate ) - 1900) * 12) + Month( #StartDate ) - 0, #DayOfMonth - 1 )
END
ELSE DateAdd( month, #Interval, #LastReminderDate )
END
The meat of this is the last four lines, the SELECT CASE ... END statement. I provided a whole script that lets you plug in different values, and see how the SELECT CASE ... END behaves for those test values.
But to just use this on your table, use only the last four lines (and remove the # from the front of the names so they match the table's column names).
You could also generalize this so that Interval doesn't have to be months. If your table had an IntervalType column, you could supply that as the first argument to DateAdd(). See the docs but some common intervals are days, months, years, and so on.
EDIT2: Respect DayOfMonth.
Since you want to use the StartDate if there is no LastReminderDate, then you'll want to use COALESCE for that bit of logic: COALESCE(LastReminderDate, StartDate)
Now, get to the last of the previous month: DATEADD(DAY, -DAY(COALESCE(LastReminderDate, StartDate)), COALESCE(LastReminderDate, StartDate))
Finally, add the months and then get to the date that we need:
DATEADD(MONTH, Interval, DATEADD(DAY, -DAY(COALESCE(LastReminderDate, StartDate)) + DayOfMonth, COALESCE(LastReminderDate, StartDate)))
This will potentially go forward less than two months if the date of the last reminder was on a day of the month after the "DayOfMonth" that's configured for the reminder. You should be able to tweak that depending on what your business logic is in that situation.