DELPHI AND THE YEAR 2000 PROBLEM |
|
conundrum
尊榮會員 ![]() ![]() ![]() ![]() ![]() ![]() 發表:893 回覆:1272 積分:643 註冊:2004-01-06 發送簡訊給我 |
The Unofficial Newsletter of Delphi Users - by Robert Vivrette http://www.undu.com/Articles/990111a.html DELPHI AND THE YEAR 2000 PROBLEM by Clay Shannon - ClaySCS@aol.com Y2K. The Year 2000 problem. The Millenium Bug. The mother of all software projects. However you feel about the potential problems associated with the year 2000 and the impact it will have on your work and life, you will surely admit that it is important for your software projects to be "Year 2000 compliant". Computer programs are viewed by the "ungeeky masses" as generating cold, hard, rigid results. It seems a conundrum to them that there could be ambiguity connected with a date stored in a computer file or database table. But, as we all know, ambiguity can be the result if the date was entered using two digits rather than four, in which case an assumption has to be made about the century intended by the person entering the data. This is not just a COBOL/mainframe problem. Our beloved Delphi also accepts a two-digit entry for the year portion of a date and will by default encode the date as belonging in the century in which the user entered made the entry. For example, if sometime in 1998 you enter the date "10/10/99" in a DBEdit connected to a date field, the date will be interpreted and stored as October 10th, 1999. However, if you enter "10/10/99" in the year 2000, it will be interpreted and stored as October 10th, 2099. WAYS TO ENFORCE ENTRY OF FOUR DIGITS FOR YEARS How to prevent the application from making assumptions which may or may not be what is intended? The optimal solution is to force the user to always enter four digits for the year. This could be coded into the OnValidate event of the TField descendent (TDateField or TDateTimeField), like this: procedure TForm1.Table1DobValidate(Sender: TField);
begin
if Length(dobEdit.Text) < 10 then
begin
MessageDlg('Please enter a date in the format
mm/dd/yyyy',mtInformation,[mbOK],0);
dobEdit.SetFocus;
end;
end;
In order to do have access to a TField's OnValidate event via the Object Inspector's events page, you must first instantiate the date field(s) in your dataset. To do so, use the Fields Editor by right-clicking on the TDataset (TTable, TQuery, TStoredProc in all versions of Delphi; TClientDataSet in Client/Server versions 3 and 4; TNestedTable in Delphi 4) component and selecting Fields Editor, or by double-clicking the TDataset. See "Fields Editor" and "Persistent Field Components" in Delphi help for more information.
If for some reason you do not want to instantiate the field(s) at design time, you can adapt the above code and attach it to the TDBEdit's OnExit event: procedure TForm1.dobEditExit(Sender: TObject);
begin
if Length(dobEdit.Text) < 10 then
begin
MessageDlg('Please enter a date in the format
mm/dd/yyyy',mtInformation,[mbOK],0);
dobEdit.SetFocus;
end;
end;
Another option that can be employed to programmatically require the entry of four digits to represent the year portion of a date is to use a TMaskEdit component with the EditMask property's value set to !99/99/0000;1; and then assign the value to the database field desired. For example:
Table1DOB.AsDateTime := StrToDate(MaskEdit1.Text);
Similarly, you can use the TDateTimePicker component, which, when clicked, drops down a calendar from which you can select a date. You can then assign its value to a database field like this:
Table1DOB.AsDateTime := DateTimePicker1.Date;
Note: If you are using Delphi 4, there is a new standalone calendar component, TMonthCalendar, which can be used in a manner similar to TDateTimePicker.
DEALING WITH TWO-DIGIT YEAR ENTRIES If you do not want to force the user to enter four digits in each date field, you can set a pivot number that determines the century to be assumed by the program. Numbers above your pivot number are assumed to be in the 21st Century, numbers below your pivot number are assumed to be in the 1900s. For example, you may determine that users will only intend to enter values between 1950 and 2049. In this case, you can make 50 the pivot year. You then attach code to each dataset's BeforePost event, which passes all date fields to a function that returns a date corresponding to the rules you have built in via your choice of pivot year. The example below showing how this could be done uses a TTable's BeforePost event, but will work also for other TDataset descendents (TQuery, TClientDataSet, TStoredProc, TNestedTable). . . .
const
CenturyPivot = 1950;
var
Form1: TForm1; implementation {$R *.DFM} function TForm1.CenturyWindow(const Value: TDateTime): TDateTime;
var
Year, Month, Day : Word;
begin
Result := Value;
DecodeDate(Result, Year, Month, Day);
if Year < CenturyPivot then
Result:= EncodeDate(Year+100, Month, Day);
end; procedure TForm1.Table1BeforePost(DataSet: TDataSet);
var
DateValue: TDateTime;
DateTypes: set of TFieldType;
i: Integer;
begin
DateTypes := [ftDate, ftDateTime];
for i:=0 to DataSet.FieldCount-1 do
if (DataSet.FieldDefs[i].DataType in DateTypes) then
begin
DateValue := DataSet.Fields[i].AsDateTime;
DateValue := CenturyWindow(DateValue);
DataSet.Fields[i].AsDateTime := DateValue;
end;
end;
A MORE DYNAMIC SOLUTION
Delphi 4 provides an elegant solution to potential Year 2000 problems. Explicit entry of four-digit years is left unchanged. When two-digit years are entered, instead of relying on a constant pivot year, it determines the century to assume based on the current year less a number of years that you designate. The difference between this and the approach shown above is that if you assign a pivot year of 1950 using the aforementioned method, the pivot year will always remain 1950 until you (or someone after you) changes the value of that constant. It does not take much imagination to see that this may not always produce the desired results. Delphi 4 provides this functionality via the new TwoDigitYearCenturyWindow system variable (declared in the SysUtils unit). The default value of this variable is 0, in which state Delphi will continue to expand ambiguous (two-digit) year entries according to the current century. In other words, if you enter "10/10/00" in 1998, it will be stored as October 10th, 1900; entering the same value on or after January 1, 2000 will store the date as October 10th, 2000). By setting this variable to a non-zero integer, the actual pivot year changes as the current year changes, but remains the same relative to the current year. The value you assign the TwoDigitYearCenturyWindow variable is subtracted from the current year to determine the pivot year. For example, if you set TwoDigitYearCenturyWindow to 50, the pivot year will be 1948 in 1998, 1950 in 2000, and 1982 in 2032. For example, if you set the TwoDigitYearCenturyWindow variable to 50 and enter a two-digit year value of 50 in 1998, it will be stored as 1950; entering the same value in 2000 will still store the year as 1950; however, in 2032, the year will be stored as 2050. When an entry is made into a data control (such as TDBEdit) whose DataField property refers to a date field, the entry is implicitly converted from a string to a date value (Delphi uses the StrToDate and StrToDateTime conversion functions internally to accomplish this). Delphi 4 then checks for entry of four digits for the year portion of the date. If only two digits were entered, the value of the TwoDigitYearCenturyWindow variable is checked, and the appropriate century assigned based on the value you have assigned this variable (Again, it is 0 by default, in which state the current century is assumed). Of course, if you do not want to upgrade to Delphi 4 (and there are many reasons why you should want to), you can always code your own function to provide the same support to your users. This is an exercise left to the readers (
|
stillalive
初階會員 ![]() ![]() 發表:7 回覆:148 積分:41 註冊:2004-04-07 發送簡訊給我 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |