Microsoft Access VBA Tutorials for self-paced learning, Class Modules, SQL Techniques, and AI Integration Guides.

Thursday, April 24, 2008

Days in Month Function

Function to Calculate Number of Days

The User-Defined Function DaysM() given below can be used in calculations that involve the number of days of a particular month. Copy and paste the following Code into a Global Module and save it in your Project.

Function VBA Code

Public Function DaysM(ByVal varDate) As Integer 
Dim intYear As Integer
Dim intmonth As Integer

On Error GoTo DaysM_Err

If Nz(varDate) = 0 Then
    DaysM = 0    
    Exit Function
End If

intYear = Year(varDate)
intmonth = Month(varDate)

DaysM = Day(DateSerial(intYear, intmonth + 1, 1) - 1)

DaysM_Exit:
Exit Function
DaysM_Err:
MsgBox Err.Description, , "DaysM()"
DaysM = 0
Resume DaysM_Exit
End Function

Syntax: X = DaysM(varDate)

Replace the varDate parameter with a valid Date. The Number of Days for the Month will be returned in Variable X.

The Parameter value can be a valid Date, a Date in Text format like "15-02-2008", or its corresponding numeric value 39493.

If you would like to rewrite the Function differently by adding a few extra lines of code, then you may replace the expression DaysM = Day(DateSerial(intYear, intmonth + 1, 1) - 1) with the following lines of code:

DaysM = Choose(intmonth, 31, 28 + IIf((intYear Mod 4) = 0, 1, 0), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)

If intmonth=2 then
   Select Case (intYear Mod 400)
       Case 100, 200, 300
            DaysM = DaysM - 1
   End Select
End if

Usage Options

This Function can be used in VBA Routines, Queries, or Text Controls in Forms or Reports where the number of days of a particular month is involved in calculations.

Example: An Employee resumed duty after her vacation on 15-02-2008. To calculate the balance number of days for her salary payment, one of the three Expressions given below can be used.

Dt = #02/15/2008#

BalDays = 1 + DateDiff("d", Dt, DateSerial(Year(Dt), Month(Dt) + 1, 1) - 1) 

or

BalDays =   1 + Day(DateSerial(Year(Dt), Month(Dt) + 1, 1) - 1) - Day(Dt) 

or

BalDays = 1 + DaysM(Dt) - Day(Dt)

The first two calculations are performed using built-in functions. The `DaysM()` function, which uses the second expression for its primary calculation, produces the same result with fewer characters in the final expression.

Determining the number of days in a month is generally straightforward. We commonly use simple rules to remember that April, June, September, and November (months 4, 6, 9, and 11) have 30 days, while February has 28 days. February alone requires additional calculations to determine whether an extra day should be added in a leap year. A commonly used rule is that a year evenly divisible by 4 is treated as a leap year.

However, this rule requires refinement when dealing with century years. For example, February had 29 days in the year 2000 because it was a leap year. In contrast, the years 1700, 1800, and 1900 were not leap years, despite being evenly divisible by 4. Similarly, the years 2100, 2200, and 2300 will also be treated as common years.

The leap year rule is based on the Earth's orbital period around the Sun. A calendar year is commonly approximated as 365.25 days, with every fourth year designated as a leap year containing 366 days by adding one extra day to February.

However, the Earth's actual orbital period is approximately 365 days, 5 hours, 48 minutes, and 45.5 seconds (365.2422 days). Using an average of 365.25 days takes an excess of approximately 0.0078 days each year. Over a period of about 400 years, this accumulates to approximately 3.12 extra days. To compensate for this excess, century years that are not evenly divisible by 400 are treated as common years, even though they are evenly divisible by 4.

The remaining excess of approximately 0.12 days accumulates to about 1.2 days over 4,000 years. Consequently, under this extended rule, the year 4000 is treated as a common year, even though it is evenly divisible by 400.

Who knows, before then, another scientific discovery may require us to revise the entire system once again.

References: Microsoft Encarta Encyclopedia

History of Calendar.

The Roman Calendar

The original Roman calendar, introduced around the 7th century BC, consisted of 10 months and a Total of 304 days, with the year beginning in March. Later in the same century, two additional months—January and February—were added. However, because the months contained only 29 or 30 days, an extra month had to be inserted approximately every second year to keep the calendar aligned with the seasons.

Days within each month were identified using the Roman system of counting backward from three fixed dates: the Calends, the first day of the month; the Nones, the ninth day before the Ides; and the Ides, which fell on the 13th day in some months and the 15th day in others. Over time, the Roman calendar became increasingly disordered because the officials responsible for adding days and months often manipulated the calendar to extend their terms of office or to hasten or delay elections.

