How to get start and end of previous month in VB - ms-access

Im trying to create some VB code that will get the start and end of the previous month.
Im able to the current month which is just:
Month(DateValue(Now))
which would return 3. From there I can take away 1 to give me 2 meaning February. This is fine but what about when I Im in January and I repeat this and it gives me zero - my code will fail. Any one know how to get the previous months start and end day then?
Thanks

The first day of the previous month is always 1, to get the last day of the previous month, use 0 with DateSerial:
''Today is 20/03/2013 in dd/mm/yyyy
DateSerial(Year(Date),Month(Date),0) = 28/02/2013
DateSerial(Year(Date),1,0) = 31/12/2012
You can get the first day from the above like so:
LastDay = DateSerial(Year(Date),Month(Date),0)
FirstDay = LastDay-Day(LastDay)+1
See also: How to caculate last business day of month in VBScript

I have similar formula for the First and Last Day
The First Day of the month
FirstDay = DateSerial(Year(Date),Month(Date),1)
The zero Day of the next month is the Last Day of the month
LastDay = DateSerial(Year(Date),Month(Date)+ 1,0)

firstDay = DateSerial(Year(DateAdd("m", -1, Now)), Month(DateAdd("m", -1, Now)), 1)
lastDay = DateAdd("d", -1, DateSerial(Year(Now), Month(Now), 1))
This is another way to do it, but I think Remou's version looks cleaner.

Try this
First_Day_Of_Previous_Month = New Date(Today.Year, Today.Month, 1).AddMonths(-1)
Last_Day_Of_Previous_Month = New Date(Today.Year, Today.Month, 1).AddDays(-1)

This works reliably for me in my main sub.
Dim defDate1 As Date, defDate2 As Date
'** Set default date range to previous month
defDate1 = CDate(Month(Now) & "/1/" & Year(Now))
defDate1 = DateAdd("m", -1, defDate1)
defDate2 = DateAdd("d", -1, DateAdd("m", 1, defDate1))

Try this to get the month in number form:
Month(DateAdd("m", -3, Now))
It will give you 12 for December.
So in your case you would use Month(DateAdd("m", -1, Now)) to just subract one month.

Just to add something to what #Fionnuala Said, The below functions can be used. These even work for leap years.
'If you pass #2016/20/01# you get #2016/31/01#
Public Function GetLastDate(tempDate As Date) As Date
GetLastDate = DateSerial(Year(tempDate), Month(tempDate) + 1, 0)
End Function
'If you pass #2016/20/01# you get 31
Public Function GetLastDay(tempDate As Date) As Integer
GetLastDay = Day(DateSerial(Year(tempDate), Month(tempDate) + 1, 0))
End Function

Public Shared Function GetFOMPrev(ByVal tdate As Date) As Date
Return tdate.AddDays(-(tdate.Day - 1))
End Function
Public Shared Function GetEOMPrev(ByVal tdate As Date) As Date
Return tdate.AddDays(-tdate.Day)
End Function
Usage:
'Get End of Month of Previous Month - Pass today's date
EOM = GetEOMPrev(Date.Today)
'Get First of Month of Previous Month - Pass date just calculated
FOM = GetFOMPrev(EOM)

Related

Calculating the Start Date of the Last Quarter

I'm looking to calculate the start date of the last quarter based on the current date.
Where
Q1 = Jan-Mar
Q2 = Apr-Jun
Q3 = Jul-Sep
Q4 = Oct-Dec
Hence, if the current date is 8th Jan 2018, the function would return the date 1st Oct 2017.
I have written the following code, however, this seems clunky and inelegant, and I have a feeling that there may be a better way to write it (for example, using dateadd).
Function LMLastQuarterStart() As Date
Dim mo As Integer
Dim yr As Integer: yr = Year(Date)
Select Case Month(Date)
Case 1 To 3: mo = 10: yr = yr - 1
Case 4 To 6: mo = 1
Case 7 To 9: mo = 4
Case Else: mo = 7
End Select
LMLastQuarterStart = DateSerial(yr, mo, 1)
End Function
I would appreciate any advice/suggestions offered, thanks.
The function you're looking for, with the DateAdd, is the following:
Public Function LastQuarter(theDate As Date) As Date
LastQuarter = DateAdd("q", DatePart("q", theDate) - 2, DateSerial(Year(theDate), 1, 1))
End Function
Explanation:
DateSerial(Year(theDate), 1, 1)) returns the first quarter of the current year.
DateAdd("q", DatePart("q", theDate), ThatDate) adds the current quarter, returning the next quarter (e.g. quarter 1 -> quarter 2). So the -2 substracts two quarters.
About clunkyness: this function may be shorter and possibly include less operations, but it's harder to understand. That may or may not be relevant.
And about parameters: I have made it take a date, to both make it easy to test and to let you keep it variable. You can do with that what you will.
Thanks to Gustav for making the suggestion to use DatePart instead of Format

first business day of next month

