?
Solved

Converting date string to tdatetime (varied date format entry)

Posted on 2004-04-10
12
Medium Priority
?
679 Views
Last Modified: 2010-04-05
I would like to find a function that would allow user to enter a date into an edit box in the format of any of these: mm/dd/yy or m/d/y or mm/dd/yyyy or m/d/yy, etc. and return a valid tdatetime, or return false if unable to convert to a tdatetime.  I've tried to figure it out by looking at the date formatting stuff in Delphi 6, but I'm so confused now I thought I'd go to the experts.

I would think this would be an often-used function.

Can you steer me towards the answer?  Thanks.
0
Comment
Question by:rjsand
  • 6
  • 3
  • 3
12 Comments
 
LVL 11

Expert Comment

by:ZhaawZ
ID: 10797916
1. You can use TMaskEdit to let the user enter date in a single format.
2. You can divide the string and use function EncodeDate().
0
 
LVL 11

Expert Comment

by:ZhaawZ
ID: 10797965
procedure TForm1.Edit1Change(Sender: TObject);
var
  dt : TDateTime;
  s : string;
  str : array [0..2] of string;
  int : array [0..2] of word;
  err : array [0..2] of integer;
  ValidDate : boolean;
begin
s := Edit1.Text;
str[0] := copy(s,1,pos('/',s) - 1); delete(s,1,pos('/',s));
str[1] := copy(s,1,pos('/',s) - 1); delete(s,1,pos('/',s));
str[2] := copy(s,1,length(s));
Val(str[0],int[0],err[0]);
Val(str[1],int[1],err[1]);
Val(str[2],int[2],err[2]);
ValidDate := true;
if err[0] or err[1] or err[2] <> 0 then ValidDate := false;
if (int[0] = 0) or (int[0] > 12) then ValidDate := false;
{add checking for day of month}
{add checking for year}
if ValidDate then dt := EncodeDate(int[2],int[0],int[1]) else ShowMessage('invalid date format');
end;
0
 
LVL 12

Accepted Solution

by:
esoftbg earned 600 total points
ID: 10798229
Install this TeoEditDate into your Delphi components palette:

unit eoEditDate;

interface

uses
  Windows, Messages, SysUtils, Classes, Controls, StdCtrls,
  Dialogs, DateUtils;

type
  TDateMask          = (mm_dd_yyyy, mm_dd_yy);
  TeoEditDate          =   class(TEdit)
    private          { Private declarations }
      FDate:           TDate;
      FDateMask:       TDateMask;
      FKeyPress:       TNotifyEvent;
      FSize:           Integer;
    protected        { Protected declarations }
      procedure        Change; override;
      procedure        KeyPress(var Key: Char); override;
      procedure        SetMask(const Value: TDateMask);
    public           { Public declarations }
      constructor      Create(AOwner: TComponent); override;
      destructor       Destroy; override;
    published        { Published declarations }
      property         Date: TDate read FDate write FDate;
      property         DateMask: TDateMask read FDateMask write SetMask default mm_dd_yyyy;
      property         Size: Integer read FSize write FSize default 10;
      property         OnKeyPress: TNotifyEvent read FKeyPress write FKeyPress;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('EOSoft', [TeoEditDate]);
end;

constructor            TeoEditDate.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FDateMask := mm_dd_yyyy;
  case FDateMask of
    mm_dd_yyyy: FSize := 10;
    mm_dd_yy:   FSize := 8;
  end;
end;

destructor             TeoEditDate.Destroy;
begin
  try
    inherited Destroy;
  except
  end;
end;

procedure              TeoEditDate.SetMask(const Value: TDateMask);
begin
  FDateMask := Value;
  case FDateMask of
    mm_dd_yyyy: FSize := 10;
    mm_dd_yy:   FSize := 8;
  end;
end;

function               Text_To_Date(T: string): TDate;
begin
  try
    Result := StrToDate(T);
  except
    Result := 0;
  end;
end;

procedure              TeoEditDate.Change;
begin
  if (FSize>0) then
  begin
    if (Length(Text)>FSize) then
      Text := Copy(Text, 1, FSize);
  end;
  FDate := Text_To_Date(Text);
  inherited;
end;

procedure              TeoEditDate.KeyPress(var Key: Char);
var
  B:                   Boolean;
  I:                   Integer;
  J:                   Integer;
  L:                   Integer;
