Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Edit Mask On Time question

0 views
Skip to first unread message

Don

unread,
Apr 23, 2001, 3:04:10 PM4/23/01
to
Hi Folks

I'm having a hell of a time with an edit mask in a DBEdit. When I
click into the DBEdit the display is all strange.

The data field is TTimeField

For example:
In the Object Inspector for the database field I set EditMask to
!90:00>LL;1;_ and the DisplayFormat to hh:nnampm

when I click into the empty DBEdit and enter '0245pm' and exit the
DBEdit everything looks fine '02:45PM' But when I click back into the
DBEdit if shows as '_2:0_PM'

I tried setting the EditMask to the Long Time sample
!90:00:00>LL;1;_
But when I click back into the DBEdit if shows as '_2:45:0_PM'

I tried setting the EditMask to the Short Time sample
!90:00;1;_
But when I click back into the DBEdit if shows as '_2:AM'

I tried removing the _ at the end I tried removing the ! at the front,
I tried using a 0 instead of a 9. I tried setting the display format
to null when entering the DbEdit. I've basically tried every
combination I can thing of... I've been at this for about 2 hours and
I have to say... I'm stumped.

I'm trying to get an entry that matched the Display Format hh:nnampm
I must be missing something simple here. Any suggestions?

Cheers
Don

Bjørge Sæther

unread,
Apr 23, 2001, 4:10:08 PM4/23/01
to
"Don" <spamprote...@donwalsh.com> skrev i melding
news:f1u8etcpsl8q4i098...@4ax.com...

> Hi Folks
>
> I'm having a hell of a time with an edit mask in a DBEdit. When I
> click into the DBEdit the display is all strange.
>
> The data field is TTimeField
>
> For example:
> In the Object Inspector for the database field I set EditMask to
> !90:00>LL;1;_ and the DisplayFormat to hh:nnampm
>
> when I click into the empty DBEdit and enter '0245pm' and exit the
> DBEdit everything looks fine '02:45PM' But when I click back into the
> DBEdit if shows as '_2:0_PM'

A tip: Use the OnGetText/OnSetText events to do formatting on a regular
string input. This is a conversion function hat I just love, although it's
not perfectly written:

function StraightenTime(S: string): string;
var
NumDigits : byte;
i : integer;
begin
if Length(S) = 0 then exit;
NumDigits := 0;
result := '';
for i := 1 to Length(S) do
begin
case S[i] of
'0'..'9':
begin
inc(NumDigits);
result := result + S[i];
end;
'.', ':', '-':
begin
if NumDigits = 1 then
insert('0', result, Length(result));
NumDigits := 0;
end;
';': exit;
end;
end;
if NumDigits = 1 then
insert('0', result, Length(result));
if (Length(result) = 3) or (Length(result) = 5) then
result := '0' + result;
end;


function StrToTimeEx(S: string; DefaultTime: TDateTime): TDateTime; //
Utvidede tidskonverteringer
var
L : integer;

procedure DoRaise;
begin
if DefaultTime <> -1 then
result := DefaultTime
else
raise EConvertError.Create(Exception(ExceptObject).Message);
end;

begin
if Trim(S) = '*' then // Well...Now, actually
result:=SysUtils.Time
else begin
// First, make one out of 4 possible formats:
// "hh", "hhmm", "hhmmss" or "hhmmss+1/100's"
S := StraightenTime(S);
L := length(S);
case L of
0,
1,
3,
5: DoRaise;
2: result := EncodeTime(StrToInt(S), 0, 0, 0);
4: result := EncodeTime(StrToInt(Copy(S, 1, 2)), StrToInt(Copy(S, 3,
2)), 0, 0);
6: result := EncodeTime(StrToInt(Copy(S, 1, 2)), StrToInt(Copy(S, 3,
2)), StrToInt(Copy(S, 5, 2)), 0);
8: result := EncodeTime(StrToInt(Copy(S, 1, 2)), StrToInt(Copy(S, 3,
2)), StrToInt(Copy(S, 5, 2)), StrToInt(Copy(S, 7, 2)));
end;
end;
end;
...it's treating time input about as intellegently as you may do, like:

Current time = '*', 105 = 01:05, 12=12:00, etc...

The same may be done with dates, but here my routine is so ugly I won't post
it, and you didn't ask, either;_)