In 45 BC, Julius Caesar, advised by the Greek astronomer Sosigenes (flourished in the 1st century BC), introduced a purely solar calendar. This system, known as the Julian calendar, established the common year as 365 days and designated every fourth year as a leap year with 366 days. The term leap year originates from the effect of the extra day in February, which causes dates after February to occur two weekdays later than in the previous year, rather than one weekday later as in a common year. The Julian calendar also established the order of the months and the seven-day week that form the basis of the modern calendar.

In 44 BC, Julius Caesar renamed the month Quintilis to Julius (July) in his own honor. Later, the month Sextilis was renamed Augustus (August) to honor Caesar Augustus, Julius Caesar's successor. Some authorities maintain that Augustus also established the lengths of the months as they are used today.

The Gregorian Calendar.

The Julian year was 11 minutes and 14 seconds longer than the solar year. This discrepancy accumulated until by 1582 the vernal equinox (see Ecliptic) occurred 10 days earlier, and Church holidays did not occur in the appropriate seasons. To make the vernal equinox occur on or about March 21, as it had in AD 325, the year of the First Council of Nicaea, Pope Gregory XIII issued a decree dropping 10 days from the calendar. To prevent further displacement, he instituted a calendar, known as the Gregorian calendar, which provided that century years divisible evenly by 400 should be leap years and that all other century years should be common years. Thus, 1600 was a leap year, but 1700 and 1800 were common years.

The Gregorian calendar, or the New Style calendar, was slowly adopted throughout Europe. It is used today throughout most of the Western world and in parts of Asia. When the Gregorian calendar was adopted in Great Britain in 1752, a correction of 11 days was necessary; the day after September 2, 1752, became September 14. Britain also adopted January 1 as the day when a new year begins. The Soviet Union adopted the Gregorian calendar in 1918, and Greece adopted it in 1923 for civil purposes, but many countries affiliated with the Greek Church retain the Julian, or Old Style, calendar for the celebration of Church feasts.

The Gregorian calendar is also called the Christian calendar because it uses the birth of Jesus Christ as a starting date. Dates of the Christian era (see Chronology) are often designated AD (Latin anno domini, "in the year of our Lord") and BC (before Christ). Although the birth of Christ was originally given as December 25, 1 BC, modern scholars now place it as about 4 BC.

Because the Gregorian calendar still entails months of unequal length, so that the dates and days of the week vary through time, numerous proposals have been made for a more practical, reformed calendar. Such proposals include a fixed calendar of 13 equal months and a universal calendar of four identical quarterly periods.

Source: Microsoft Encarta Encyclopedia

Earlier Post Link References:

Friday, April 18, 2008

Finding Consecutive Workdays with Query

Finding Consecutive Workdays with Query.

How can we determine whether date values within a certain range are consecutive or intermittent?

Let’s use a real-world example:

A company hires temporary workers on a daily wage to complete a project within 15 days. Workers are informed that if they work 8 hours a day for 7 consecutive days (no weekends or breaks), they will receive a special incentive in addition to their daily wages.

In practice, employees joined on different dates, and not all could maintain a full 7-day streak. Attendance is logged in a table by date and employee code.

After the project ends, we are tasked with identifying which employees worked 7 straight days to award the incentives.

This is actually quite simple to solve—just three queries are enough.

A Table with Sample Data.

Step 1 – Table Structure

Create a new table in Design View with the following fields:

Field NameData TypeDescription
empShort TextEmployee code (e.g., E001, E002)
workdateDate/TimeThe date the employee worked

Step 2 – Primary Key

  • Select both fields (emp and workdate) together.

  • Right-click → Primary Key.
    This ensures no duplicate date entries are accepted for the same employee.

Solution

  1. Query1:

  2. Create a Total Query grouped by emp, take the minimum value from workdate to find the work-start date of each employee, and create a new column, adding 6 days to the work-start date to calculate and store the 7th Day-Date of work for each employee. They must work from the work-start date to this date without a break for a special eligibility incentive.
  3. SQL: Query1

    SELECT Table1.emp,
     Min(Table1.workdate) AS min_date,
     Min([workdate])+6 AS Day7Date
    FROM Table1
    GROUP BY Table1.emp;
  4. Query2: Join Table1 with Query1 on the emp field and select records using the Day7Date as a criterion on workdate that falls on or before the Day7Date.

    SQL: Query2 

    SELECT Table1.* 
    FROM Query1 INNER JOIN Table1 ON Query1.emp = Table1.emp
    WHERE (((Table1.workdate)<= [Day7Date]));
    
  5. Query3: Create a Total Query using Query2 as a source. Group on the 'emp' field, take the count of workdate, and filter the output with workdate Count =7.