begin
  if (FSize>0) then
  begin
    if (Length(Text)>FSize-1) and (Key<>#8) then
      Key := #0;
  end
  else
  begin
    B := False;
    inherited;
    if Assigned(FKeyPress) then
      FKeyPress(Self);
    try
      J := 0;
      L := Length(Text);
      if (L>1) then
      begin
        for I := 1 to L do
          if (Text[I]=DateSeparator) then
            Inc(J);
        if (J<2) then
          B := not (Key in ['0'..'9', DateSeparator, #8])
        else
          B := not (Key in ['0'..'9', #8])
      end
      else
        B := not (Key in ['0'..'9', DateSeparator, #8]);
    finally
      if B then Key := #0;
    end
  end;
end;

end.
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 12

Expert Comment

by:esoftbg
ID: 10798348
The function would be:

type
  TDateRec = record
     Ok:          Boolean;
     Date:       TDate;
  end;

function  Text_To_Date(T: string): TDateRec;
begin
  try
    Result.Date := StrToDate(T);
    Result.Ok := True;
  except
    Result.Date := 0;
    Result.Ok := False;
  end;
end;
0
 
LVL 12

Expert Comment

by:esoftbg
ID: 10800018
An improved version:

unit eoEditDate;

interface

uses
  Windows, Messages, SysUtils, Classes, Controls, StdCtrls,
  Dialogs, DateUtils;

type
  TDateMask         = (mm_dd_yyyy, mm_dd_yy, m_d_yy, m_d_y);

  TDateRec = record
    Ok:      Boolean;
    Date:    TDate;
  end;

  TeoEditDate       =  class(TEdit)
    private          { Private declarations }
      FDate:           TDate;
      FDateOk:         Boolean;
      FDateMask:       TDateMask;
      FKeyPress:       TNotifyEvent;
      FSize:           Integer;
    protected        { Protected declarations }
      procedure        Change; override;
      procedure        KeyPress(var Key: Char); override;
      procedure        SetMask(const Value: TDateMask);
    public           { Public declarations }
      constructor      Create(AOwner: TComponent); override;
      function         Text_To_Date(T: string): TDateRec;
      destructor       Destroy; override;
    published        { Published declarations }
      property         Date: TDate read FDate write FDate;
      property         DateOk: Boolean read FDateOk write FDateOk;
      property         DateMask: TDateMask read FDateMask write SetMask default mm_dd_yyyy;
      property         Size: Integer read FSize write FSize default 10;
      property         OnKeyPress: TNotifyEvent read FKeyPress write FKeyPress;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('EOSoft', [TeoEditDate]);
end;

constructor            TeoEditDate.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FDateMask := mm_dd_yyyy;
  FSize := 10;
end;

procedure              TeoEditDate.SetMask(const Value: TDateMask);
begin
  FDateMask := Value;
  case FDateMask of
    mm_dd_yyyy: FSize := 10;
    mm_dd_yy:   FSize := 8;
    m_d_yy:     FSize := 6;
    m_d_y:      FSize := 5;
  end;
end;

function               TeoEditDate.Text_To_Date(T: string): TDateRec;
begin
  try
    Result.Date := StrToDate(T);
    Result.Ok := True;
  except
    Result.Date := 0;
    Result.Ok := False;
  end;
end;

procedure              TeoEditDate.Change;
var
  DateRec:             TDateRec;
begin
  if (FSize>0) then
  begin
    if (Length(Text)>FSize) then
      Text := Copy(Text, 1, FSize);
  end;
  DateRec := Text_To_Date(Text);
  FDateOk := DateRec.Ok;
  FDate := DateRec.Date;
  inherited;
end;

procedure              TeoEditDate.KeyPress(var Key: Char);
var
  B:                   Boolean;
  I:                   Integer;
  J:                   Integer;
  L:                   Integer;
begin
  B := False;
  inherited;
  if Assigned(FKeyPress) then
    FKeyPress(Self);
  try
    J := 0;
    L := Length(Text);
    if (L>1) then
    begin
      for I := 1 to L do
        if (Text[I]=DateSeparator) then
          Inc(J);
      if (J<2) then
        B := not (Key in ['0'..'9', DateSeparator, #8])
      else
        B := not (Key in ['0'..'9', #8])
    end
    else
      B := not (Key in ['0'..'9', DateSeparator, #8]);
  finally
    if B then Key := #0;
  end
end;

destructor             TeoEditDate.Destroy;
begin
  inherited Destroy;
end;

end.
0
 

Author Comment

by:rjsand
ID: 10814757
I loaded the eoEditDate component, but it stops after any keypress with a convert error.  Am I missing something in using the component?

Also, what I need is the ability to accept any string that could be interpreted as a valid date, without knowing ahead of time how the date format will be used.  If the user enters 4/5/03 or 405/2003, then they would both be able to be accepted and converted to a datetime value.

Thank you for your responses, and I sure would appreciate some additional feedback.

0
 

Author Comment

by:rjsand
ID: 10814797
I meant in the previous post "If the user enters 4/5/03 or 4/05/2003"  etc.
0
 
LVL 11

Expert Comment

by:ZhaawZ
ID: 10815073
rjsand, why don't you use my example?
0
 
LVL 12

Expert Comment

by:esoftbg
ID: 10815417
Hi rjsand,
If you set the DateMask property to m_d_y then the component doesn't allow to be entered more than 5 symbols. In this case you must enter 4/5/3 and it will be interpreted as 04/05/2003
If you set the DateMask property to mm_dd_yyyy then the component doesn't allow to be entered more than 10 symbols. In this case you can enter 4/5/3 and 4/5/03 and 04/5/03 and 04/05/03 and 04/05/2003 it will be interpreted as 04/05/2003
Thank you for the feedback. If you want I will improve the component as you need.
0
 
LVL 12

Expert Comment

by:esoftbg
ID: 10815455
It is better to use the last version of the component. I see you are accepted the first version wich has some errors.
0
 

Author Comment

by:rjsand
ID: 10816153
Thanks for your help.  This is the first time I've used this site, and I didn't really understand how the process worked.  Hopefully, my next time will be better for everyone.  I meant to accept the last version.  My mistake.
0
 
LVL 12

Expert Comment

by:esoftbg
ID: 10816361
Here is the last version (I hope it is error free):

unit eoEditDate;

interface

uses
  Windows, Messages, SysUtils, Classes, Controls, StdCtrls,
  Dialogs, DateUtils;

type
  TDateMask         = (mm_dd_yyyy, mm_dd_yy, m_d_yy, m_d_y);

  TDateRec = record
    Ok:      Boolean;
    Date:    TDate;
  end;

  TeoEditDate       =  class(TEdit)
    private          { Private declarations }
      FDate:           TDate;
      FDateOk:         Boolean;
      FDateMask:       TDateMask;
      FKeyPress:       TNotifyEvent;
      FSize:           Integer;
    protected        { Protected declarations }
      procedure        Change; override;
      procedure        KeyPress(var Key: Char); override;
      procedure        SetMask(const Value: TDateMask);
    public           { Public declarations }
      constructor      Create(AOwner: TComponent); override;
      function         Text_To_Date(T: string): TDateRec;
      destructor       Destroy; override;
    published        { Published declarations }
      property         Date: TDate read FDate write FDate;
      property         DateOk: Boolean read FDateOk write FDateOk;
      property         DateMask: TDateMask read FDateMask write SetMask default mm_dd_yyyy;
      property         Size: Integer read FSize write FSize default 10;
      property         OnKeyPress: TNotifyEvent read FKeyPress write FKeyPress;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('EOSoft', [TeoEditDate]);
end;

constructor            TeoEditDate.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FDateMask := mm_dd_yyyy;
  FSize := 10;
end;

procedure              TeoEditDate.SetMask(const Value: TDateMask);
begin
  FDateMask := Value;
  case FDateMask of
    mm_dd_yyyy: FSize := 10;
    mm_dd_yy:   FSize := 8;
    m_d_yy:     FSize := 8;
    m_d_y:      FSize := 8;
  end;
end;

function               TeoEditDate.Text_To_Date(T: string): TDateRec;
begin
  try
    Result.Date := StrToDate(T);
    Result.Ok := True;
  except
    Result.Date := EncodeDate(1,1,1);
    Result.Ok := False;
  end;
end;

procedure              TeoEditDate.Change;
var
  I:                   Integer;
  DateRec:             TDateRec;
begin
  if (FSize>0) then
  begin
    I := SelStart;
    if (Length(Text)>FSize) then
      Text := Copy(Text, 1, FSize);
    SelLength := 0;
    SelStart := I;
  end;
  DateRec := Text_To_Date(Text);
  FDateOk := DateRec.Ok;
  FDate := DateRec.Date;
  inherited;
end;

procedure              TeoEditDate.KeyPress(var Key: Char);
var
  B:                   Boolean;
  I:                   Integer;
  J:                   Integer;
  L:                   Integer;
begin
  B := False;
  inherited;
  if Assigned(FKeyPress) then
    FKeyPress(Self);
  try
    J := 0;
    L := Length(Text);
    if (L>1) then
    begin
      for I := 1 to L do
        if (Text[I]=DateSeparator) then
          Inc(J);
      if (J<2) then
        B := not (Key in ['0'..'9', DateSeparator, #8])
      else
        B := not (Key in ['0'..'9', #8])
    end
    else
      B := not (Key in ['0'..'9', DateSeparator, #8]);
  finally
    if B then Key := #0;
  end
end;

destructor             TeoEditDate.Destroy;
begin
  inherited Destroy;
end;

end.
0

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
This video shows how to quickly and easily deploy an email signature for all users in Office 365 and prevent it from being added to replies and forwards. (the resulting signature is applied on the server level in Exchange Online) The email signat…
With just a little bit of  SQL and VBA, many doors open to cool things like synchronize a list box to display data relevant to other information on a form.  If you have never written code or looked at an SQL statement before, no problem! ...  give i…
Suggested Courses

850 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question