![](/file/18315/Y2K_Resource_Nov99.iso/webcon~1/usa/year2k/images/spacer.gif)
Microsoft Year 2000 Readiness Disclosure
& Resource Center |
![](/file/18315/Y2K_Resource_Nov99.iso/webcon~1/usa/year2k/images/spacer.gif) |
![](/file/18315/Y2K_Resource_Nov99.iso/webcon~1/usa/year2k/images/spacer.gif) |
![](/file/18315/Y2K_Resource_Nov99.iso/webcon~1/usa/year2k/images/spacer.gif) |
Developing Year 2000 Compliant
Applications in Microsoft Visual Basic |
![](/file/18315/Y2K_Resource_Nov99.iso/webcon~1/usa/year2k/images/spacer.gif) |
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](/file/18315/Y2K_Resource_Nov99.iso/webcon~1/usa/year2k/images/vby2k02.gif) 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.
|