Microsoft Y2K  
Microsoft
 This static CD-based web site is representative of the www.microsoft.com/y2k site as of October 15, 1999.

Microsoft Year 2000 Readiness Disclosure & Resource Center
Developing Year 2000 Compliant Applications in Microsoft Visual Basic
4.  So How Does Visual Basic Help My Dating Success?

The Date Data Type

Visual Basic has had a dedicated Date data type since version 4.0. Prior to that (in versions 2.0 and 3.0), Visual Basic had a Date Variant type with the same storage pattern. Dates can be declared and used like this:

Dim dteMyDate As Date

dteMyDate = DateSerial(1998, 2, 12)

Or perhaps like this:

dteMyDate = #2/12/98#

The Date data type is actually stored as an IEEE double-precision floating point value, 8 bytes long. The data stored can represent dates from January 1 100 up to December 31 9999. Days are stored as whole numbers; zero is December 30 1899. Earlier dates are stored as negative values, later dates are positive. In the example above, February 12 1998 is stored as 35838. You can test this outcome with the following code:

MsgBox CDbl(DateSerial(1998, 2, 12))

The Date data type can also hold time information. Hours, minutes, and seconds are held as fractions. Noon is represented as 0.5. If you take the number of seconds in a day, 86400, and divide that into 1, the answer is the fraction equal to one second: 0.000011574à. The table below shows the minimum, default, and maximum values that can be stored in a variable declared as a Date.

. Date Value Stored
Minimum Value January 1 100 00:00:00 -657434
Default Value December 30 1899 00:00:00 0
Maximum Value December 31 9999 23:59:59 2958465.99998843

As shown, there is nothing wrong with the way Visual Basic stores dates. Its method is both compact and year 2000 compliant. For example, 8 bytes would store only the date if encoded as an alphanumeric CCYYMMDD. In effect, the Date data type allows you to store the time for free.

Manipulating Dates in Visual Basic

Once the dates are stored in Date variables, all the date manipulation functions become available. The benefits of these functions are obviousùthey are year 2000 compliant and leap year aware.

Visual Basic has a number of date manipulation functions. This section will examine some in detail. It might seem like I am telling you something you already know, but I have seen too many supposedly good Visual Basic developers remain unaware of the range of tools that are in the box.

Manipulating dates

Visual Basic provides a lot of properties and functions that support comparison and manipulation of dates. These properties and functions are designed to work with the Visual Basic Date data type and are recommended in preference to all other methods. The majority of these elements reside in the Visual Basic library in a class called DateTime. You can see the details of the class in Figure 1.


Figure 1   The VBA.DateTime class as seen in the Visual Basic Object Browser   (If your browser does not support inline frames, click here to view Figure 1 in a separate page.)

Tip   The use of IsDate is recommended for testing your expression prior to performing conversion functions.

The Calendar property

This property exposes the current calendar system in use within your application. By default it is set to vbCalGreg in the Gregorian calendar. Currently the only alternative is vbCalHijri, the Hijri calendar.

The Now, Date, Date$, Time, and Time$ properties

All these properties perform a similar task. They retrieve or assign the system date or time. By far the most used is the read-only Now property, which will return the current system date and time as a Visual Basic Date that can be assigned directly to a Date data type variable without conversion.

The Date and Time properties can be used to assign or return only the date or time part of the current system date. When assigning, the Date property expects to be passed a date expression containing the date to which you want to set the system date. Any time information is ignored. The date must be within the range shown in the table below. Dates outside this range will result in a run-time error (5 - Invalid Procedure Call Or Argument). The Date$ property returns and assigns dates from Strings, with the equivalent Date property using Variants.

Range for Visual Basic.DateTime.Date Windows 9x Windows NT
Minimum Date January 1 1980 January 1 1980
Maximum Date December 31 2099 December 31 2099

The Time and Time$ properties perform a task similar to Date and Date$, exposing the system time.

The Timer property

