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
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.


Send This To a Friend


 

Tuesday, May 11, 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.