?
Solved

Converting date string to tdatetime (varied date format entry)

Posted on 2004-04-10
12
Medium Priority
?
677 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Industry Leaders: 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

New benefit for Premium Members - Upgrade now!

Ready to get started with anonymous questions today? It's easy! Learn more.

Question has a verified solution.

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

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
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…
If you’ve ever visited a web page and noticed a cool font that you really liked the look of, but couldn’t figure out which font it was so that you could use it for your own work, then this video is for you! In this Micro Tutorial, you'll learn yo…
In this video, Percona Solution Engineer Rick Golba discuss how (and why) you implement high availability in a database environment. To discuss how Percona Consulting can help with your design and architecture needs for your database and infrastr…
Suggested Courses
Course of the Month10 days, 23 hours left to enroll

770 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