Try it, and you'll never want a masked input field again !
--
Bjoerge Saether
Consultant / Developer
http://www.itte.no
Asker, Norway
bjorgere...@itte.no (remove the obvious)

Don

unread,
Apr 23, 2001, 4:44:02 PM4/23/01
to
Thanks loads for the reply Bjørge

I've been at it almost 10 hours today so I have to take a break but
first thing tomorrow morning I'll me at the code you sent me.

Looking forward to having a look at it.

Thanks again I really appreciate it.

Cheers
Don

Don

unread,
Apr 24, 2001, 10:17:03 AM4/24/01
to

Hey M.V

Please excuse my ignorance here. I've put those functions you sent in
my Data Module and in there I created OnGetText and OnSetText events
for the StartTime field. Then in them I put the following:

procedure TDataModule1.SessionalTableStartTimeGetText(Sender: TField;
var Text: String; DisplayText: Boolean);
begin
Text := StraightenTime(SessionalTableStartTime.Text);
end;

procedure TDataModule1.SessionalTableStartTimeSetText(Sender: TField;
const Text: String);
begin
SessionalTableStartTime.Value := StrToTimeEx(Text,Now);
end;

I obviously have these set wrong because it just loops on the GetText
line... Text := StraightenTime(SessionalTableStartTime.Text);

The weird thing is that I have a break point set on the first line of
the StraightenTime function but it doesn't get there.

Could you post the correct method of using your functions for me. I'd

M.H. Avegaart

unread,
Apr 24, 2001, 10:32:35 AM4/24/01
to
Don't use Field.Text in the OnGetText event ! Instead, use:

procedure TDataModule1.SessionalTableStartTimeGetText(Sender: TField; var
Text: String; DisplayText: Boolean);
begin

Text := StraightenTime(Sender.AsString);
end;

procedure TDataModule1.SessionalTableStartTimeSetText(Sender: TField; const
Text: String);
begin

Sender.AsDateTime := StrToTimeEx(Text, Now);
end;


"Don" <spamprote...@donwalsh.com> schreef in bericht
news:sq1betsfi30j75b24...@4ax.com...

Bjørge Sæther

unread,
Apr 24, 2001, 2:29:14 PM4/24/01
to
"M.H. Avegaart" <avegaar...@mccomm.nl> skrev i melding
news:9c42s2$2ou$1...@porthos.nl.uu.net...

> Don't use Field.Text in the OnGetText event ! Instead, use:
>
> procedure TDataModule1.SessionalTableStartTimeGetText(Sender: TField; var
> Text: String; DisplayText: Boolean);
> begin
> Text := StraightenTime(Sender.AsString);
> end;
>
> procedure TDataModule1.SessionalTableStartTimeSetText(Sender: TField; const
> Text: String);
> begin
> Sender.AsDateTime := StrToTimeEx(Text, Now);
> end;

Sorry, I didn't take the time to explain the practical implementation...

Well, actually, the StraightenTime is only a helper function.

It should be done like:

procedure TDataModule1.SessionalTableStartTimeGetText(Sender: TField; var
Text: String; DisplayText: Boolean);
begin

// = not necessary, this is what happens before anyway...
// Only necessary with custom formatting using e.g. FormatDateTime()
Text := Sender.AsString;
end;

procedure TDataModule1.SessionalTableStartTimeSetText(Sender: TField; const
Text: String);
begin
Sender.AsDateTime := StrToTimeEx(Text, Now);
end;

...hope this helps !

--
Bjoerge Saether
Consultant / Developer
http://www.itte.no
Asker, Norway
bjorgere...@itte.no (remove the obvious)

>
>

Don

unread,
Apr 24, 2001, 2:36:09 PM4/24/01
to
Thanks loads M.H.

I rewrote the StraightenTime code to suite my needs. I thought I pass
it along to you for curiosity sake.

For me I wanted the user to be able to type in the time in a number of
different ways. but always have it displayed as hh:mm ampm

For example
2 or 2A becomes 02:00 AM
2P becomes 2:00 PM
230A or 230AM gives
0230p becomes 2:20 PM
14 becomes 2:00 PM

I think I've covered every possibility.
02:00AM, 02Am, 2Am, 2A, 2 will all give you 2:00am
02:00PM, 02Pm, 2Pm, 2P, 14 will all give you 2:00pm