SQL: Query3 

SELECT Query2.emp,
 Count(Query2.workdate) AS [count]
FROM Query2
GROUP BY Query2.emp
HAVING (((Count(Query2.workdate))=7));

The continuity of dates is validated at the employee level, based on each employee’s individual work start date. All employees will work within the same month or start on a specific date.

However, when the data file contains a large number of records spanning different periods and only records from a particular period need to be evaluated using this method, it’s important to first filter the data. To do this, create a query using Table1, applying the desired Start Date and End Date as criteria to extract only records within that range. Then, use this filtered query as the source for Query1 and Query2 described earlier.

As the saying goes, “There’s more than one way to skin a cat,” we can take an alternative approach to solve this problem by slightly differentiating how the earlier queries are defined. The SQL strings for this alternative method are provided below. Copy them and create the queries to try out this method as well.

Query 1_1 SQL

SELECT Table1.emp,
 Min(Table1.workdate) AS min_date,
 [min_date]+0 AS day1,
 [min_date]+1 AS day2,
 [min_date]+2 AS day3,
 [min_date]+3 AS day4,
 [min_date]+4 AS day5,
 [min_date]+5 AS day6,
 [min_date]+6 AS day7
FROM Table1
GROUP BY Table1.emp;

Query 2_1 SQL

SELECT Table1.emp,
 Table1.workdate
FROM Query1_1 INNER JOIN Table1 ON Query1_1.emp = Table1.emp
WHERE (((Table1.workdate) In ([day1],[day2],[day3],[day4],[day5],[day6],[day7])));

Query 3_1 SQL

SELECT Query2_1.emp,
 Count(Query2_1.workdate) AS CountOfworkdate
FROM Query2_1
GROUP BY Query2_1.emp
HAVING (((Count([Query1_2].[workdate]))=7));

I have not tested these methods extensively to eliminate side effects. You may use them at your own risk.

Do you have different ideas? Please share them with me by posting them in the Comments Section.

Friday, April 11, 2008

Transparent Command Button

Transparent Command Button.

Command buttons on forms can be hidden by setting their Transparent or Visible property value = 'No', and then made visible again when a specific condition is met or when a particular user opens the form.

Example:
In a secured database where a form is routed through a network for data verification and approval by multiple users, you could:

  • Create separate command buttons for each user role.

  • Show each button only when the relevant user opens the form.

  • Base visibility on the verification status set by users of a lower rank.

The most common approach in such scenarios is not to hide the button, but to disable it while keeping it visible, and then enable it when required. Setting an active button’s Enabled or Visible property cannot be set to 'No'. You must first move the focus to another control before making the change in VBA.

The Transparent property does not have this limitation. You can make a command button invisible by setting the Transparent Property value to'Yes'.

However, there is a side effect:
If a user knows the exact location of the invisible button, clicking that spot will still trigger its action. To prevent this, you can “park” the invisible button in a different location at runtime by modifying its Left property.

  • Before moving the button, save its current Left position to a module-level global variable.

  • When it’s time to restore the button, use the saved value to reposition it in its original location.

Designing a Table and Form.

