Nice code, but may I suggest, as have the others here, that creating and
maintaining a holiday table is much easier and contains only 8 to 10
records
instead of 250 or more per year.
--
Arvin Meyer, MCP, MVP
http://www.datastrat.com
http://www.mvps.org/access
http://www.accessmvp.com
You can also enforce it by means of a referential operation. This
would
mean
that invalid dates would be prohibited however they are entered, so
control
is not exercised solely at form level, making the application more
bullet-proof. First you'd create a WorkdaysCalendar table, which is
simply a
table of all non-holiday weekdays over whatever period of time is
appropriate. This table can be created by calling the function below
as
follows, which you can do from the debug window (Press Ctrl+G to open
it).
Call the function like so to make a calendar from this year for 10
years
ahead for instance:
MakeCalendar "WorkdaysCalendar", #01/01/2007#, #12/31/2017#, 2,3,4,5,6
This will make a calendar of all weekdays over the period, so you then
need
to delete the rows for holidays. This can be done manually or via a
'delete'
query like so:
PARAMETERS [Enter holiday date:] DATETIME;
DELETE *
FROM WorkdaysCalendar
WHERE calDate = [Enter holiday date:];
Running this query will prompt for a date and then delete the date
entered
at the prompt from the table. A more flexible approach would be to run
a
query like this via a 'Holidays' dialogue form in which one or more
dates
can
be selected in a multiselect list box and then all deleted form the
table
at
a single button click.
Create a relationship between this table and the existing table on the
date
columns and enforce referential integrity. This will prevent any date
not
in
WorkdaysCalendar being entered into the existing table. In your form
you
can
control it at control level by putting this in the BeforeUpdate event
procedure of the date control:
Const conMESSAGE = "The date entered is a weekend or holiday date."
Dim ctrl As Control
Dim strCriteria As String
Set ctrl = Me.ActiveControl
strCriteria = "calDate = #" & Format(ctrl,"mm/dd/yyyy") & "#"
If IsNull(DLookup("calDate", "WorkdaysCalendar", strCriteria)) Then
MsgBox conMESSAGE, vbExclamation, "Invalid Date"
Cancel = True
End If
You might well find the table created is useful for other purposes,
e.g.
for
counting all working days between two dates, which you can do with the
DCount
function or in a query, to count the workdays per project in a Projects
table
for instance with ProjectStart and ProjectEnd date columns:
SELECT Project, COUNT(*) AS WorkdaysPerProject
FROM Projects INNER JOIN WordaysCalendar
ON (WorkdaysCalendar.caldate BETWEEN
Projects.ProjectStart AND Projects.ProjectEnd)
GROUP BY Project;
You can of course use the same function to create any other auxiliary
calendar tables which you might need.
Here's the code to create the calendar table. Paste it into any
standard
module in the database and call it as described above:
Public Function MakeCalendar_DAO(strTable As String, _
dtmStart As Date, _
dtmEnd As Date, _
ParamArray varDays() As Variant)
' Accepts: Name of calendar table to be created: String.
' Start date for calendar: DateTime.
' End date for calendar: DateTime.
' Days of week to be included in calendar
' as value list, e,g 2,3,4,5,6 for Mon-Fri
' (use 0 to include all days of week)
Dim dbs As DAO.Database, tdf As DAO.TableDef
Dim strSQL As String
Dim dtmDate As Date
Dim varDay As Variant
Dim lngDayNum As Long
Set dbs = CurrentDb
' does table exist? If so get user confirmation to delete it
On Error Resume Next
Set tdf = dbs.TableDefs(strTable)
If Err = 0 Then
If MsgBox("Replace existing table: " & _
strTable & "?", vbYesNo + vbQuestion, _
"Delete Table?") = vbYes Then
strSQL = "DROP TABLE " & strTable
dbs.Execute strSQL
Else
Exit Function
End If
End If
On Error GoTo 0
' create new table
strSQL = "CREATE TABLE " & strTable & _
"(calDate DATETIME, " & _
"CONSTRAINT PrimaryKey PRIMARY KEY (calDate))"
dbs.Execute strSQL
' refresh database window
Application.RefreshDatabaseWindow
If varDays(0) = 0 Then
' fill table with all dates
For dtmDate = dtmStart To dtmEnd
lngDayNum = lngDayNum + 1
strSQL = "INSERT INTO " & strTable & "(calDate) " & _
"VALUES(#" & Format(dtmDate, "mm/dd/yyyy") & "#)"
dbs.Execute strSQL
Next dtmDate
Else
' fill table with dates of selected days of week only
For dtmDate = dtmStart To dtmEnd
For Each varDay In varDays()
If Weekday(dtmDate) = varDay Then
lngDayNum = lngDayNum + 1
strSQL = "INSERT INTO " & strTable & "(calDate) " &
_
"VALUES(#" & Format(dtmDate, "mm/dd/yyyy") &
"#)"
dbs.Execute strSQL
End If
Next varDay
Next dtmDate
End If
End Function
Ken Sheridan
Stafford, England
:
i am still learning and would like the help of the group. i have a
from
that
has a date field. i will like to restrict the input dates to only
business or
non holiday dates (no weekends). restriction should include a message
that
the date entered is invalid. thanks for your help