You get the picture.

I add one more Boolean variable in the function... DisplayTheTime.
So when I call the function from inside StrToTimeEx function I set it
to false:
S := StraightenTime(S,False);

but when I call it from the GetText procedure I set it to true:
Text := StraightenTime(Sender.AsString,True);


Thanks for putting me on the road to recovery here.

Cheers
Don

function StraightenTime(S: string; DisplayTheTime : Boolean): string;
var
i : integer;
PM : Boolean;


begin
if Length(S) = 0 then exit;

if Pos(':',S) = 2 then S := '0'+S; // in case time is < 10
while Pos(':',S) > 0 do Delete(S,Pos(':',S),1); // Strip colons away
if UpCase(S[Length(S)]) = 'M' then Delete(S,Length(S),1); // if
there and M it's not needed
PM := UpCase(S[Length(S)]) = 'P';
if UpCase(S[Length(S)]) in ['A','P'] then
Delete(S,Length(S),1) // Get rid of the A or P
else
// No pm or am so check for a time > 12
if Length(S) = 2 then
if StrToInt(S) > 12 then
PM := True;
// Now just keep the first 4 digits (Not Worried about Sec or MSec)
if Length(S) > 4 then
S := Copy(S,1,4);
Case Length(S) of
1 : S := '0'+S+'00'; // Eg: Entering 2 becomes 0200
2 : S := S + '00'; // Eg: Entering 02 becomes 0200
3 : S := '0'+S; // Eg: Entering 230 becomes 0230
end;
// determine the proper value for am pm
i := StrToInt(Copy(S,1,2));
if PM and (i < 12) then
i := i + 12;
if Not PM then
if (i > 12) then
begin
ShowMessage(Copy(S,1,2)+':'+Copy(S,3,2)+'AM Invalid. Resetting
to PM');
PM := True;
end
else
if (i = 12) then i := 0;

Delete(S,1,2);
Insert(IntToStr(i),S,1);
if Length(S) = 3 then S := '0' + S;

// for the display called from Get Text
if DisplayTheTime then
begin
i := StrToInt(Copy(S,1,2));
Delete(S,1,2);
Case i of
0 : begin
Insert('12:',S,1);
S := S + ' AM';
end;
1..9 : begin
Insert('0'+IntToStr(i)+':',S,1);
S := S + ' AM';
end;
10..11 : begin
Insert(IntToStr(i)+':',S,1);
S := S + ' AM';
end;
12 : begin
Insert(IntToStr(i)+':',S,1);
S := S + ' PM';
end;
13..24 : begin
Insert(IntToStr(i-12)+':',S,1);
S := S + ' PM';
end;
end;
end;
Result := S;
end;

Bruce Roberts

unread,
Apr 24, 2001, 3:23:36 PM4/24/01
to

"Don" <spamprote...@donwalsh.com> wrote in message
news:c0gbetsdui71bd8s2...@4ax.com...

> Thanks loads M.H.
>
> I rewrote the StraightenTime code to suite my needs. I thought I pass
> it along to you for curiosity sake.
>
> For me I wanted the user to be able to type in the time in a number of
> different ways. but always have it displayed as hh:mm ampm
>
> For example
> 2 or 2A becomes 02:00 AM
> 2P becomes 2:00 PM
> 230A or 230AM gives
> 0230p becomes 2:20 PM

A typo?

> 14 becomes 2:00 PM
>
> I think I've covered every possibility.
> 02:00AM, 02Am, 2Am, 2A, 2 will all give you 2:00am
> 02:00PM, 02Pm, 2Pm, 2P, 14 will all give you 2:00pm

I haven't really been following this thread so this might not be appropriate
:), but one thing I do is allow the entry of M and N for midnight and noon
respectively.

Don

unread,
Apr 24, 2001, 4:58:08 PM4/24/01
to
>> 230A or 230AM gives
>> 0230p becomes 2:20 PM
>
>A typo?
Yes. Should be '0230p becomes 2:30 PM'


>I haven't really been following this thread so this might not be appropriate
>:), but one thing I do is allow the entry of M and N for midnight and noon
>respectively.
>

Good choice... I'll add it for sure.

Sorry Bjoerge I think I got my wires crossed as to who was posting
what. Thanks a lot fellows... you got me on the straight road again.