I'm trying to set the default value for a date parameter to the first business day of next month, that is if the 1st of the month is a Saturday or a Sunday, it selects the following Monday.
I've got this but for some reason when I try to run the report it says an error occurred during local report processing and I can't figure out what's going wrong. Can anyone help?
= iif (datepart("dw", dateadd("m",1,DateAdd("d",1-DatePart("d",Today()),Today()))) = 7,
dateadd("m",1,DateAdd("d",3-DatePart("d",Today()),Today())),
iif (datepart("dw", dateadd("m",1,DateAdd("d",1-DatePart("d",Today()),Today()))) = 1,
dateadd("m",1,DateAdd("d",2-DatePart("d",Today()),Today())),
dateadd("m",1,DateAdd("d",1-DatePart("d",Today()),Today()))))
=Today.AddMonths(1).AddDays(-Today.Day + 1).AddDays(
SWITCH(
Today.AddMonths(1).AddDays(-Today.Day + 1).DayOfWeek = DayOfWeek.Sunday, 1,
Today.AddMonths(1).AddDays(-Today.Day + 1).DayOfWeek = DayOfWeek.Saturday, 2,
True, 0
))
This returns the 1st of the following month:
Today.AddMonths(1).AddDays(-Today.Day + 1)
The switch statement then determines how many days to add based on the day of the 1st of the following month:
.AddDays(SWITCH(
Today.AddMonths(1).AddDays(-Today.Day + 1).DayOfWeek = DayOfWeek.Sunday, 1,
Today.AddMonths(1).AddDays(-Today.Day + 1).DayOfWeek = DayOfWeek.Saturday, 2,
True, 0
))
Try:
=Switch(
WeekDay(DateSerial(Today.Year,Today.Month,1).AddMonths(1),FirstDayOfWeek.Monday)=6,
DateSerial(Today.Year,Today.Month,1).AddMonths(1).AddDays(2),
WeekDay(DateSerial(Today.Year,Today.Month,1).AddMonths(1),FirstDayOfWeek.Monday)=7,
DateSerial(Today.Year,Today.Month,1).AddMonths(1).AddDays(1),
true, DateSerial(Today.Year,Today.Month,1).AddMonths(1)
)
Assuming your first date of week monday.
Hope it helps.

Access Query. If records Due Date = Last Week Insert Yes in Cell

Good morning All,
I am working on the following however, I can't figure it out for the life of me. I have table that contains a bunch of due dates. What I am trying to do is add a query that adds another field and inserts a yes if the date equals a day in last week. Honestly I need it to insert yes as long as it does not = this week.
I've tried using:
Urgent: IIf([Due Date]=[Due Date]
Between
DateAdd("d",1-Weekday(Date()) 7, Date()) And
DateAdd("d",1-Weekday(Date())-1, Date()),"Yes","")
with no luck. What am I missing here?!
Thanks all. Cheers.
Here's how to return Urgent if 'not this week' means previous Saturday and before. Not sure how you would do it without code.
Helper Function to get the first day of this week based on current date. Paste it into a new or existing global module.
Function FirstDateOfTheWeek() As Date
Dim dt As Date
If Weekday(Date) = vbSaturday Then
FirstDateOfTheWeek = DateAdd("y", -6, Date) 'today is Saturday? then return previous Sunday
ElseIf Weekday(Date) = vbSunday Then
FirstDateOfTheWeek = Date 'today is Sunday? then return Sunday because its the first day of the week
Else 'weekday, so just go backwards until we hit previous sunday's date
dt = Date
While Weekday(dt) <> vbSunday
dt = DateAdd("y", -1, dt)
Wend
FirstDateOfTheWeek = dt
End If
End Function
An IsUrgent function to be called from query. Paste it into a new or existing global module.
Function IsUrgent(dt As Variant) As String
If IsNull(dt) Then 'if null date is passed then return blank string; Variant chosen instead of date for this case; change it to N/A if you want?
IsUrgent = ""
Exit Function
End If
If dt < FirstDateOfTheWeek Then
IsUrgent = "Yes"
Else
IsUrgent = ""
End If
End Function
The Query Column calling IsUrgent() function:
IsUrgent: IsUrgent([Due Date])

capture dates by quarters in access