This property returns the number of seconds that have elapsed since midnight.

The DateDiff function

This function performs a comparison on two dates. The value that is returnedùthe difference between the two datesùis reported in a time or date unit of the callerÆs choosing. The answer will correctly reflect the fact that the year 2000 is a leap year. The following code displays the difference, in number of days (specified by the first argument), between the current system date and December 1 2000.

' Display the number of days until Dec 1 2000.
MsgBox DateDiff("d", Now, #12/1/2000# _
, vbUseSystemDayOfWeek, vbUseSystem)

The fourth and fifth arguments are each optional, allowing you to specify the first day of the week and the first week of the year. Both will default to the system values if omitted.

The DateAdd function

This function is used to modify a Visual Basic Date; the value returned is the new Date following modification. Again this routine is fully aware of the leap year rules. The following line of code adds one month to the date January 31 2000 and returns the result February 29 2000, correctly calculating that February will have 29 days in the year 2000.

' Add one month to Jan 31 2000.
MsgBox DateAdd("m", 1, CDate("31 Jan 2000"))

The Year, Month, and Day functions

The Format$ function is often abused when a programmer needs to get only part of the information held in a date. I still come across newly written code where Format$ has been used to do this.

' Getting the month of the current date, the old way.
iMonth = CInt(Format$(Date, "MM"))

' And how to do it the new, more efficient way.
iMonth = Month(Date)

Visual Basic provides the Year, Month, and Day functions to return these numeric values when passed a Date.

The Hour, Minute, and Second functions

Not surprisingly, these functions perform a similar task to the Year, Month, and Day functions described above, except that they will return the numeric values representing the components of the time held in a Visual Basic Date.

The DatePart function

This function returns the part of a passed date that you request in the unit of your choice. The above Year, Month, Day, Hour, Minute, and Second functions can perform the majority of the tasks that DatePart can, but the DatePart function offers more flexibility, as demonstrated in the following code:

' Get the quarter of the current date.
MsgBox DatePart("q", Now, vbUseSystemDayOfWeek, vbUseSystem)

The third and fourth arguments are both optional, allowing you to specify the first day of the week and the first week of the year. Both will default to the system values if omitted.

The Weekday function

This function will return the day of the week of the Date passed in as the first argument. The second optional argument allows you to specify the first day of the week.

' Get the current day of the week.
MsgBox Weekday(Now, vbUseSystemDayOfWeek)

The DateValue and TimeValue functions

These two functions perform conversions from a String date expression to a Date data type; in this case the conversion will be of only the date for DateValue and the time for TimeValue. These functions are useful if you want to separate the two parts of a date for separate storage.

One point to note with these two functions is that you can get a Type Mismatch error if any part of the expression you are converting is not valid, even the part you are not interested in. Executing the code below will cause this error, even though the time part of the expression is valid.

' Try this; it causes a Type Mismatch error!
MsgBox TimeValue("29 02 1900 12:15")

The DateSerial and TimeSerial functions

DateSerial and TimeSerial are less flexible than DateValue and TimeValue, requiring three numeric parameters to define the date or time you want to convert. The three parameters of the DateSerial function are the year, month, and day, in that order. TimeSerial expects hours, minutes, and seconds.

' Assign April 12 1998 to the date.
dteMyDate = DateSerial(1998, 4, 12)

' Alternatively, assign the time 12:00:00.
dteMyDate = TimeSerial(12, 00, 00)

Each of these functions has an interesting ability to accept values outside the normal range for each time period (excluding years). For instance, if you pass the year 1998 and 14 for the month to the DateSerial function, it will actually return a date in the second month of 1999, having added the 14 months to 1998. The following line of code illustrates this. (Your output might look different depending on your system settings, but the date will be the same.)

Debug.Print "The Date is " & Format$( _
DateSerial (1998, 2, 29), "Long Date")
The Date is 01 March 1998

