-
1
- #1
Mike Lewis
Programmer
I was interested in Griff's offering in thread184-1817870. I'm constantly finding a need for this sort of date-manipulation function. With that in mind, I decided to resurrect one that I wrote several years ago, which determines the Nth occurrence of a given weekday (e.g. the 1st Monday or the 3rd Thursday) in a given month and year. It will also find the last occurrence, such as the last Sunday.
The parameters should be self-explanatory, but if you are in doubt, read the comments at the top of the code. I've tried to make it as straightforward as possible.
I'd be grateful for your comments, corrections and bug reports.
Mike
__________________________________
Mike Lewis (Edinburgh, Scotland)
Visual FoxPro articles, tips and downloads
The parameters should be self-explanatory, but if you are in doubt, read the comments at the top of the code. I've tried to make it as straightforward as possible.
Code:
FUNCTION OrdinalDay
LPARAMETERS tnOrdinal, tnDay, tnMonth, tnYear
* Determines the date corresponding to the Nth weekday
* (for example, the 1st Monday or the 3rd Wednesday) of a
* given month and year; can also determine the last
* of a given weekday in the month and year.
* Parameters:
* - The ordinal (1 = 1st, 2 = 2nd, etc) or -1 for the last.
* - The weekday (1 = Monday, 2 = Tuesday, etc)
* && note: for this purpose, weeks start on Monday
* - The month (1 - 12); defaults to current month
* - The year; defaults to current year (must be later than 1752 because
* of a quirk in VFP's GOMONTH() function)
* Examples:
* - OrdinalDay(2, 4, 6, 2024) to find the 2nd Thursday in June 2024
* - OrdinalDay(-1, 1, 12, 1900) to find the last Monday in December 1900
* - OrdinalDay(1, 7) to find the first Sunday in the current month and year
* Returns:
* The speficied date; returns an empty date if the specified date does
* not exist(which will occur if the ordinal is 5 and the specified month
* and year does not have five of the specified days).
LOCAL llParamsOK, lnFirstOfMonth, lnDaysInMonth, lnDayOffset, ;
lnWeekOffset, ldResult
* Deal with default parameters
tnMonth = EVL(tnMonth, MONTH(DATE()))
tnYear = EVL(tnYear, YEAR(DATE()))
* Validate parameters
llParamsOK = ;
BETWEEN(tnMonth, 1, 12) AND ;
BETWEEN(tnYear, 1753, 9999) AND ;
(BETWEEN(tnOrdinal, 1, 5) OR tnOrdinal = -1) AND ;
BETWEEN(tnDay, 1, 7)
IF NOT llParamsOK
ERROR "Invalid parameters(s)"
ENDIF
*Day of week on which first of the month falls
lnFirstOfMonth = DOW(DATE(tnYear, tnMonth, 1), 2)
* No. of days in the month
lnDaysInMonth = DAY(GOMONTH(DATE(tnYear, tnMonth, 1),1) - 1)
lnDayOffset = tnDay - lnFirstOfMonth + 1
IF lnDayOffset < 1
lnDayOffset = lnDayOffset + 7
ENDIF
lnWeekOffset = IIF(tnOrdinal = -1, ;
IIF(lnDayOffset + 28 > lnDaysInMonth, 21, 28), ;
(tnOrdinal - 1) * 7)
* Calculate the required date, or make it blank if it does not exist
ldResult = ;
IIF (lnDayOffset + lnWeekOffset > lnDaysInMonth, ;
{}, ;
DATE(tnYear, tnMonth, lnDayOffset + lnWeekOffset))
RETURN ldResult
I'd be grateful for your comments, corrections and bug reports.
Mike
__________________________________
Mike Lewis (Edinburgh, Scotland)
Visual FoxPro articles, tips and downloads