Logo

Hacker’s Guide to Visual FoxPro
An irreverent look at how Visual FoxPro really works. Tells you the inside scoop on every command, function, property, event and method of Visual FoxPro.

SET STRICTDATE, Set(“StrictDate”)

While this SET command was new in VFP 6.0, the concept of strict dates was introduced in VFP 5.0. This command makes it easier to transition legacy code and also allows you to ensure Year 2000 compliance.

Usage

SET STRICTDATE TO [ 0 | 1 | 2 ]
nStrictLevel = SET("STRICTDATE")

Parameter

Value

Meaning

nStrictLevel

0 or omitted (at runtime)

Off. No strict date checking is done. To avoid problems with running legacy code, this is the default setting for ODBC and runtime modules. Code compiled in this mode will not generate an error, regardless of the runtime setting.

1 or omitted (at design-time)

On. Verifies that all date and datetime constants are non-ambiguous. Otherwise, this setting generates an error in development or runtime modes. Code must be recompiled in 6.0 in order for the error detection to work, even at runtime.

2

CTO-hostile. This setting incorporates all of the behaviors of level 1, but also squawks when it runs into a CTOD() or CTOT() function, warning that they "can produce incorrect results."

Strict date formatting was introduced in Visual FoxPro 5.0, with the StrictDateEntry property available for text boxes. However, it’s with the introduction of the SET command in VFP 6.0 that this feature really comes into its own.

A strict date is a constant or date expression that can be interpreted only one way. The format for strict dates is:

{^YYYY-MM-DD [ , ] [ HH [ :MM [ :SS ] ] [ A | P ] ] } 

where the separators can be any combination of dashes, forward slashes or dots. The year must be four digits in order to be unambiguous. The time portion looks really messy when expressed in the standard syntax, but all it means is that you express only as much time precision as you need—hours, minutes or seconds—and add the optional “a” or “p” on the end (AM is assumed). Hmmm … doesn’t this mean the time is still ambiguous? We think so, but let’s not tell Microsoft—they tried so hard!

One thing tripped us up while trying all the variations of the optional sections of this expression. If you want to specify time after the date, you must include either a colon after the hours, or the comma separating the date from the time.

At first, we thought SET STRICTDATE was a compile-time setting only, then we started seeing runtime effects, then we just got totally confused. Let’s see if we can clarify what might be the single most important Y2K feature in the language.

First, let’s talk about the compile-time effects. These are pretty clearly documented—0 is the equivalent of “Shut up,” 1 generates errors when compiling code and running that compiled code, and 2 does all that 1 does, but also objects to the CTOT() and CTOD() functions. All pretty straightforward. Our general feeling is that we will develop with STRICTDATE set to 2 all the time, a setting even more conservative than the default development setting of 1. After all, if we can build features into our products that will make it easier for us to produce both internationally consistent and Year-2000-safe code, why not take advantage of what is there?

Setting STRICTDATE to its various settings also changes the size of the resulting object code. Code with CTOD() is larger when compiled with STRICTDATE equal to 2—it appears that the entire line of suspicious code is preserved for the runtime environment to evaluate, and to generate errors if STRICTDATE is still not met.

If the compile-time environment is set to 0, the code will never generate an error at runtime, regardless of the runtime setting of STRICTDATE. With compile-time STRICTDATE of 1 or 2, the runtime setting of 1 or 2 generates errors, but 0 is silent if errors are present. So what does this mean? The compiler has the brains, not the runtime. The compiler flags code as suspicious, and if the runtime isn’t set up to be silent, it alarms when that code is hit.

What came next really caught us by surprise. We tested a routine that tells us how many days until DevCon and updated it to show the days until the then-just-announced 1999 conference. Compiling the program led to an error message, because dates were in the American and not strict format, and running the program also gave warnings until the code was rewritten. But here’s the kicker: the code had been running for months in Visual FoxPro 6.0 without a peep! It had to be recompiled in 6.0 before it would generate an error. So, 5.0 code with ambiguous dates will not error under later versions until recompiled in the later version.

In runtime, we’ll SET STRICTDATE as strictly as we can—in most cases, at 2, but perhaps at 0 in situations where we are still bringing the code into Y2K compliance. StrictDate is set by default at 0 in runtime environments, for the maximum backward compatibility; code in previous versions should compile and run with no change in behavior. But you’ll want to boost StrictDate up to 2 as soon as you’ve ironed out the issues in your code.

Strict dates solve the problem of source code changing its behavior unexpectedly when recompiled, only because the developer changed the settings for date interpretation. For example, changing SET CENTURY from 19 ROLLOVER 50 to 19 ROLLOVER 60, or changing SET DATE from MDY to DMY, changes the interpretation of the constant {10/12/55} embedded within the code the developer recompiles. This is almost always not intended, and can lead to code breaking under “normal” circumstances. The primary purpose of SET STRICTDATE is to sound alarms at compile time to alert the developer to a potential problem.

The highest setting, SET STRICTDATE TO 2, essentially eliminates the use of the CTOT() and CTOD() functions. Because these functions evaluate a string parameter at runtime and interpret their value as dates based on the current SET DATE settings, it is possible for these functions to return a value unanticipated by the developer. Instead, we agree with the Microsoft recommendation to use the revised DATE() and DATETIME() functions to create unambiguous dates.

Example

SET STRICTDATE TO 2
? CTOT("01/01/1950")  && Error 2033, "CTOD and CTOT can produce
                      && incorrect results..."
SET STRICTDATE TO 1
? {^1998-05-17 14}   && Errors if lacking colon or comma
? {^1958-05-17 14:}  && Works correctly
? {^1958-05-17, 14}  && Also works

See Also

CToT(), CToD(), Date(), DateTime(), Set, StrictDateEntry