To make my life much easier working with my data I set 3 columns of same date content. The first displays in the format mm/dd/yyyy, second in the format of yyyy-mm and the third in the format yyyy-q.
I did it purposely due to my reports. Sometimes I need to create monthly, quarterly, yearly etc. Usually I work with a form where I invite the user select start and end date and by a click of a button run a report. This report extracts a query where I specify on the date section to pull all information between start and end date. This time I want to do the same procedure but instead of start and end date - I want the user to select which quarter he wants so that the query will pull all information regarding this quarter. What do I specify in the criteria to archive this?
Filter on
DatePart("q", [YourDateField])
or
Format([YourDateField], "yyyyq")
To obtain the first and last date of a quarter, given the year and the quarter, you can use these expressions:
DateQuarterFirst = DateSerial(Y, 1 + 3 * (Q - 1), 1)
DateQuarterLast = DateSerial(Y, 1 + 3 * Q, 0)
If you have a date of the quarter, you can these functions to obtain the first and last date of the quarter of that date:
Public Function DateThisQuarterFirst( _
Optional ByVal datDateThisQuarter As Date) As Date
Const cintQuarterMonthCount As Integer = 3
Dim intThisMonth As Integer
If datDateThisQuarter = 0 Then
datDateThisQuarter = Date
End If
intThisMonth = (DatePart("q", datDateThisQuarter) - 1) * cintQuarterMonthCount
DateThisQuarterFirst = DateSerial(Year(datDateThisQuarter), intThisMonth + 1, 1)
End Function
Public Function DateThisQuarterLast( _
Optional ByVal datDateThisQuarter As Date) As Date
Const cintQuarterMonthCount As Integer = 3
Dim intThisMonth As Integer
If datDateThisQuarter = 0 Then
datDateThisQuarter = Date
End If
intThisMonth = DatePart("q", datDateThisQuarter) * cintQuarterMonthCount
DateThisQuarterLast = DateSerial(Year(datDateThisQuarter), intThisMonth + 1, 0)
End Function

Multi Select List Boxes with Multiple Columns in Access 2013

I have a listbox set to Multiselect property of Simple.
The listbox is populated by using a table.
There are 4 columns in the listbox
1 3/23/2014 4/5/2014 2014
2 4/6/2014 4/19/2014 2014
3 4/20/2014 5/3/2014 2014
The columns are PayPeriod, StartDate, EndDate, FiscalYear
What I want to be able to do is highlight a chunk of dates and have the first selected StartDate and the last selected EndDate populate two hidden text boxes so I can use them for my queries/reports.
I've tried a couple different ways. Each time what happens is it only uses the last item I have selected in it's calculations.
Dim ItemIndex As Variant
For Each ItemIndex In Me.lstPayPeriods.ItemsSelected
If Me.lstPayPeriods.Selected(ItemIndex) And Me.lstPayPeriods.Selected(ItemIndex - 1) = False Then
Date1.SetFocus
Date1.Text = Me.lstPayPeriods.Column(2, Me.lstPayPeriods.ListIndex)
End If
Next
In this example I tried to have it go through each Item of the listbox. I wanted to check to see if the current row was selected and the row before it wasn't. That way I could determine it was the first item selected in the group of selected items. It would always only use the last item I had selected.
Dim CurrentRow As Integer
Dim FirstDate As Date
For CurrentRow = 0 To Me.lstPayPeriods.ListCount - 1
If Me.lstPayPeriods.Selected(CurrentRow) Then
Date2.SetFocus
Date2.Text = Me.lstPayPeriods.Column(3, Me.lstPayPeriods.ListIndex)
End If
Next CurrentRow
For CurrentRow = 0 To Me.lstPayPeriods.ListCount - 1
If Me.lstPayPeriods.Selected(CurrentRow) And Me.lstPayPeriods.Selected(CurrentRow - 1) = False Then
Date1.SetFocus
Date1.Text = Me.lstPayPeriods.Column(2, Me.lstPayPeriods.ListIndex)
End If
Next CurrentRow
I tried to do something similar with this code. Again, it only uses the last item I have selected.
I am running into a wall figuring out how to accomplish my goal.
I think the issue is in your approach. I'm personally not keen on the approach you're using to determine the earliest start and latest end, though the issue might just be your column numbers: the first column in a listbox is column 0, and the last column (of 4 columns) is column 3. Accordingly in your code above, you're setting Date2 = fiscal year, not enddate.
I would however recommend a different approach to determining (a) the earliest selected StartDate, and (b) the latest selected enddate. You could have a loop for each operation, or your can encapsulate both in a function:
private function GetPayPeriodDate(baseValue as Date, findLater as boolean, colNo as long) as Date
'baseValue is the default date to test against
'findLater tells the function whether to look for < or > the baseValue
'colNo tells the function which column of data to test
Dim vv as variant
For each vv in lstPayPeriods.ItemsSelected
if lstPayPeriods.Selected(vv) then
if findLater then
if lstPayPeriods.Column(colNo, vv) > baseValue then
baseValue = lstPayPeriods.Column(colNo, vv)
end if
else
if lstPayPeriods.Column(colNo, vv) < baseValue then
baseValue = lstPayPeriods.Column(colNo, vv)
end if
end if
end if
next vv
GetPayPeriodDate = baseValue
end function
Then you can set your start and end date textboxes by calling this function:
me.StartDate = GetPayPeriodDate(CDate("31/12/2099"), false, 1)
'since startdate looks for the earliest date, the base date must be in the future
me.EndDate = GetPayPeriodDate(CDate("01/01/1900"), true, 2)
'similarly, looking for the latest date, base date must be in the past