Here, we will use the Transparent Command Button for a Main Switchboard Menu.

  1. Design a Table using the Structure shown below and enter a few sample records as given below.

  2. Use the Form Wizard to design a Tabular Form for the above table and save it with the name DataFiles.

  3. Open the Form in Design view. Retain the ID Desc fields, and remove other columns. Keep the Shift Key down and click on both Fields to select them together. Or click outside the Fields and drag the mouse over to select them both.

  4. Display the Property Sheet (View -> Properties) and change the Following Property Values.

    • Enabled = No

    • Locked = Yes

    • Top = 0.0417"

    • Height = 0.1771"

    • Back Style = Normal

    • Back Color = -2147483633

    • Special Effect = Raised

    • Border Style = Solid

    • Border Color = 0

    • Border Width = Hairline

    • ForeColor = 0

  5. Select View Menu and remove the check mark from the Form Header/Footer Option. Select Yes to the Warning message to delete the Header/Footer Sections from the Form.

  6. Click the top left corner of the Form to deselect all controls and select the Form. Display the Form Property Sheet (View -> Properties) and change the following Form Property Values.

    • Form Width = 2.5417"

    • Default view = Continuous Forms

    • Views Allowed = Form

    • Allow Edits = No

    • Allow Additions = No

    • Allow Deletions = No

    • Record Selectors = No

    • Navigation Buttons = No

    • Dividing Lines = No

    • Scrollbars = No

    • Border Style = None

    • Control Box = No

    • Min Max Buttons = None

    • Close Button = No

    • What this Button=No

    • Allow Design Changes = Design View Only

  7. Draw a Command Button about the size of both Field widths put together somewhere below the Fields so that we can modify the properties of the Command Button and place it over both the Fields in a transparent state.

  8. Select the Command Button and display the Property Sheet. Change the following Property Values:

    • Name = cmdMenu

    • Transparent = Yes

    • Height = 0.1771"

  9. Click on the On Click Property and select Event Procedure from the Dropdown List, and click on the Build (...) button to open the Form's VBA Module.

    Here we can write code to test the ID Value of the record clicked by the User and open the Form corresponding to that Number.

    The VBA Code for a simple method to test and open the Form corresponding to the record ID  that received the click is given below.

  10. Copy and paste the following code into the VBA Module of the DataFiles Form and save the Form.

    Private Sub cmdMenu_Click()
    Dim IDNumber As Integer, strForm As String
    
    IDNumber = Me![ID]
    strForm = ""
    Select Case IDNumber
        Case 1
           strForm = "CRREQ_MASTER"
        Case 2
           strForm = "Dept_Codes"
        Case 3
           strForm = "Branch"
    End Select
    If Len(strForm) > 0 Then
       DoCmd.OpenForm strForm, acNormal
    End If
    End Sub
    

    Note: A more powerful and reusable method for handling this functionality is explained in my earlier article, Opening Access Forms. I recommend going through that article, as the method described there is very simple to implement in any project.

    In this example, the sample table shown earlier has been adapted from that article’s example, with additional fields (Forms, Macro, and Type). If you use the code provided in that article, you can add any number of records to this table without needing to test each ID value individually, as was required in the earlier approach.

    This method also allows you to:

    • Open a form directly, or

    • Run a process via a macro and, at the end of the process, open a form to display results.

    You can control this behavior by setting the Type field value to 0 or 1 when inserting a new record.

    To implement this with your command button, drag the transparent button (or, for precise positioning, use Ctrl + Arrow Keys in Office 2000 or the Arrow Keys alone in Office 2003 after selecting it) and place it directly over the ID and Desc fields, as shown below.

  11. Click on the Detail Section of the Form and Display the Property Sheet. Change the Details Section height.

    • Detail Section Height = .25"

    The completed form design will appear as shown in the image below when viewed in Normal View. This form will function as a subform on the Control Screen (Main Switchboard) for our Data Files menu.

    If you prefer not to display the serial numbers on the left side, simply set the Visible property of that field to No in the Property Sheet.


    Trial Run

    Open the Main Switchboard form of your project (or any other form you’d like to test with) and drag the form you created in the previous step onto it.

    In my example, I placed the menu form on the sample Switchboard form used in the Colorful Command Buttons article.

  12. Click on the Sub-Form, display the Property Sheet, and change the following Property Values:

  • Special Effect = Flat

  • Border Style = Transparent

The transparent command button instances now appear above each record in the form and will respond to user clicks. Using VBA, you can detect which record was clicked and open the form associated with that record’s ID.

When new records are added to the menu table, they will automatically appear in the menu—no design changes required.

Test the menu by replacing the sample form names in the code with actual form names from your project.

  1. Command Button Animation
  2. Double Action Command Button
  3. Colorful Command Buttons
  4. Transparent Command Button
  5. Command Button Animation-2
  6. Creating an Animated Command Button with VBA
  7. Command Button Color Change on Mouse Move

Friday, April 4, 2008

Colorfull Command Buttons

Gradient-Colored Command Buttons.

We have seen the Double-Action Command Button in an earlier Post and Command Button Animation before, and now it is time to add some color to the Command Buttons. Take a look at some different Command Buttons in action on a Control Screen (Main Switchboard) of a sample MS-Access Application.

Would you like to use these colorful buttons in your own application?

You might be expecting a long lecture from me about their setup — maybe a hundred lines of VBA code tucked away at the end of this article for you to copy and paste. Or perhaps you’re bracing yourself to download some MS Access add-ons, link a couple of library files, and wrestle with complex installations.

Well… none of that is needed.

In fact, you can create one of these buttons in just two minutes — maybe three the first time you try. Once you’ve made one, you can produce variations in under a minute.

Here’s the twist: these buttons are not created inside MS Access at all. Instead, we make them in MS Word (or Excel, if you prefer), then copy and paste them straight into an Access form. After that, just tweak a few settings in the Property Sheet, add maybe one or two lines of VBA for animation, and you’re ready to roll. 

