Solved

Converting date string to tdatetime (varied date format entry)

Posted on 2004-04-10
12
675 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 150 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: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

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

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…
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…
This video shows how to use Hyena, from SystemTools Software, to update 100 user accounts from an external text file. View in 1080p for best video quality.

739 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