Cheers
Don

Bjørge Sæther

unread,
Apr 25, 2001, 5:12:48 AM4/25/01
to
"Don" <spamprote...@donwalsh.com> skrev i melding
news:a1qbet82rik0r5c3a...@4ax.com...

Hi, would you please send me a copy of your final routine ? I've been
concidering rewriting the whole thing, but I've no experience with the am/pm
needs (in fact, I don't even know for sure what it means and what's
before/after noon...)
I've done something similar with dates as well, like:
12 -> 12. of current month
dd -> Today
m -> monday this week
m- or -m -> monday last week
m-- -> monday twoo weeks ago
124 -> april 12. (ddmmyy zone), because it couldn't be 1. of the 24. month
w24m -> monday, week 24

...but this code is really *not* beautiful, although working...

--
Bjoerge Saether
Consultant / Developer

Bruce Roberts

unread,
Apr 25, 2001, 11:34:32 AM4/25/01
to

"Bjørge Sæther" <REMOVE_bsaether@THIS_online.no> wrote in message
news:xvyF6.130

>
> ...but this code is really *not* beautiful, although working...
>

In my book if its working it beautiful :).

Don

unread,
Apr 25, 2001, 11:51:03 AM4/25/01
to

I've send it via email. Let me type it up neatly first :-)

Cheers
Don

Don

unread,
Apr 25, 2001, 1:08:13 PM4/25/01
to
On Wed, 25 Apr 2001 11:12:48 +0200, "Bjørge Sæther" >
>Hi, would you please send me a copy of your final routine ? I've been
>concidering rewriting the whole thing, but I've no experience with the am/pm
>needs (in fact, I don't even know for sure what it means and what's
>before/after noon...)

I'm posting this as well as sending it to you by email. Who knows
someone else might like to have it.


Hi Bjoerge

I've tried to write step by step comments for you here. I hope it's
not overkill but I really appreciate the help I get on this news group
from people like yourself and when I'm given the opportunity to give
something back I want to make sure everything is A-Ok and clear.
Thanks for the questions you've answered for me in the past.

Now to the business at hand.

First as per your request AM means anything from 12 Midnight to 12
Noon and PM is anything from 12 Noon to 12 Midnight.

I changed you StraightenTime Function to suit my needs but only one
line of StrToTimeEx was changed, that line was
S := StraightenTime(S,False);
I needed the Boolean variable to determine weather or not to set the
display.

As you explained to me the StraightenTime Function gets called from
the GetText Event. My Table variable is called SessionalTableStartTime
so SessionalTableStartTime.OnGetText is set to
SessionalTableStartTimeGetText, and SessionalTableStartTime.OnSetText
is set to SessionalTableStartTimeSetText in the DataModule.
These procedures in turn call the StraightenTime and StrToTimeEx.
Of course you know all this... because you explained it to me in the
first place :-)

So... with the code below the user can enter a time any way they like.
For example:

Lets say we want 2:00 AM
The user can enter 2, 200, 2A, 2AM, 2:00, 2:00A, 2:00AM, 02:00,
02:00AM even 2:AM will give 2:00 AM

Lets say we want 2:00 PM then we can use any of the above with a P
added instead of the A.
2P, 200P, 2PM, 200PM etc.

Midnight and Noon are special cases.
To Get 12:00 midnight enter 12, 12A, 12AM, 12:00A or 12:00AM
To Get 12:00 Noon enter 12P, 12PM, 12:00P or 12:00PM

Of course all AM's and PM's can me upper or lower case and if no A,
AM, P or PM are entered then the program assumes AM

