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

Adding time to the a tdatetime

1,751 views
Skip to first unread message

D-Fan

unread,
Aug 4, 2008, 3:27:05 AM8/4/08
to
What is the best way to add minutes, hours, and or days to a tdatetime
variable?

Descartes AT -REMOVE-THIS- DOT

unread,
Aug 4, 2008, 3:41:12 AM8/4/08
to

"D-Fan" wrote:
> What is the best way to add minutes, hours, and or days to a
> tdatetime variable?

D-Fan,

Check out

IncMilliSecond
IncSecond
IncMinute
IncHour
IncDay
IncWeek
IncYear

in unit DateUtils

Regards
Descartes


John Herbster

unread,
Aug 4, 2008, 7:01:08 AM8/4/08
to
> "D-Fan" wrote:
>> What is the best way to add minutes, hours,
>> and or days to a TDateTime variable?

"Descartes" wrote

> Check out
> IncMilliSecond
> IncSecond
> IncMinute
> IncHour
> IncDay
> IncWeek
> IncYear
> in unit DateUtils

D-Fan and Descartes,

Of course many of the routines are sub-optimal or broken
(at least in D7). Many of the Inc* functions accumulate
errors. For example
procedure TForm1.Button3Click(Sender: TObject);
var DT: TDateTime; i: integer;
begin
DT := 40000;
For i := 1 to 24 do DT := IncHour(DT,1);
If DT = 40001
then ShowMessage('EQ')
else ShowMessage(FloatToStr(DT-40001));
end;
will increment DT to a little *less* than a day.

A better way is to convert and round the DT to milliseconds,
add the increment and convert back to DT.

You can find code for converting to DT to milliseconds
and back in this QualityCentral report:
Report No: 56957 Status: Open
A Fix for DateUtils Date-Time Compare Functions
http://qc.codegear.com/wc/qcmain.aspx?d=56957
QCWIN:Defect_No=56957
(Look in the comments or attachments.)

Rgds, JohnH

D-Fan

unread,
Aug 4, 2008, 10:46:16 AM8/4/08
to
Thanks for your response.

Descartes AT -REMOVE-THIS- DOT

unread,
Aug 4, 2008, 12:40:40 PM8/4/08
to
John,

I have a great respect for your thoughts about TDateTime and
calculations in general with floats.
Reading your writings, I've learned at least to be cautios and to take
into consideration the limits and the inexactness of floats.

However, I would like to put the OPs question in perspective to avoid
that he or anybody else gets scared and goes into unnecessary
complicated measures in trying to achieve their goal.

> Of course many of the routines are sub-optimal or broken
> (at least in D7).

"Of course"? ;-)

> Many of the Inc* functions accumulate errors.

Of course! Adding inexact values repeatedly will do just that (except
in the rare case when the errors cancel out each other).

> will increment DT to a little *less* than a day.

Your example produces an error of -5 nanoseconds

I made a test using IncMinute 365 * 24 * 60 times (1 year).
The error was 103 milliseconds.
But why would somebody want to do that?

> A better way is to convert and round the DT to milliseconds, add the
> increment and convert back to DT.


OP wanted to add minutes, hours and days. Although he did not say so,
one can assume that he deals with ordinary dates and times with a
resolution down to seconds, but not milliseconds.

Looking at the errors produced with the standard inc* routines in this
perspective, I don't think it's worth to bother with conversion
to/from milliseconds.

A more severe problem with TDateTime is that the pitfalls with
negative values (datetimes before 31.12.1899) are not documented at
all!

> You can find code for converting to DT to milliseconds and back in
> this QualityCentral report: Report No: 56957 Status: Open
> A Fix for DateUtils Date-Time Compare Functions
> http://qc.codegear.com/wc/qcmain.aspx?d=56957
> QCWIN:Defect_No=56957
> (Look in the comments or attachments.)

Seems to be a very good report. I'll check it later in depth and vote
for it (maybe ;-))

No offence, best regards
Descartes
1794744326139 milliseconds old a few minutes ago ;-)


John Herbster

unread,
Aug 4, 2008, 2:32:32 PM8/4/08
to
>> Of course many of the routines are sub-optimal or broken
>> (at least in D7).

"Descartes" wrote
> "Of course"? ;-)

Descartes,

Yes, DateUtils.pas has had many problems, most of
which are still not fixed. Check QualityCentral!

>> Many of the Inc* functions *accumulate* errors.

> Of course! Adding inexact values repeatedly will do
> just that (except in the rare case when the errors
> cancel out each other).

>> will increment DT to a little *less* than a day.

> Your example produces an error of -5 nanoseconds

Which is more than enough to throw the final increment
into the wrong day.

What we need, of course, is a way to do exact arithmetic
with days, hour, minutes, and seconds. This would be
easily possible with time variables of that could store
time exactly to the minute, second, thousandth of a
second. But as long as programmers are happy with inexact
time measurement and arithmetic, it will not happen.

My


