Microsoft Year 2000 Readiness Disclosure
& Resource Center |
|
|
|
Year 2000 Date Support in
FoxPro |
|
For FoxPro and
Visual FoxPro developers, the transition to the year 2000 presents a
number of issues to be aware of so that the applications you build
will be fully year 2000 compliant and function with the behavior you
desire after the turn of the century.
This
paper is meant to help you identify year 2000 issues that may be
present in your applications and to suggest solutions that you can
provide.
It has
always been easy to create year 2000 compliant applications in all
versions of FoxPro. The latest versions of Visual FoxPro include
enhanced language features to make this process even easier. Because
FoxPro is a development language and application tool, it has always
been possible for developers to create applications that will not
perform as desired after the turn of the century. If you have
identified and resolved potentially ambiguous dates during the
development and testing of your applications, they may already be
year 2000 ready. If not, this paper will help you do so now.
If you
have Visual FoxPro 6.0, you may also want to consult the Help files.
They contain detailed information on new features that make it even
easier to identify potential year 2000 issues in your FoxPro
applications.
To help
you get started, here is a summary of some potential year 2000
issues.
Quick Reference of Date Issues
Issue |
Description |
Dates in tables
|
Dates stored in tables
are represented as 8-byte numeric values and are year 2000
compliant. |
Dates in code
|
Dates hard-coded in
source code are determined at compile time based on SET
CENTURY and SET DATE settings. One way to avoid ambiguous
dates is by using strict date formatting (Visual FoxPro 5.0
and later). The default setting for SET CENTURY is OFF. If
your application uses dates before 1900 or after 1999, we
recommend that you change this to ON and adjust your
applications to display years in 4 digits. If your
applications receive 2-digit year entry or display years in
only 2 digits you should provide data validation in code to
determine the desired century. FoxPro interprets 2-digit years
as 20th century dates if SET CENTURY is OFF. If SET CENTURY is
ON, how 2-digit dates entered in a 4-digit field are
interpreted by default depends upon the FoxPro version you are
using. Visit MicrosoftÆs Year 2000 Readiness Disclosure &
Resource Center, http://www.microsoft.com/year2000/,
and see the appropriate sections of this paper for information
on your version. |
Functions that produce
ambiguous dates |
The functions most
susceptible to date ambiguities include YEAR( ),
MONTH( ), CTOD( ) and CTOT( ). Without strict
date formatting, their values are determined by the SET
CENTURY and SET DATE settings. |
Macro substitutions
and expressions at runtime |
The SET STRICTDATE
command helps detect date ambiguities. While it works at both
compile time and runtime, issues detectable only at runtime
such as macro substitutions and EVAL( ), property, index
tag, and report expressions, and so on, are harder to track
down. |
Converting "{ à }"
date expressions |
If you are using
Visual FoxPro 5.0 or later, you should search your code for
date expressions using the { } format and consider using
the new strict date format or the enhanced DATE( ) and
DATETIME( ) functions. |
CTOD( ) and
CTOT( ) usage |
If you are using
Visual FoxPro 6.0 and your application has SET CENTURY OFF,
you should search your code for CTOD( ) and CTOT( )
commands and change them to DATE( ) or DATETIME( )
functions. Also, consider using DTOS( ) instead of DTOC( ) if
converting from a date to character expression. The DTOS( )
function will always return a 4-digit year regardless of the
SET CENTURY setting. |
FDATE( ) and
LUPDATE( ) usage |
For versions prior to
Visual FoxPro 6.0, you should search your code for
LUPDATE( ) and replace it with FDATE( ) since
LUPDATE( ) reads the .dbf file header, which only stores
a 2ùdigit year for the last update.
|
Ambiguous Dates
As a
FoxPro or Visual FoxPro developer, you probably already know that
year 2000 issues are nothing more than a special case of data
ambiguity. When you eliminate ambiguous references to dates, your
applications will become year 2000 compliant, so long as you are
using the unambiguous dates appropriately for your application. So,
what do we mean by date ambiguity?
LetÆs
take a look at a date you might have stored in a program file:
{10/11/12}
Obviously, this date may have different meanings to different
people:
- If you are a librarian cataloging old books, you may assume
that the date represents October 11, 1912.
- If you are working for a US brokerage firm calculating yields
on 30-year bonds, you may interpret the date as October 11, 2012.
- Finally, if youÆre an economist in Europe forecasting economic
trends, you might see this date as November 10, 2012.
In fact,
the date constant {10/11/12} could represent October 11, 1912,
October 11, 2012, November 10, 1912, November 12, 1910, or November
12, 2010 depending on factors such as context and local date
standards. In FoxPro and Visual FoxPro, the value represented by
this ambiguous date constant is determined by the settings of the
SET CENTURY and SET DATE commands.
Since
FoxPro and Visual FoxPro are developer products used for creation of
database applications around the world in a variety of contexts
(e.g., storage of historical as well as contemporary data),
developers need to understand how the rich date-related language
affects their applications.
It is
easy to determine, by reading the product documentation and entering
some sample dates, how FoxPro and Visual FoxPro products resolve
ambiguous dates by default. For example, the FoxPro 2.6 manual
states that the default for SET CENTURY is OFF and that all dates
with 2-digit years are interpreted as in the 20th century (19xx).
This may be fine for the librarian above who is entering dates for
antique books. However, the stockbroker might want to change SET
CENTURY to ON so that full 4-digit year dates may be entered. (This
is the easiest method for any application since it eliminates entry
of ambiguous dates). If you permit 2-digit dates to be entered with
SET CENTURY ON, you can determine how they will be interpreted if
you wish to change the default behavior for the version of FoxPro
you are using. By default in FoxPro 2.6, for example, 2-digit dates
are interpreted with SET CENTURY ON to be in the 20th century
(19xx). You can change this by writing validation or resolution
code. Note: even with SET CENTURY OFF, developers can easily write
validation or resolution code (e.g., Valid snippet, Valid event,
LostFocus event, etc.) to resolve input of ambiguous dates since
FoxPro tables store the full unambiguous date.
In
summary, if you can eliminate ambiguous dates from your FoxPro or
Visual FoxPro application, and ensure that you are handling the
unambiguous dates correctly, your applications should be year 2000
ready.
How to use this Document
Your
approach to dealing with year 2000 compliance in your applications
should include a two-step process of Detection and
Correction. This paper is organized around these
concepts and is designed to help you understand what you need to do
to ensure that your applications will function in the manner your
customers expect after 1999.
Detection
The most
important, and perhaps most time-consuming, part of resolution is
detection. You need to examine your code, including forms, reports,
labels, tables, views, and query fields for unambiguous date
formatting. Of course data entry and display controls also need to
be examined. You also need to check for use of ambiguous dates
within code and other FoxPro files. So, where do you start?
The
following set of steps provides a good framework for investigating
year 2000 compliance in your applications:
- Read this entire paper to fully understand the year 2000
issues associated with each version of FoxPro. Over the years, new
features have been added to Visual FoxPro to make it even easier
to detect and resolve year 2000 issues.
- Review your application and check the forms (screens) and
reports for formatting and other issues related to dates. The
first step in doing this would be to ensure that SET CENTURY is ON
if you use dates before 1900 or after 1999. If you permit the
entry of 2-digit years, you need to assign them to the correct
century for your application. If you are using Visual FoxPro 5.0
or later, you can use the SET CENTURY TO nCentury ROLLOVER nYear
syntax for date windowing if you choose to leave SET CENTURY OFF.
If you are using an earlier version, you can easily write data
validation code to interpret 2-digit years.
- Use the Visual FoxPro 6.0 SET STRICTDATE command. When you SET
STRICTDATE to 1 or 2, this command will detect ambiguous dates
when you compile and run your application. Even if your
application is written in FoxPro 2.x, you can compile and run the
code in Visual FoxPro 6.0, make any desired changes, and then
recompile back in FoxPro 2.x.
- Investigate the code directly, searching for potential issues.
You can use the Visual FoxPro Filer utility to search for specific
strings in your source files, such as "CTOD(", that may cause
undesired behavior.
- Test your application under an actual year 2000 situation by
setting the Windows system to a twenty-first century date. When
you do this, make sure you close all other applications that may
be adversely impacted by the system date change. For example, with
Microsoft Outlook you may have configured it to automatically
delete e-mail messages that are older than a certain period of
time. By setting your system date ahead a few years, todayÆs
e-mail messages would now appear to be outdated. In addition, you
might trigger unnecessary meeting reminders.
Correction
After
you complete the investigation phase and have detected any year 2000
issues, you will want to make adjustments to your applications.
The
following list suggests modifications that you can make to your
applications. The remainder of this document describes them in more
detail.
- Resolve any ambiguous dates that are hard-coded in source
code. These are dates affected by SET CENTURY and SET DATE.
- Ensure that SET CENTURY is ON and use 4-digit year entry if
you want to use dates before 1900 or after 1999. This may require
some minor resizing of date fields on forms and reports. However,
it eliminates questions as to what the date input really
represents. If this is not feasible, or if your application
permits 2-digit dates to be entered with SET CENTURY ON, you
should add validation code where data input of dates is made in
order to assign 2-digit years to the desired century.
- In Visual FoxPro 5.0 and later, ensure SET CENTURY TO à
ROLLOVER is correctly set for your application needs. This will
vary based on the nature and context of your application. (Note:
with SET CENTURY ON, this setting is needed only if you permit the
entry of 2-digit years.)
- In Visual FoxPro, ensure that the Textbox Century property is
set to 1 (ON) to provide for entry of 4-digit dates. Otherwise you
should add data validation code to the Textbox Valid and/or
LostFocus events.
- In Visual FoxPro, ensure that Textbox DateFormat and Format
properties are properly set for your specific application needs to
avoid SET DATE issues.
- In Visual FoxPro 6.0, change CTOD( ) and CTOT( )
functions to use enhanced Date( ) and DateTime( )
functions.
Visual
FoxPro 6.0 added features to help you analyze your programs and
applications to determine if there is code that may provide or
accept ambiguous date information. These features, as well as other
commands and functions, make it easy to resolve year 2000 issues.
If you
find year 2000 issues in your code, the resolution can be obvious or
subtle. In general, resolution consists of changing ambiguous date
entry and display formats in control design (how big a field is, how
many digits are required), and using the SET CENTURY, DATE( )
and DATETIME( ) commands appropriately.
LetÆs
take a closer look at some of the issues.
Detection of Date Issues
The
"year 2000 problem" is primarily an issue of data ambiguity. Any
program that uses or accepts only two digits to represent the year
may lead to unintended application behavior. There are many ways of
handling this issue. Some solutions are easy.
As you
begin looking for problems in your applications, you need to be
aware of the product areas that are affected by dates. In order to
do this, you need to understand how dates are stored in FoxPro.
Dates Stored in Tables
For most
applications, dates are stored in Date fields. The good news is that
Date fields always store full 4-digit year precision, so there is no
ambiguity in a date contained in a Date (or DateTime) field.
All
versions of FoxPro provide a Date field type. All
versions of Visual FoxPro also provide a DateTime
field type. FoxPro stores Date type fields in a YYYYMMDD format as follows:
Figure
1 Data Type Storage Differences (If your
browser does not support inline frames, click here to view Figure
1 in a separate page.)
Date
types use 8 bytes per field per record on disk and are stored
internally as numeric values. This size is not affected by the
settings of SET CENTURY or any input masks you might have on a
textbox for data entry to a date field. This ensures that full,
unambiguous dates are stored independent of application logic.
Data
type |
Description |
Size |
Range
|
Date |
Chronological data
consisting of month, year, and day |
8 bytes |
When using strict date
formats, {^0001-01-01}, January 1st, 1 A.D to {^9999-12-31},
December 31st, 9999 A.D. |
DateTime |
Chronological data
consisting of month, year, day, and time |
8 bytes |
When using strict date
formats, {^0001-01-01}, January 1st, 1 A.D to {^9999-12-31},
December 31st, 9999 A.D., plus 00:00:00 a.m. to 11:59:59 p.m.
|
Dates Stored in Code
In the
Date column of Figure 1, you see how it is possible to store
ambiguous date information in code. Applications may not correctly
interpret a value. In the case of a value such as "02/16/56", FoxPro
and Visual FoxPro do not know if the year refers to 1956 or 2056 (or
even 1856) and must therefore make an assumption based on various
settings.
Additionally, one could have a date such as "01/02/56" in
which the day and month are not easily determined. In the case of
"01/02/56", the format could either be mm/dd/yy or dd/mm/yy. Because
of this, functions such as YEAR( ), MONTH( ), CTOD( )
and CTOT( ) are susceptible to date ambiguities.
Dates
are stored in code as they are entered. There are several ways to
enter dates in code.
Dates Entered as Strings
The
following example shows how a date may exist in code when stored
hard-coded as a string: myDate = "02/01/56"
This is
not a recommended way to store a date in code. Your application
needs to handle this value appropriately for the application, and
cannot rely on features such as System Regional settings.
In fact,
dates stored in the above format are often converted for comparison
against Date or DateTime fields as in the following example: myDate = "02/01/56" IF CTOD(myDate) > myDateField ENDIF
You
should avoid this approach to storing dates in code. There are
better ways to store dates. Some are described below.
Dates Entered as Dates
When you
need to store hard-coded dates in Visual FoxPro, use the Date curly
braces { } as shown in this example: myDate = {02/01/56}
When you
use the Date curly braces, the value is interpreted as a date, so
Visual FoxPro stores the full date, including a 4-digit year, in
compiled code. The value is set at compile time and not runtime. In
the preceding code, notice that there is only a 2-digit year date.
When this date is compiled, FoxPro must make an assumption about
which 4-digit year date to store.
The year
that FoxPro assumes for a compiled date is based on the value of SET
CENTURY. The full syntax for SET CENTURY in Visual FoxPro 6.0 is:
SET
CENTURY ON | OFF | TO [nCentury [ROLLOVER nYear]]
Over the
years, new features have been added to this command to enable
ambiguous years in dates stored in code to be interpreted in the way
you wish even more easily. The following table summarizes the
differences in the SET CENTURY command among versions of FoxPro and
Visual FoxPro.
Version |
SET
CENTURY |
Date
Interpretation |
FoxPro 2.x |
SET CENTURY ON | OFF
|
With CENTURY OFF,
there is no way to set an implied year, so all years are
interpreted as 20th century dates (19xx). 2-digit years
entered with SET CENTURY ON are also interpreted as 20th
century dates (19xx) by default. |
Visual FoxPro 3.0
|
SET CENTURY ON | OFF
|
With CENTURY OFF,
there is no way to set an implied year, so all years are
interpreted as 20th century dates (19xx). 2-digit years
entered with SET CENTURY ON are also interpreted as 20th
century dates (19xx) by default. |
Visual FoxPro 5.0
|
SET CENTURY ON | OFF |
TO [nCentury [ROLLOVER nYear]] |
The implied year is
based on the value of SET CENTRY TOàROLLOVER. SET CENTURY TO
without any arguments always sets year to 20th century (19)
and rollover to 0. |
Visual FoxPro 6.0
|
SET CENTURY ON | OFF |
TO [nCentury [ROLLOVER nYear]] |
The implied year is
based on the value of SET CENTRY TOàROLLOVER. SET CENTURY TO
without any arguments sets year to current century as set in
your System Date/Time Control Panel and rollover to current
century plus 50. |
In the
following example, you can eliminate the century ambiguity by
requiring 4-digit year data entry, but you still need to ensure that
there is no confusion as to the order in which days and months are
entered in your application. You can use the Regional Control Panel
settings to easily eliminate this confusion. The SET DATE command
can also help. myDate = {02/01/1856}
In
Visual FoxPro 5.0 and later, developers can eliminate all ambiguity
in hard-coded dates stored in code by using the new strict date
format ({^yyyy/mm/dd}): myDate = {^1856/01/02}
This
strict date format is ideal for developers creating applications
they intend to distribute globally. Visual FoxPro 6.0 also includes
the SET STRICTDATE command, which allows you to check for code that
does not adhere to the new strict date format.
Dates Determined at Runtime
You need
to be careful when the value of dates in code is determined at
runtime. Commands to scrutinize include:
- Macro Substitution (&)
- EVALUATE( )
The SET
STRICTDATE command works both at compile time and runtime. However,
dates evaluated at runtime using macro substitution or the
EVALUATE( ) function will not be detected when you compile a
program. The following example illustrates this (assume SET
STRICTDATE = 1): #DEFINE MYDATE {02/02/02} #DEFINE MYDATE2 '{02/02/02}'
myDate3 = MYDATE2
? DATE( ) > MYDATE && generates compile and runtime errors ? DATE( ) > EVAL(myDate3) && generates runtime error only
Remember, it is much easier to check code by compiling than
to test all the code paths at runtime. You can use the FILER utility
to search source code for "&" and "EVAL".
Dates Stored in FoxPro Files
Table Headers
The
FoxPro table (.dbf ) file stores information in the header that
specifies when the table was last updated. This information is
stored in byte offset 1 û 3 in a format of YYMMDD. It is based on
the original dBase (.dbf ) file format and has changed little since
its inception in the early æ80s. As you can see, the year is stored
in only 2 digits.
The
LUPDATE( ) function returns the date when the table was last
updated. In versions prior to Visual FoxPro 6.0, this date is read
directly from the .dbf table header. Because only the last two
digits are stored, you cannot determine the century in which the
table was updated; it defaults to the 20th century (19xx).
In
Visual FoxPro 6.0, LUPDATE( ) now queries the Windows operating
system to determine the date a table was last updated, allowing you
to determine the century in which the table was updated. Still, the
table header just stores the last two digits of the year it was last
updated. This is done to ensure backward compatibility with other
versions of FoxPro and Xbase languages.
In
applications created using versions of FoxPro earlier than 6.0, you
should replace LUPDATE( ) with the
FDATE( <tablename> ) function, which returns the
full date.
Index Tag Expressions
FoxPro
uniquely allows you to create index tags on expressions as well as
on field names. An expression can consist of any valid FoxPro
expression including the use of a date. For example, the following
code is perfectly valid in FoxPro: INDEX ON hiredate > {02/01/56} TAG mydate ? KEY( ) && displays "HIREDATE>{02/01/56}"
As you
can see, the Key expression contains an ambiguous date format. And
based on the values of SET CENTURY and SET DATE, the sort order of
your table may not be as expected.
Watch
carefully for such issues and use Strict Date formatting whenever
possible. INDEX ON hiredate > {^1956/02/01} TAG mydate
Property Memos
Visual
FoxPro forms and classes have Property Sheets which allow you to set
the value of properties to both literal values and expressions.
These can of course contain dates or expressions that evaluate to
dates.
Note Reports and labels also allow
you to set certain properties of the data environment.
The
contents of the Property Sheet are stored in the Properties memo
field of .scx and .vcx files. There is an important distinction
between date values or expressions stored in the Properties memo and
those in code.
Properties are evaluated and set at runtime, not compile
time. Because of this, the SET STRICTDATE command will not affect
date values or expressions in properties. Method code in .scx and
.vcx files is compiled and stored in the Objcode memo, so SET
STRICTDATE does check for date ambiguities in this code.
One way
to test your Properties memo fields is to copy the contents to a
.prg file, using STRTOFILE( ), and compile the file. Since the
properties are simply stored as property sets, most lines will
compile without difficulty. There are a few issues to handle if you
write a routine to check Properties memos:
- Certain properties may be set to a variable or array that is
not in scope, such as Value = myVar, since the application is not
actually executing. The workaround for this is to have your error
handler ignore this situation.
- The Properties memo stores child or leaf object settings for
container objects. For example, the Properties memo field for a
Grid record in a .scx or .vcx file stores both grid and child
properties. You can workaround this by having your routine parse
for periods (".") before the equal operator ("=") and have the
entire expression replaced with a single random variable name.
Remember, your goal is to check the expression on the right side
of the "=" sign for date problems.
Report, Label and Menu Expressions
You will
need to check report and label expressions since these are also
evaluated at runtime, and may cause undesirable behavior if they
contain dates that are not strict date compliant.
Menu
expressions are unlikely to cause problems because the full .mpr
file is compiled at design-time after being generated from the .mnx
file. Therefore menus behave like normal .prg files and allow for
easy detection of strict date issues (unless they include macro
substitution or EVAL( ) expressions).
DBC Meta Data
You
should treat DBC extended meta data as you do properties. You may
need to copy the contents of the Property memo to a separate program
file in order to compile it for testing using the SET STRICTDATE
command. Working with the DBC Property memo requires a little more
work than with .scx and .vcx files since the properties are stored
together, delimited by special characters. In general, it is
unlikely that your DBC databases will have problems, but it is
always a good idea to check. You might simply perform a substring
search of the Property memo field for occurrences of {, CTOD or
CTOT.
Stored
Procedures are handled by the SET STRICTDATE command just like any
program file.
#INCLUDE Files
You can
include #DEFINE preprocessor directives in code that contains date
constants. The rules about using dates in #DEFINEs are the same as
the rules governing dates in code. Make sure that you use the strict
date format, {^yyyy/mm/dd}, whenever possible. Because #DEFINEs are
handled at compile time, the Visual FoxPro 6.0 SET STRICTDATE
command traps for these types of errors. #DEFINE MYDATE {02/02/02} IF DATE( ) > MYDATE ENDIF
Timestamp Fields
If you
look at FoxPro Screen (Form), Report, Label and Menu files, you will
find that they each contain a Timestamp field. The Timestamp field
is used, primarily, with the FoxPro 2.x Transporter when converting
or updating files that are shared or ported between platforms such
as DOS to Windows). The timestamps do not contain any date
ambiguities, so there are no potential issues with conversions.
In
Visual FoxPro, the Transporter is bound into the Converter and is
only triggered when you convert an older FoxPro file from a
different platform. Again, there are no year 2000 implications with
the Timestamp field.
Data Input Implications
Visual
FoxPro as a database development product, provides a number of
options for data input. Data input is usually done through forms
(screens). You can, however, also input data directly (buffered or
unbuffered) through a Browse window. And input can be made directly
to native Fox tables or against remote ODBC data sources.
As with
most year 2000 issues, data input is heavily affected by SET CENTURY
and SET DATE settings. The following table shows commands and
associated properties (for objects such as Textbox controls) that
affect date input.
Command |
Property |
SET CENTURY |
Century |
SET DATE |
DateFormat |
SET MARK TO |
DateMark |
SET STRICTDATE
|
StrictDateEntry
|
Read the
Visual FoxPro 6.0 help documentation regarding the SET STRICTDATE
command and StrictDateEntry property since they are loosely related.
Note The StrictDateEntry property
isnÆt affected by the setting of SET STRICTDATE.
For
backward compatibility, the default setting of SET CENTURY is OFF.
However, the default value for the Century property in Visual FoxPro
6.0 is 1 (ON).
Note The default setting for the
Century property was changed to 1 in Visual FoxPro 6.0. In earlier
versions of Visual FoxPro, the default is 2 (OFF).
FoxPro 2.x Data Input
With
FoxPro 2.x screens, data input is usually performed using @àGET/READ
or BROWSE/EDIT. As mentioned before, input can be made directly to
the FoxPro table, but many FoxPro developers prefer using
SCATTER/GATHER into memory variables. If you use SET CENTURY ON and
require years to be entered in 4 digits you will have few data entry
issues. If your applications permit the entry of 2-digit years with
SET CENTURY ON, you can easily provide code validation code to
assign dates to the desired century. By default, 2-digit years
entered with SET CENTURY ON are interpreted as 20th century dates
(19xx).
Data
input with SET CENTURY OFF implies that the value entered will be
set to the 20th century since only 2 digits are used for the year in
the input mask. Remember, prior to Visual FoxPro 5.0, there was no
SET CENTURY TOàROLLOVER command. This behavior can be changed by
using data validation and resolution code to adjust the century.
Developers of FoxPro 2.x applications should consider
changing the SET CENTURY setting to ON if years before 1900 or after
1999 are used. You can easily ensure that your applications function
as expected in the year 2000 and after by enforcing code validation
of date input and writing code to assign ambiguous 2-digit years to
the proper century for your application.
Visual FoxPro Data Input
Visual
FoxPro still supports data input via BROWSE and @àGET. However, most
Visual FoxPro applications use object-oriented forms and controls.
Note The SET CENTURY ON/OFF setting
controls how dates are displayed in a BROWSE. With Visual FoxPro,
the full 4-digit year is always displayed when the date field is
selected, regardless of this setting.
Visual
FoxPro makes it even easier to resolve ambiguous dates with the SET
CENTURY TO à ROLLOVER command. However, there is still potential for
ambiguity based on Century and DateFormat property settings. You
should ensure that the Century property is set to 1 (ON) for your
textbox controls (in Visual FoxPro 6.0, this is the default). The
DateFormat property accepts values of Short (13) and Long (14),
which allow the format to be based on the Windows Control Panel
short and long date setting (these correspond to YS and YL settings
for the Format property).
Coding to Resolve Date Ambiguity
Much of
this document describes ways you can eliminate ambiguous dates in
your FoxPro and Visual FoxPro applications directly using native
FoxPro and Visual FoxPro language. Ambiguous dates are primarily the
result of your application having SET CENTURY set to OFF or
permitting 2-digit year entry with SET CENTURY ON. This section
describes date validation and resolution coding techniques you can
use in your applications. These code techniques are described below,
but letÆs first review recommended options for various versions of
FoxPro and Visual FoxPro.
- FoxPro 2.x applications û the easiest way to eliminate
ambiguous dates and make your applications year 2000 compliant is
to change the SET CENTURY setting to ON, make minor adjustments to
resize date input controls, and require the entry of 4-digit
years. If your applications permit the entry of 2-digit years with
SET CENTURY ON, you can easily provide data validation code to
assign dates to the desired century.
- Visual FoxPro 3.0 applications û if possible, change SET
CENTURY to ON, make minor adjustments to resize date input
controls, and require the entry of 4-digit years. If your
applications permit the entry of 2-digit years with SET CENTURY
ON, you can easily provide data validation code to assign dates to
the desired century.
- Always ensure that the Century property of your Textbox
controls is set to 1 (CENTURY = ON).
- Visual FoxPro 5.0 and 6.0 applications - while SET CENTURY ON
is always recommended, these applications can employ SET CENTURY
TOàROLLOVER to interpret ambiguous dates. Again, this setting
should be made based on the context of your application. Also,
ensure that the Century property of your Textbox controls is set
to 1 (CENTURY = ON).
You may
have older FoxPro 2.x and Visual FoxPro 3.0 applications that canÆt
easily be altered to use SET CENTURY ON. For these applications, you
should analyze the use of dates in these applications, especially
where dates are entered. If you determine that there are places
where ambiguous dates can be input, you should consider adding code
to assign the ambiguous dates to the desired century.
Controls in Visual FoxPro 3.0
To
reiterate, one of your first strategies should be to change the
Century property setting of Textboxes to 1 (ON). If this is not
feasible, code can be added to Valid and LostFocus events of
controls such as Textboxes to offer the same behavior as the SET
CENTURY TOàROLLOVER command. The following sample illustrates how
you might do this. * Valid/LostFocus event LOCAL ldGetDate, lcMonth, lcDay, lcYear, lnRollover lnRollover = 1950 ldGetDate = THIS.Value IF YEAR(ldGetDate) < lnRollover lcMonth = STR(MONTH(ldGetDate)) lcDay = STR(DAY(ldGetDate)) lcYear = STR(YEAR(ldGetDate)+100) ldGetDate = CTOD(lcMonth+"/"+lcDay+"/"+lcYear) ENDIF THIS.Value = ldGetDate
If the
ControlSource property is bound to a field (which happens when you
dragdrop a field from data environment onto the form), the field is
automatically updated when the Value property changes. If your
control is not bound directly to a field, you may need to add
additional code such as: REPLACE mydatefld WITH THIS.Value
The lnRollover variable should be based on the context
of your application. Also, ensure that the SET DATE setting is
appropriate since CTOD( ) is being used.
Browse and Edit Windows
Some
developers like to use Browse and/or Edit Windows to allow users to
edit data directly against a table. The BROWSE command provides the
ability to do record-level validation. The following excerpt is from
the Browse help topic:
VALID lExpression2
Performs record-level validation in a Browse
window. The VALID clause is executed only if a change is made to
the record and you attempt to move the cursor to another record.
The VALID clause is not executed if the only change is to a memo
field.
If VALID returns a value that is true (.T.), the user can move
the cursor to another record. If VALID returns a false value
(.F.), the cursor remains in the current field and Visual FoxPro
generates an error message. If VALID returns 0, the cursor remains
in the current field, and an error message isn't displayed.
The VALID clause shouldn't be confused with the verify option
(:V), which enables field-level validation.
:F
Forces the VALID clause to execute before the user moves the
cursor to the next record. In this case, VALID is executed even if
the record isn't changed.
The
following code shows an example of how you might code date
validation for a Browse Window. BROWSE VALID CheckDate() PROCEDURE CheckDate() PRIVATE ldGetDate, lcMonth, lcDay, lcYear, lnRollover lnRollover = 1950 ldGetDate = mydatefld IF YEAR(ldGetDate) < lnRollover lcMonth = STR(MONTH(ldGetDate)) lcDay = STR(DAY(ldGetDate)) lcYear = STR(YEAR(ldGetDate)+100) ldGetDate = CTOD(lcMonth+"/"+lcDay+"/"+lcYear) REPLACE mydatefld WITH ldGetDate ENDIF
Keep in
mind that with record-level validation you donÆt necessarily know if
the contents of your date field changed. So, you may want to use the
:V option to perform validation at the field-level. This should,
again, be determined by the context of your application.
FoxPro 2.x @àGet Commands
For
FoxPro 2.x applications, screens are used to handle much of your
data input. The Screen Builder automatically generates @àGET/SAY,
READ code via the GENSCRN.PRG program.
You can
easily add date validation or resolution to this code using the
Valid snippets at either the field or READ level. The code is
essentially the same as described in the preceding sections. You
first trap the date entered by the user and then check to see if it
is ambiguous and adjust accordingly.
Many
FoxPro 2.x applications use an Indirect READ strategy where the
field values of a record are first SCATTERed to memory variables
(memvars). And depending on the developerÆs preference, edits are
made directly against data or to the memvars. In either case, since
original values are preserved, a user can easily cancel his/her
edits (e.g., GATHER) without data loss. You can interpret an
ambiguous date for either the memvar or field. Regardless of the
setting of SET CENTURY or whether you perform date validation or
resolution against the memvar or field directly, FoxPro will ensure
the entire 4-digit year is preserved.
Using Default Values
One way
to help users enter unambiguous dates is through the use of default
values. Not only does the use of default values enhance user
productivity, it also gives developers more control of date handling
based on the context of the specific application. For example, an
order entry application might default to todayÆs date for an
OrderDate field when a new order (record) is added. An application
that stores historical U.S. Civil War data might use a default value
of 01/01/1860 for an EventDate field. By having preset values placed
in a Date field, the user may be more aware of the date being saved.
When used together with data validation and resolution, default
settings can help interpret ambiguous dates.
Date Language
This
section describes Visual FoxPro language features that are related
to year 2000 support. These language categories summarize Visual
FoxPro 6.0 commands related to year 2000 support.
Date Formatting
SET
CENTURY, SET DATE, SET MARK TO, SET FDOW, SET FWEEK
SET
SYSFORMATS, SET DATASESSION
Date Checking
SET
STRICTDATE
File Dates
LUPDATE( ), FDATE( )
Date Manipulation
DATE( ), DATETIME( ), YEAR( ), MONTH( ),
DAY( ), HOUR( ), MINUTE( ), SEC( )
WEEK( ), DOW( ), CDOW( ), CMONTH( ),
GOMONTH( )
Date Conversion
CTOD( ), CTOT( ), DTOC( ), DTOT( ),
DTOS( ), TTOC( ), TTOD( ), MDY( ), DMY( )
Textbox Date Properties
Century,
DateFormat, DateMark, StrictDateEntry
The
Visual FoxPro Help file provides more details and descriptions of
these commands, functions, and properties. The remainder of this
section discusses specific language that developers should examine
because of year 2000 implications.
Language Possibly Affected by Year 2000
Certain
commands, including YEAR( ), MONTH( ), CTOD( ), and
CTOT( ) can, potentially, return unintended date values. LetÆs
look at these functions and how they may affect year 2000 compliance
in your applications.
YEAR( )
Some
Date ambiguities donÆt produce errors; they generate data that may
be ambiguous or unintended for the context of your application.
For
instance, unless you SET CENTURYàROLLOVER (Visual FoxPro 5.0 and
later) properly within applications that span the change of century,
your code could display and store an unintended date.
Assumption: The system date is in the 20th century, e.g.,
October 2, 1998, and your existing code attempts to access the date.
? YEAR({10/2/98}) && displays "1998"
Then
you get to the year 2000 (the 21st century) and your code tries to
access October 2, 2000. ? YEAR({10/2/00}) && displays "1900"
In
this case, the year 1900 is displayed. To avoid this situation,
you need to SET CENTURY and use the ROLLOVER clause of the command
as in the following code. SET CENTURY TO 19 ROLLOVER 99
? YEAR({10/2/00}) && displays "2000"
This
way Visual FoxPro assumes any number less than 99 starts with "20"
(therefore existing in the 21st century). If you now try to run
the original code, you end up with a year of 2098 (see below)
which also is not desirable. So, you need to make sure you set the
rollover value to an appropriate setting for your application.
? YEAR({10/2/98}) && displays "2098"
Of
course, if in the year 2000 you want to access the date in 1998, the
default SET CENTURY is just fine. Again, this setting should be made
based on the context of your application. For dates in which you
specify the year with two digits, SET CENTURY TO determines in which
century a year occurs. This is why encouraging developers to use
strictly formatted dates is a good choice; itÆs a case of æmoreÆ
being æbetterÆ. This subtlety also illustrates why using the code
thoroughly during testing is important.
Use the
SET STRICTDATE command to force your program to generate errors if
it encounters code with ambiguous dates.
MONTH( )
The
MONTH( ) function is similar to YEAR( ) in that its value
can vary depending on the value of certain date settings. SET
CENTURY can cause the value of YEAR( ) to vary based on its
setting. The SET DATE command determines what MONTH( ) will
return.
The SET
DATE help topic shows the date formats for this setting. For
example:
SET DATE TO AMERICAN
|
mm/dd/yy |
SET DATE TO GERMAN
|
dd.mm.yy
|
You
should consider using the SET DATE TO SHORT/LONG values since these
are based on the system Control Panel Regional setting. By doing
this, you can better prepare your applications so that they can be
deployed on machines around the world. It is recommended that your
dates not be formatted for a specific local format.
By using
the enhanced Visual FoxPro 6.0 DATE( ) and DATETIME( )
functions, you can ensure that your calls to MONTH( ) always
return the correct value regardless of the SET DATE setting.
CTOD( ) and CTOT( )
If you
are using Visual FoxPro 6.0, you should avoid using CTOD( ) and
CTOT( ) since they are rarely needed and can usually be
replaced by the enhanced DATE( ) and DATETIME( )
functions, which remove any ambiguity in the date. Round-trip
conversions from CTOD(DTOC( )) and CTOT(TTOC( )) are
inherently ambiguous.
Consider
the following common code, which can cause unintended results:
REPLACE field2 WITH CTOT(DTOC(DATE( )) + " " + TIME( ))
Situations in which you might consider using CTOT( ) and
CTOD( ) include parsing user input from a character-based
TextBox or EditBox, or parsing a text file that contains formatted
dates. In both cases, SET DATE and SET CENTURY govern how the
character fields are interpreted, so they should be used with care.
DTOC( ) and TTOC( )
Inversely related to the CTOD( ) and CTOT( ) functions, DTOC(
) and TTOC( ) convert from date/datetime expressions to a character
strings. The results returned by these functions vary based on the
values of SET CENTURY and SET DATE. Therefore, they can lead to
ambiguous results. Round-trip conversions, such as CTOD(DTOC( ))
shown in the above topic, can lead to unintended results in the
context of your application.
LUPDATE( )
This
function returns the date on which a table was last updated.
LUPDATE([nWorkArea | cTableAlias])
Prior to
Visual FoxPro 6.0, this value was read directly from the .dbf table
header, which stores the year in only 2 digits. With Visual FoxPro
6.0, the value returned is now the operating system file last update
attribute.
If you
are using LUPDATE( ) in older versions of FoxPro, you should
consider switching your code to use FDATE( ) instead. Otherwise
you should write your own rollover routine when evaluating LUPDATE(
).
The
following code snippet shows an example of how you could write your
own routine to handle LUPDATE( ) if you choose not to use FDATE( ).
LOCAL ldGetDate, lcMonth, lcDay, lcYear, lnRollover
lnRollover = YEAR(DATE())
ldGetDate = LUPDATE()
IF YEAR(ldGetDate) < lnRollover
lcMonth = STR(MONTH(ldGetDate))
lcDay = STR(DAY(ldGetDate))
lcYear = STR(YEAR(ldGetDate)+100)
ldGetDate = CTOD(lcMonth+"/"
+lcDay+"/"+lcYear)
ENDIF
This
sample assumes that the SET DATE command is set to the desired order
of the day and month.
Language for Manipulating Dates
FoxPro
and Visual FoxPro applications often require dates to be passed
around. The formatted value of the dates can vary based on the SET
CENTURY and SET DATE settings. This can affect the year 2000
compliance of your applications. In Visual FoxPro 6.0, the
DATE( ) and DATETIME( ) functions have been enhanced to
make it even easier to pass dates unambiguously. By using
DATE( ) and DATETIME( ), you can often eliminate the need
for using CTOD( ) and CTOT( ) functions, which can lead to
ambiguous results.
DATE( )
The
Date( ) function exists in all versions of FoxPro. By itself,
the function returns the current system date, which is controlled by
the operating system.
In
Visual FoxPro 6.0, this function has been enhanced to allow for the
optional passing of parameters.
DATE([nYear, nMonth, nDay])
When
valid year, month and day parameters are passed, DATE( )
returns a year 2000 compliant Date value which can then be used in
your application as an unambiguous date not dependent on SET CENTURY
or SET DATE.
DATETIME( )
The
DateTime( ) function exists in all versions of Visual FoxPro.
By itself, the function returns the current system datetime, which
is controlled by the operating system.
In
Visual FoxPro 6.0, the function has been enhanced to allow for
parameters to be optionally passed in.
DATETIME([nYear, nMonth, nDay [, nHours [, nMinutes [,
nSeconds]]]])
When
valid parameters are passed in, DATETIME( ) returns a year 2000
compliant DateTime value which can then be used in your application
as an unambiguous datetime not dependent on SET CENTURY or SET DATE.
DTOS( )
With
many applications, it is necessary to convert dates to strings so
that you can manipulate and work with them in your application. The
DTOS( ) function is highly recommended for this purpose, especially
when working with Date and DateTime fields, since it always returns
the character string in a YYYYMMDD format. Since
the format is fixed, it is unaffected by both SET CENTURY and SET
DATE settings. The DTOC( ) and TTOC( ) functions return strings that
will differ based on SET CENTURY and SET DATE settings.
Language for Controlling Dates
SET CENTURY TO
As shown
in the SET CENTURY table earlier in this paper, this command has
been enhanced over various versions of Visual FoxPro to make it even
easier to resolve ambiguous dates. These enhancements are provided
for convenience and do not offer capabilities not already available
through the use of code in FoxPro 2.x. Remember, many of your
ambiguous date issues can be eliminated with SET CENTURY ON.
There
are several key points with SET CENTURY:
- SET CENTURY ON/OFF controls two things: 1) number of digits
displayed for year portion of date and 2) assumed century for a
2-digit year.
- SET CENTURY OFF is the default setting and causes only 2
digits to be displayed for the year in date expressions. This
default is for the purpose of preserving compatibility with all
versions of FoxPro and Visual FoxPro, as well as other common
Xbase languages such as dBase and Clipper.
- With SET CENTURY OFF, since only 2 digits are used for the
year, all dates are assumed to be in the 20th century (19xx) for
purposes of calculations.
- SET CENTURY TO ROLLOVER is available in Visual FoxPro 5.0 and
later, and allows you to control the assumed year for dates used
when SET CENTURY OFF. It also allows for a rollover value since
many applications contain dates that span multiple centuries.
Note SET CENTURY OFF
always implies dates in the 20th century. However, the new SET
CENTURY TO syntax takes precedence over this setting. So, with
Visual FoxPro 5.0 and later, the SET CENTURY ON/OFF setting only
controls the number of digits displayed.
The
value of SET CENTURY TO is scoped to the current data session.
In
Visual FoxPro 5.0, issuing SET CENTURY TO without any additional
parameters sets the century to 19 and rollover to zero. With Visual
FoxPro 6.0, the default ROLLOVER value for SET CENTURY has been
changed to the last two digits of the current year (determined by
the system) plus 50 years. If the current year is 1998, nYear is 48, the last two digits of 2048 (1998 +
50).
SET DATE TO
The SET
DATE command controls the format for display of date and datetime
expressions. As with SET CENTURY, this command is scoped to the
current data session (Visual FoxPro). As mentioned throughout this
paper, date ambiguity is not limited to the year. The day and month
can also be misinterpreted. Consider the following date:
{01/02/03}
Depending on the setting of SET DATE, this date could
represent the month of January or February. When you develop your
applications, think about worldwide implications. Americans are
familiar with dates being formatted as mm/dd/yy (e.g., 01/31/62),
whereas Germans are used to a format of dd.mm.yy (e.g., 31.01.62).
The SET DATE command controls the display format for dates and
allows developers to easily create applications which can be used
globally.
Strict Date Formats
Normally, Date and DateTime constants or expressions are
interpreted based on the current settings of SET DATE and SET
CENTURY at the time the constants or expressions are compiled or
evaluated. This means that many date constants are ambiguous since
they might evaluate to different values depending upon when they
were compiled and what date settings were in effect at compilation
time.
For
example, is the date constant {10/11/12} October 11, 1912, October
11, 2012, November 10, 1912, November 12, 1910, or November 12,
2010?
The
correct answer depends on the current settings of SET DATE and SET
CENTURY TO. This possibility for ambiguity can introduce unexpected
results into existing Visual FoxPro code wherever Date or DateTime
constants or expressions are either compiled or are evaluated at run
time, such as in report and object expressions. This can introduce
year 2000 noncompliance into existing code when the setting of SET
CENTURY rolls over into the year 2000 and a 4-digit year isn't
specified.
Visual
FoxPro 5.0 and 6.0 provide an unambiguous strict date format. A
strict date always evaluates to the same Date or DateTime value
regardless of any date settings. The strict date format is:
^yyyy-mm-dd[,][hh[:mm[:ss]][a|p]]
The
caret character (^) always denotes the strict date format and causes
Dates and DateTimes to be interpreted in a YMD format. Valid Date
and DateTime separators are hyphens, forward slashes, periods, and
spaces.
Empty
Dates and DateTimes are considered unambiguous and are always valid.
Valid empty Date and DateTime formats include {}, {--}, and {--,:}.
With
strict date formats, a greater range of Date and DateTime values are
available. In Visual FoxPro 5.0, the smallest date value that can be
expressed is {^0100/1/1}, January 1st, 100 A.D. This is because year
values less than 100 were always rounded up to the nearest century
based on the setting of SET CENTURY.
The
smallest valid date in Visual FoxPro 6.0 is {^0001-01-01}, January
1st, 1 A.D. The largest valid date in Visual FoxPro 6.0 is
{^9999-12-31}, December 31st, 9999 A.D.
Note
that the strict date format ignores the TAIWAN setting for SET DATE,
so the year of a strict format Date or DateTime is always in the
Western calendar. (Note that this is not true in Visual FoxPro 5.0.)
SET STRICTDATE
A new
command in Visual FoxPro 6.0, SET STRICTDATE, can be used to enforce
unambiguous date constants and date strings in your code.
SET STRICTDATE TO 0
Setting
STRICTDATE to 0 means that strict date format checking is off. This
setting is Visual FoxPro 5.0 compatible. 0 is the default setting
for the Visual FoxPro run time and ODBC driver. When STRICTDATE is
set to 0, invalid Date and DateTimes evaluate to the empty date.
SET STRICTDATE TO 1
Setting
STRICTDATE to 1 requires that all Date and DateTime constants be in
the strict date format. Any Date or DateTime constant that is not in
the strict format or evaluates to an invalid value generates an
error, either during compilation, at run time, or during an
interactive Visual FoxPro session. 1 is the default setting for an
interactive Visual FoxPro session.
SET STRICTDATE TO 2
Identical to setting STRICTDATE to 1, but also generates a
compilation error (2033 û CTOD and CTOT can produce incorrect
results) whenever CTOD( ) and CTOT( ) functions appear in code.
Because
the values returned by CTOD( ) and CTOT( ) rely on SET DATE and SET
CENTURY to interpret the date string they contain, they can produce
unintended results. Use DATE( ) and DATETIME( ) with the optional
numeric arguments to create Date and DateTime constants and
expressions.
This
setting is most useful during debugging sessions to trap code that
may produce unintended results for dates after 1999.
Strict Date Format Errors
The
following new errors have been added to Visual FoxPro 6.0, and can
be generated when SET STRICTDATE is set to 1 or 2.
Error 2032: Ambiguous Date/DateTime constant.
This
error occurs when a Date or DateTime did not adhere to the strict
format. The following conditions will produce this error:
- The caret (^) is missing.
- The date separators are not the required hyphen, forward
slash, period, or space separators.
- The year field contains less than four characters
({^98-02-16}).
- The month or day field is empty ({^1998-02}).
Error 2033: CTOD and CTOT can produce incorrect
results.
This
error occurs for the same reasons as error 2032, but CTOD( ) and
CTOT( ) may produce unintended results. Use the DATE( ) or DATETIME(
) functions instead.
Error 2034: Date/DateTime evaluated to an invalid
value.
A Date
or DateTime is not in the valid Date or DateTime format, or is
outside the valid Date or DateTime range.
When SET
STRICTDATE is set to 0, invalid Date and DateTime constants evaluate
to the empty Date or DateTime. When SET STRICTDATE is set to 1 or 2,
invalid date constants, such as {^2000-02-31}, February 31st, or
{^2000-01-01,25:00}, 25 o'clock, generate this error.
Examples
of invalid Dates and DateTimes include:
- {^2000-02-31}, February 31st, 2000.
- {^2000-01-01,25:00} 25 o'clock.
- {^2000-01-01, 14a}, 14 A.M.
Error 2035: Date/DateTime contains illegal
characters.
The Date
or DateTime constant contains characters that are not supported in
Date and DateTime constants.
When SET
STRICTDATE is set to 0, the Date or DateTime constant containing the
illegal characters evaluates to the empty Date or DateTime. When SET
STRICTDATE is set to 1 or 2, the Date or DateTime constant
containing the illegal characters generates this error.
Note
that the StrictDateEntry property isn't affected by the setting of
SET STRICTDATE. The StrictDateEntry property remains unchanged in
Visual FoxPro 6.0.
Visual FoxPro ODBC Driver
The
Visual FoxPro ODBC Driver has been updated for each new release of
Visual FoxPro and incorporates product changes which affect the
FoxPro data engine. The ODBC driver is unique in that it can work
with all versions of FoxPro data including the ability to smartly
recompile stored procedures that may have been compiled in an older
version of Visual FoxPro. Therefore, it is highly recommended that
you always use the latest available Visual FoxPro ODBC driver.
Visual
FoxPro 6.0 ships with the same ODBC driver that is included in the
Microsoft Data Access Components 2.0 (MDAC). You can check
periodically for updates to the driver in newer releases of MDAC
which is available from the Microsoft Universal Data Access web site
http://www.microsoft.com/data.
⌐ 1999
Microsoft Corporation. All rights reserved.
ALL
COMMUNICATIONS OR CONVEYANCES OF INFORMATION TO YOU CONCERNING
MICROSOFT AND THE YEAR 2000, INCLUDING BUT NOT LIMITED TO THIS
DOCUMENT OR ANY OTHER PAST, PRESENT OR FUTURE INFORMATION REGARDING
YEAR 2000 TESTING, ASSESSMENTS, READINESS, TIME TABLES, OBJECTIVES,
OR OTHER (COLLECTIVELY THE "MICROSOFT YEAR 2000 STATEMENT"), ARE
PROVIDED AS A "YEAR 2000 READINESS DISCLOSURE" (AS
DEFINED BY THE YEAR 2000 INFORMATION AND READINESS DISCLOSURE ACT)
AND CAN BE FOUND AT MICROSOFTÆS YEAR 2000 WEBSITE LOCATED AT
http://www.microsoft.com/year2000/ (the "Y2K WEBSITE"). EACH
MICROSOFT YEAR 2000 STATEMENT IS PROVIDED PURSUANT TO THE TERMS
HEREOF, THE TERMS OF THE Y2K WEBSITE, AND THE YEAR 2000 INFORMATION
AND READINESS DISCLOSURE ACT FOR THE SOLE PURPOSE OF ASSISTING THE
PLANNING FOR THE TRANSITION TO THE YEAR 2000. EACH MICROSOFT YEAR
2000 STATEMENT CONTAINS INFORMATION CURRENTLY AVAILABLE AND IS
UPDATED REGULARLY AND SUBJECT TO CHANGE. MICROSOFT THEREFORE
RECOMMENDS THAT YOU CHECK THE Y2K WEBSITE REGULARLY FOR ANY CHANGES
TO ANY MICROSOFT YEAR 2000 STATEMENT. EACH MICROSOFT
YEAR 2000 STATEMENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
KIND. CONSEQUENTLY, MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER
EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE. MOREOVER, MICROSOFT DOES NOT
WARRANT OR MAKE ANY REPRESENTATIONS REGARDING THE USE OR THE RESULTS
OF THE USE OF ANY MICROSOFT YEAR 2000 STATEMENT IN TERMS OF ITS
CORRECTNESS, ACCURACY, RELIABILITY, OR OTHERWISE. NO ORAL OR WRITTEN
INFORMATION OR ADVICE GIVEN BY MICROSOFT OR ITS AUTHORIZED
REPRESENTATIVES SHALL CREATE A WARRANTY OR IN ANY WAY DECREASE THE
SCOPE OF THIS WARRANTY DISCLAIMER. IN NO EVENT SHALL
MICROSOFT OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER
REGARDING ANY MICROSOFT YEAR 2000 STATEMENT INCLUDING DIRECT,
INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS,
PUNITIVE OR SPECIAL DAMAGES, EVEN IF MICROSOFT OR ITS SUPPLIERS HAVE
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO
NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL
OR INCIDENTAL DAMAGES, SO THE FOREGOING LIMITATION MAY NOT APPLY TO
YOU. THE INFORMATION CONTAINED IN EACH MICROSOFT YEAR 2000 STATEMENT
IS FOUND AT THE Y2K WEBSITE AND IS INTENDED TO BE READ IN
CONJUNCTION WITH OTHER INFORMATION LOCATED AT THE Y2K WEBSITE,
INCLUDING BUT NOT LIMITED TO MICROSOFTÆS YEAR 2000 COMPLIANCE
STATEMENT, THE DESCRIPTION OF THE CATEGORIES OF COMPLIANCE INTO
WHICH MICROSOFT HAS CLASSIFIED ITS PRODUCTS IN ITS YEAR 2000 PRODUCT
GUIDE, AND THE MICROSOFT YEAR 2000 TEST CRITERIA.
ANY
MICROSOFT YEAR 2000 STATEMENTS MADE TO YOU IN THE COURSE OF
PROVIDING YEAR 2000 RELATED UPDATES, YEAR 2000 DIAGNOSTIC TOOLS, OR
REMEDIATION SERVICES (IF ANY) ARE SUBJECT TO THE YEAR 2000
INFORMATION AND READINESS DISCLOSURE ACT (112 STAT. 2386). IN CASE
OF A DISPUTE, THIS ACT MAY REDUCE YOUR LEGAL RIGHTS REGARDING THE
USE OF ANY SUCH STATEMENTS, UNLESS OTHERWISE SPECIFIED BY YOUR
CONTRACT OR TARIFF.
|