1) First thing the StraightenTime function does is make sure it's a
00:00 formatted time because the program will send back 2:00 AM and
the function deals with 4 digit times. Then it strips away all Colons.
2) Next it checks for an 'M' at the end of the string and deletes it
if it's there. It's not needed.
3) Next Find out if it AM or PM and set a Boolean variable PM
accordingly.
- If it finds no A or P at this point it assumes AM.
4) Next delete the A or P if it's there. We now just want to deal with
the digits.
5) If no AM or PM was entered then check to see if the time entered is
greater then 12. Of course only do this if there are only 2 digits
left in the input string. For example if the string with all the AMs
and PMs removed is 145 then the time is 1:45 not 14 hundred hours. If
it is only 2 digits and > 12 then change the PM Boolean Variable to
True.
6) I wasn't concerned about seconds or milliseconds so I next I make
sure there's only 4 or less digits left in the string.
Then convert the Time Input String to a 24 Hour Clock, this just makes
it easier to deal with.
7) The case statement next resets the Input String back to a 4 digit
time.
8) At this point it's been determined if the time entered is PM or AM.
If it's PM and the Time is < 12 then we have to add 12 to it.
9) If it's not PM and the Time entered is > 12 ( if someone enters
15:00AM) then we give a warning and convert it back to PM
10) Because it's been dealing with an integer value, 'i', to determine
the proper value for am pm we have to replace the first two digits of
the Time Input String to match the String value of i.

At this point the function exits if it was called from the StrToTimeEx
because now Delphi has to deal with the Input String.

11) However if it's called from the GetText event then we want to
display it neatly for the user. Again dealing with am or pm. Convert
the first two digits of the Time Input String to 'i'. Then use the
case statement to deal with the 24 hour clock system and convert it to
a viewable time for the user.

That's about it. If you need anything else drop me a line.

Cheers
Don

Here are the functions:

function StraightenTime(S: string; DisplayTheTime : Boolean): string;
var
i : integer;
PM : Boolean;
begin
if Length(S) = 0 then exit;

// (STEP 1)


if Pos(':',S) = 2 then S := '0'+S; // in case time is < 10
while Pos(':',S) > 0 do Delete(S,Pos(':',S),1);

// (STEP 2)


if UpCase(S[Length(S)]) = 'M' then Delete(S,Length(S),1);

// (STEP 3)


PM := UpCase(S[Length(S)]) = 'P';

// (STEP 4)


if UpCase(S[Length(S)]) in ['A','P'] then
Delete(S,Length(S),1) // Get rid of the A or P
else

// (STEP 5)


if Length(S) = 2 then
if StrToInt(S) > 12 then
PM := True;

// (STEP 6)


if Length(S) > 4 then
S := Copy(S,1,4);

// (STEP 7)


Case Length(S) of
1 : S := '0'+S+'00'; // Eg: Entering 2 becomes 0200
2 : S := S + '00'; // Eg: Entering 02 becomes 0200
3 : S := '0'+S; // Eg: Entering 230 becomes 0230
end;

// (STEP 8)


i := StrToInt(Copy(S,1,2));
if PM and (i < 12) then
i := i + 12;

// (STEP 9)


if Not PM then
if (i > 12) then
begin
ShowMessage(Copy(S,1,2)+':'+Copy(S,3,2)+'AM Invalid. Resetting
to PM');
PM := True;
end
else
if (i = 12) then i := 0;

// (STEP 10)


Delete(S,1,2);
Insert(IntToStr(i),S,1);
if Length(S) = 3 then S := '0' + S;

// (STEP 11)

function StrToTimeEx(S: string; DefaultTime: TDateTime): TDateTime;
var
L : integer;

procedure DoRaise;
begin
if DefaultTime <> -1 then
result := DefaultTime
else
raise EConvertError.Create(Exception(ExceptObject).Message);
end;

begin
if Trim(S) = '*' then

result:=SysUtils.Time
else
begin
// First, make one out of 4 possible formats:
// "hh", "hhmm", "hhmmss" or "hhmmss+1/100's"

S := StraightenTime(S,False);


L := length(S);
case L of
0,
1,
3,
5: DoRaise;
2: result := EncodeTime(StrToInt(S), 0, 0, 0);
4: result := EncodeTime(StrToInt(Copy(S, 1, 2)),

StrToInt(Copy(S, 3,2)), 0, 0);


6: result := EncodeTime(StrToInt(Copy(S, 1, 2)),

StrToInt(Copy(S, 3,2)), StrToInt(Copy(S, 5, 2)), 0);


8: result := EncodeTime(StrToInt(Copy(S, 1, 2)),

StrToInt(Copy(S, 3,2)), StrToInt(Copy(S, 5, 2)), StrToInt(Copy(S, 7,
2)));
end;
end;
end;

procedure TDataModule1.SessionalTableStartTimeGetText(Sender: TField;


var Text: String; DisplayText: Boolean);
begin

Text := StraightenTime(Sender.AsString,True);

0 new messages