In this instance, DateSerial has correctly determined that there is no February 29 in 1998, so it has rolled the month to March for the extra day. We can use this ability to write a function that indicates whether any year is a leap year.

Public Function IsLeapYear(ByVal inYear As Integer) As Boolean

IsLeapYear = (29 = Day(DateSerial(inYear, 2, 29)))

End Function

Formatting and displaying dates

These functions can be found in the VBA.Strings module. All these functions are aware of the current system locale settings. Any strings returned will be in the language and style of this locale.

Locales have different formats for such things as the date, time, and currency. For instance, a user on a computer in France would expect to read or enter date information in a familiar format. Microsoft Windows« operating system extends this formatting to cover common text such as the days of the week or the months of the year. Visual Basic is aware of the system locale and will use the information associated with it when interpreting and formatting dates.

The Format and Format$ functions

The Format function and the Format$ function are interchangeable. These functions return a string containing the passed date in the specified format. By default there are seven predefined date formats (see Table 8-3), of which Long Date and Short Date are the most useful; these two formats coincide with the formats set in the Regional Settings dialog box, shown in Figure 2. You can access this dialog box from the Regional Settings option in Control Panel. The user can modify both the Short Date and Long Date formats in the Date property page of this dialog box. These formats are directly supported by the Format$ function.

Image
Figure 2   The Windows Control Panel, Regional Settings dialog box.

If you convert a Date type to a string without applying a format, you will actually assign the date in General Date format. For the United States, this defaults to MM/dd/yy; for the United Kingdom and much of Europe it defaults to dd/MM/yy. The code extract below will display the date in a message box using the system General Date format. You can experiment by changing the Short Date and Long Date formats and rerunning the code.

Dim dteMyDate As Date

dteMyDate = DateSerial(1997, 2, 12)
MsgBox CStr(dteMyDate)

To use any named format other than General Date, you have to specify explicitly the format with the Format$ function. You can substitute the following line for the MsgBox line in the code above:

MsgBox Format$(dteMyDate, "Long Date" _
, vbUseSystemDayOfWeek, vbUseSystem)

The third and fourth arguments are both optional, allowing you to specify the first day of the week and the first week of the year. Both will default to the system values if omitted.

The format types are useful for displaying dates, either online or within reports. Here the user has some control over the format using Control Panel, and maintains consistency with many other applications.

Caution   The size of date and time formats can be changed. Because it is outside the applicationÆs direct control, allow sufficient space for any eventuality. Even when using the default General Date format you cannot assume a fixed length string. Dates in the twentieth century will be formatted with two-digit years; dates in any other century, however, will be formatted with four-digit years. This behavior is consistent, even when you move the system date into the twenty-first century.

Notice that the formats in the table below are purely for coercing a Date into a String; they have no effect on the date value stored. A Date displayed using the Short Date format will still hold century information, but it will be coy about it. The Short Date is particularly open to abuse, sometimes by so-called year 2000 experts convinced that the computer problem can be solved by allowing the Short Date format to include the century.

Format Name Description
General Date (Default) This will use the system Short Date. If the date to be displayed contains time information, this will also be displayed in the Long Time format. Dates outside 1930 to 2029 will be formatted with century information regardless of the settings for the Short Date format in the Regional Settings.
Long Date This will use the Regional Settings system Long Date format.
Medium Date This will use a format applicable to the current system locale. This cannot be set in the Regional Settings of the Control Panel.
Short Date This will use the Regional Settings system Short Date format.
Long Time This will use the Regional Settings system Time format.
Medium Time This will format the time using a 12-hour format.
Short Time This will format the time using a 24-hour format.

In addition to the predefined formats, you can apply your own formats. However, Regional Settings in Control Panel do not control nonstandard formats for display. If you are considering foreign markets for your software, you might have to modify your code for any change in regional date format (different United Kingdom and United States formats are an obvious example). My advice is to use only the default formats when possible.