>> A Fix for DateUtils Date-Time Compare Functions
>> http://qc.codegear.com/wc/qcmain.aspx?d=56957

is a attempt to at least allow time calculations that
will be as exact as possible.

>> A better way is to convert and round the DT to milliseconds,
>> add the increment and convert back to DT.

> OP wanted to add minutes, hours and days. Although he did not
> say so, one can assume that he deals with ordinary dates and
> times with a resolution down to seconds, but not milliseconds.
> Looking at the errors produced with the standard inc* routines
> in this perspective, I don't think it's worth to bother with
> conversion to/from milliseconds.

But if he follows your advice, when he discovers that adding
a minutes 60 times does not give the same result as adding
an hour, he will be back to the well again asking what's wrong.

> A more severe problem with TDateTime is that the pitfalls
> with negative values (datetimes before 31.12.1899) are not
> documented at all!

TDateTime type is documented in D7's Help, though not
very well.

My conversions to and from milliseconds hide all of the
pre-31.12.1899 nastiness by using the nearly perfect
DateTimeToTimeStamp and TimeStampToDateTime routines.

>> You can find code for converting to DT to milliseconds and
>> back in this QualityCentral report:
>> Report No: 56957 Status: Open
>> A Fix for DateUtils Date-Time Compare Functions
>> http://qc.codegear.com/wc/qcmain.aspx?d=56957
>> QCWIN:Defect_No=56957
>> (Look in the comments or attachments.)

> Seems to be a very good report. I'll check it later in depth
> and vote for it (maybe ;-))

Thank you.

Regards, JohnH

PS: D7's DateUtils gives wrong result for the last call to
EncodeDateTime in this test (time part got wrong sign):
procedure TForm1.Button4Click(Sender: TObject);
var s: string; dt: TDateTime;
begin
s := FormatDateTime('yyyy-mm-dd_HH:nn:ss.zzz', 0.00);
Memo1.Lines.Add(s);
s := FormatDateTime('yyyy-mm-dd_HH:nn:ss.zzz', 2.75);
Memo1.Lines.Add(s);
s := FormatDateTime('yyyy-mm-dd_HH:nn:ss.zzz',-1.25);
Memo1.Lines.Add(s);
s := FormatDateTime('yyyy-mm-dd_HH:nn:ss.zzz',35065);
Memo1.Lines.Add(s);
dt := EncodeDateTime(1899,12,29,06,00,00,000);
Memo1.Lines.Add('EncodeDateTime(1899,12,29,06,00,00,000) =');
s := FormatDateTime(' yyyy-mm-dd_HH:nn:ss.zzz',dt);
Memo1.Lines.Add(s); {D7's DateUtils.EncodeDateTime has error.}
end;

Pieter Zijlstra

unread,
Aug 4, 2008, 3:38:53 PM8/4/08
to
John Herbster wrote:

> procedure TForm1.Button4Click(Sender: TObject);
> var s: string; dt: TDateTime;
> begin
> s := FormatDateTime('yyyy-mm-dd_HH:nn:ss.zzz', 0.00);
> Memo1.Lines.Add(s);
> s := FormatDateTime('yyyy-mm-dd_HH:nn:ss.zzz', 2.75);
> Memo1.Lines.Add(s);
> s := FormatDateTime('yyyy-mm-dd_HH:nn:ss.zzz',-1.25);
> Memo1.Lines.Add(s);
> s := FormatDateTime('yyyy-mm-dd_HH:nn:ss.zzz',35065);
> Memo1.Lines.Add(s);
> dt := EncodeDateTime(1899,12,29,06,00,00,000);
> Memo1.Lines.Add('EncodeDateTime(1899,12,29,06,00,00,000) =');
> s := FormatDateTime(' yyyy-mm-dd_HH:nn:ss.zzz',dt);
> Memo1.Lines.Add(s); {D7's DateUtils.EncodeDateTime has error.}
> end;

Can't remember if I already tested this one before, but here we go :)

D7
1899-12-30_00:00:00.000
1900-01-01_18:00:00.000
1899-12-29_06:00:00.000
1996-01-01_00:00:00.000
EncodeDateTime(1899,12,29,06,00,00,000) =
1899-12-30_18:00:00.000

D2006
1899-12-30_00:00:00.000
1900-01-01_18:00:00.000
1899-12-29_06:00:00.000
1996-01-01_00:00:00.000
EncodeDateTime(1899,12,29,06,00,00,000) =
1899-12-29_06:00:00.000

D2007
1899-12-30_00:00:00.000
1900-01-01_18:00:00.000
1899-12-29_06:00:00.000
1996-01-01_00:00:00.000
EncodeDateTime(1899,12,29,06,00,00,000) =
1899-12-29_06:00:00.000

Seems to be fixed in the later versions.

--
Pieter

John Herbster

unread,
Aug 4, 2008, 3:56:42 PM8/4/08
to
Pieter, Thanks, JohnH
0 new messages