Calculating the Start Date of the Last Quarter - ms-access

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

Related

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])

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

How to use between operator for 2 date input parameters in mysql?

My task is to get the records between 2fromdate and todate(given as a input parameters).
i am not able to use between operator for 2 input parameters...
My query as follows...
DELIMITER $$
CREATE DEFINER=`testrunner`#`%` PROCEDURE `usp_GetAllTranasactions`(pFromDate nvarchar(30),pToDate nvarchar(30),pstatus int)
BEGIN
select
ST.UserID,U.Username,
ST.SubscriptionID,
ST.DateOfSubscription,
SM.SubType,
SM.Details,
ST.Amount,
ST.EndDate,
ST.Status
from tr_t_subscriptiontransactions ST
Join tr_m_users U on U.UserID=ST.UserID
join tr_m_subscription SM on SM.SubscriptionID=ST.SubscriptionID
where **ST.DateOfSubscription between (pFromDate and pToDate) and ST.EndDate
between(pFromDate and pToDate) and ST.Status=pstatus;**
END if;
END
here i don't know how to use between parameters..plz help me..i want to retrive record between fromdate and todate..hope u understand..
Let us assume you want all transactions for the month of June 2014
In your user interface the parameter values are:
from_date = 2014-06-01
to_date = 2014-06-30
But you will evaluate against a transaction date & time. How do you ensure that absolutely every transactions on June 30 - right up to midnight - is included in the results?
Here is how: use 2014-07-01 instead of 2014-06-30, and here is what the query would look like - which does NOT use between!
SELECT
ST.UserID
, U.Username
, ST.SubscriptionID
, ST.DateOfSubscription
, SM.SubType
, SM.Details
, ST.Amount
, ST.EndDate
, ST.Status
FROM tr_t_subscriptiontransactions ST
JOIN tr_m_users U
ON U.UserID = ST.UserID
JOIN tr_m_subscription SM
ON SM.SubscriptionID = ST.SubscriptionID
WHERE (ST.DateOfSubscription >= pFromDate AND ST.DateOfSubscription < pToDate + 1)
AND (ST.EndDate >= pFromDate AND ST.EndDate < pToDate + 1)
AND ST.Status = pstatus
;
AVOID between for date ranges because it INCLUDES both the lower and upper boundary values.
... equivalent to the expression (min <= expr AND expr <= max)
http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#operator_between
What this can lead to is an "anti-pattern" which look like this:
where dt_field between '2014-06-01 00:00:00' and '2014-06-30 23:59:59'
but there are time units smaller than one second, so that approach is imperfect. Don't attempt to overcome the deficiencies of between by adjusting the upper value this way. The simple and more accurate approach is to use >= and < adjusting the upper value by one whole time unit (usually the next day).

How to get start and end of previous month in VB

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)

VBA: DateDiff Hour Rounded off

I have the following sub in Access 2003 to return the hours elapsed bewteen two datetime fields.
Function DateDifferenceHour(dateStart As Date, dateEnd As Date) As String
'Outputs Hours from two dates
Dim age_hour As Double
age_hour = DateDiff("h", dateStart, dateEnd)
DateDifferenceHour = age_hour
End Function
If I have the following: DateDifferenceHour("07/23/2005","07/23/2005 7:30:00 PM").
It correctly returns 19 hours, but in reality, the time elapsed is 19 hours and 30 minutes.
How can I modify it so it can round off to 20 hours?
Edit:
My original suggestion was "Compute the difference in minutes, divide by 60, and round the quotient to zero decimal places". However, #Jean-François Corbett showed me the limitation of that approach.
? DateDifferenceHour("07/23/2005 7:00:59 PM","07/23/2005 7:30:00 PM")
1
IOW my first attempt rounded a duration of 29 minutes and 1 second up to 1 hour, which is no good. So instead I suggest using the difference in seconds and dividing by 3600.
Function DateDifferenceHour2(dateStart As Date, dateEnd As Date) As String
'Outputs Hours from two dates
DateDifferenceHour2 = _
Format(DateDiff("s", dateStart, dateEnd) / 3600, "0")
End Function
? DateDifferenceHour2("07/23/2005 7:00:59 PM","07/23/2005 7:30:00 PM")
0
There is still the issue of which rounding approach you want.
I chose Format() thinking you would want 2.5 hours rounded up to 3.
The VBA Round() function uses round-to-even, so Round(2.5, 0) would give you 2.
We don't know which you want; you can tell us. Also, dateStart and dateEnd imply dateStart will not be greater than dateEnd. However, if it can be, consider how you want a negative duration "rounded" to the nearest hour. Here are some examples copied from the Immediate Window.
? Round(-2.5, 0)
-2
? Round(-1.5, 0)
-2
? Format(-2.5, "0")
-3
? Format(-1.5, "0")
-2
This works, without any unexpected rounding (aside from the precision of the Date type itself).
Function DateDifferenceHour(dateStart As Date, dateEnd As Date) As String
' Rounds .5's to nearest even integer.
'DateDifferenceHour = CStr( Round( _
' CDbl(dateEnd - dateStart) * 24 ) )
' Rounds .5's up.
DateDifferenceHour = Format( _
CDbl(dateEnd - dateStart) * 24, "0" )
End Function
I put two rounding options so that it rounds to whole numbers; pick your favourite. It's way better programming practice to round explicitly and transparently than having DateDiff implicitly apply its unusual rounding.