Designing the Button.

  1. Open your MS Access project and open a form in Design View.

  2. Launch MS Word and check whether the Drawing Toolbar is visible at the bottom, just above the status bar.

    • If it’s not visible, go to View → Toolbars → Drawing.

    • If the Drawing Toolbar button is already visible, then click it to display the toolbar.

  3. On the Drawing Toolbar, click AutoShapes → Basic Shapes → Rounded Rectangle.

  4. Draw a Rounded Rectangle on the Word document.

  5. Right-click the shape you just created and choose Format AutoShape from the shortcut menu.

  6. In the Format AutoShape dialog box, go to the Colors and Lines tab.

  7. Under the Fill group, open the Color drop-down list to select your preferred fill color.

  8. Click on the Yellow color on the Color Palette, and then click on the Fill Effects. Control.

  9. In the Fill Effects dialog box, select the Gradient tab.

    • Under Shading Styles, choose Vertical.

    • In the Variants section, click the shape at the bottom right corner.

    • The selected gradient will appear under the Sample preview on the right.

  10. Click OK, and then click OK again in the Format AutoShape dialog to apply the chosen gradient to the Rounded Rectangle.

  11. Right-click the shape and select Edit Text from the shortcut menu.

  12. Type the button caption—for example, Data Files. Highlight the text and apply the desired formatting using Word’s standard tools:

    • Align Center

    • Bold

    • A font color that provides good visibility against the gradient background.

  13. Note: Once you copy and paste the button into an MS Access form, you cannot change its caption or formatting there. It’s a good practice to keep a copy of the original buttons in the Word document. If you need changes later, edit them in Word, then copy and paste the updated version into Access.

    You can make copies of this Button and follow from Step 5 above to change the Gradient Color and Caption.

  14. Tips: You can easily change the shape of your created buttons:

    • On the Drawing toolbar in Word, open the Draw menu.

    • Select Change AutoShape, then choose any shape you prefer for your button.

    To insert the button into Access:

    • Right-click the button in Word and choose Copy from the shortcut menu.

    • Minimize Word and return to the Access form you have open in Design View.

    • Right-click in the form’s Detail or Footer section where you want the button placed, and choose Paste.

    • Drag and position the button to the desired location.

      Adjusting the button display in Access:

    • Right-click the pasted button in Access and select Properties.

    • Move the Property Sheet so it does not overlap the button.

    • Locate the Size Mode property and experiment with the available settings:

      • Clip

      • Zoom

      • Stretch

    • When Zoom is selected, the button resizes proportionally, maintaining the height-to-width ratios. However, it may leave a gap around the image. You can fill this background area with the Form’s background color so the gap is not visible when the form opens in Normal View.

  15. If the button is in the Footer Section of your Form, then click on the Footer Section of the Form to select it and display the Property Sheet.

  16. Copy the Back Color Property Value of the Form.

  17. Click on the button to display the Property Sheet of the Button.

  18. Paste the value in the Back Color property copied from the Form.

  19. Change the Special Effect Property to Raised.

  20. Change the Border Style Property to Transparent.

  21. Now you can program your Colorful Command Button like a normal MS-Access Command Button.

    If you look at the Property Sheet of this Command Button, you can see that all the essential Properties and Events are available for Event Procedures, Hyperlinks, Macros, etc.

    I will give you one line of code to give some life (Animation) to this Button so that it will respond when the mouse moves over it.

  22. Click on the Button's Mouse Move Property and select Event Procedure. Copy the following Code between the Empty Subroutine lines.

     Me.OLEUnbound257.SpecialEffect = 2

  23. Copy the correct name of the Button from its Name Property and paste it to replace OLEUnbound257. Mind the dot separator after the word Me. And at the beginning of SpecialEffect, while pasting the Button Name.

  24. Select the Form's Section (Detail or Footer, or Header) where you have placed the Command Button and display the Property Sheet.

  25. Click on the Mouse Move Property and select Event Procedure, copy and paste the above line of Code with the Button Name changed, and paste between the empty Subroutine lines.

  26. Change the Value 2 to 1.

  27. Animating the Button.

    Initially, the Button will be in a Raised Style. When the mouse is moved over the Button, it will be pushed-in (Sunken). When the Mouse is moved out of the Button, it will restore to the raised state. If you repeat this action in quick succession, the Animation will be more evident.

    We will learn some more tricks with Command Buttons.

     What do you think about them?

     

    1. Command Button Animation
    2. Double-Action Command Button
    3. Colorful Command Buttons
    4. Transparent Command Button
    5. Command Button Animation-2
    6. Creating an Animated Command Button with VBA
    7. Command Button Color Change on Mouse Move

Powered by Blogger.