Note   Format$, DateAdd, and DateDiff are a little inconsistent with the tokens they use to represent different time periods. Format$ uses n as the token for minutes and m or M for months. However, DateAdd and DateDiff expect minutes as m, and months as M. Because the Regional Settings dialog box also uses M, always use the upper-case letter when specifying the month in any of these functions.

If you convert a Date directly to a string without using Format, the resulting string will follow the general date rules except that dates outside the range 1930 to 1999 will be formatted with four-digit years, regardless of the settings for Short Date.

The FormatDateTime function

This function is new to Visual Basic in version 6.0. It works in a similar way to Format. However, FormatDateTime uses an enumerated argument for the format instead of parsing a string. This makes it less flexible than Format$, but faster. If you are going to use only the system date formats, I recommend that you use FormatDateTime instead of Format$, allowing cleaner code and a slight performance improvement.

' Print the current system date.
dteMyDate = FormatDateTime(Now, vbLongDate)

The MonthName function

Another addition to Visual Basic version 6.0, is MonthName, which returns a string containing the name of the month that was passed in as an argument of type long. This function replaces one of the tricks that Format$ had often been called upon to do in the past: getting the name of a month.

' Give me the full name of the current month, the old way.
MsgBox Format$(Now, "MMMM")

' Now do it the new way.
MsgBox MonthName(Month(Now), False)

This function has a second, optional Boolean argument that when set to TRUE will cause the function to return the abbreviated month name. The default for this argument is FALSE.

The WeekdayName function

WeekdayName is another addition to Visual Basic 6.0. It works in a similar way to MonthName except that it returns a string containing the name of the day of the week.

' Give me the name of the current day of the week,
' the old way.
MsgBox Format$(Now, "dddd", vbUseSystemDayOfWeek)

' Give me the full name of the current day of the week
' for the current system locale, the new way.
MsgBox WeekdayName(Weekday(Now, vbUseSystemDayOfWeek), _
False, vbUseSystemDayOfWeek)

Again, the remaining arguments are optional. The first, if set to TRUE, will cause the function to return the abbreviation of the day of the week; the second tells the function what day to use as the first day of the week.

The conversion and information functions

The last set of functions we are going to discuss are the conversion functions.

The CDate and CVDate functions

CDate and CVDate both convert a date expression (ambiguous or not) directly into a Date data type. The difference is that CVDate actually returns a Variant of type vbDate (7) and is retained for backward compatibility with earlier versions of the language. The following code demonstrates two different ways of using CDate to retrieve a Date.

Dim dteMyDate As Date

' This assigns December 31 1999 to the date...
dteMyDate = CDate("31 Dec 1999")

' ...and so does this.
dteMyDate = CDate(36525)

CDate and CVDate perform a similar function to the DateValue function in the DateTime library with two exceptions. First, they can convert numeric values to a Date. The example above shows CDate converting the numeric serial date value of 36525 to a date of December 31 1999. Second, they will include time information in the conversion if present.

These functions are in the VBA.Conversion module, along with the other conversion functions such as CLng and CInt.

The IsDate function

This function performs a simple but vital task. If passed a date expression, it will return TRUE if the expression can be successfully converted to a Visual Basic Date. This useful when validating dates from sources directly outside your control, such as the user.

If IsDate(txtDateOfBirth.Text) Then
' Convert the expression entered to a date.
dteDOB = CDate(txtDateOfBirth.Text)
Else
' Otherwise, inform the user of his or her mistake.
MsgBox "DonÆt be silly. That is not a valid date."
End If

To add a final bit of complexity, this function lives in a fourth module, VBA.Information.

<< 1 2 3 4 5 6 7 8 9 10 >>


Send This To a Friend


 

Wednesday, April 14, 1999
1998 Microsoft Corporation. All rights reserved. Terms of use.

This site is being designated as a Year 2000 Readiness Disclosure and the information contained herein is provided pursuant to the terms hereof and the Year 2000 Information and Readiness Disclosure Act.