### Bookstore

 Computer Math and Games in Pascal (preview) Lazarus Handbook

### Author Topic: DateUtils.Inc* with double instead on Int64  (Read 1873 times)

#### tt

• Jr. Member
• Posts: 69
##### DateUtils.Inc* with double instead on Int64
« on: May 25, 2022, 01:44:40 pm »
Hi,
I was using the DateUtils.IncSeconds(time, seconds) function, but my seconds parameter ended up being a floating point value.
I remembered that these function want a Int64 number, so I had to use milliseconds with a little rounding.

Would it be senseful to extend them to floating point inputs instead of interger?
All in all the inner calculation does

Code: Pascal  [Select][+][-]
1. Function IncSecond(const AValue: TDateTime; const ANumberOfSeconds: Int64): TDateTime;
2. begin
3.   if AValue>=0 then
4.     Result:=AValue+ANumberOfSeconds/SecsPerDay
5.   else
6.     Result:=IncNegativeTime(Avalue,ANumberOfSeconds/SecsPerDay);
7.   MaybeSkipTimeWarp(AValue,Result);
8. end;
9.

and this would work also with ANumberOfSeconds being a floating point.

Of course the same argument applies to all other DateUtils.Inc* functions.
« Last Edit: May 25, 2022, 01:53:01 pm by tt »

#### AlexTP

• Hero Member
• Posts: 1800
##### Re: DateUtils.Inc* with double instead on Int64
« Reply #1 on: May 25, 2022, 01:52:15 pm »
This must be Delphi compatible,
but if overload will appear, maybe its OK.

#### tt

• Jr. Member
• Posts: 69
##### Re: DateUtils.Inc* with double instead on Int64
« Reply #2 on: May 25, 2022, 02:00:35 pm »
I correct myself:

Quote
The same argument might apply to DateUtils.IncDay, DateUtils.IncHour, DateUtils.IncSecond, DateUtils.IncMilliSecond functions.

Others make less sense to be floating point.

#### winni

• Hero Member
• Posts: 3091
##### Re: DateUtils.Inc* with double instead on Int64
« Reply #3 on: May 25, 2022, 05:49:22 pm »
Hi!

If you know the basics of TDateTime thren you don't need IncSeconds and friends.

Code: Pascal  [Select][+][-]
1. Type
2. TDateTime = Double;
3.

The Integer part contains the days since 30. December 1899

The fractional part contains the time and is organized this way:

1 hour = 1.0 / 24
1 minute = 1.0 / (24*60)
1 second = 1.0/ (24*60*60)

To increment your DateTime with one second you can do
Code: Pascal  [Select][+][-]
1. MyDateTime := MyDateTime + 1/ (24*60*60);

To increment your DateTime with 45 days you can do:

Code: Pascal  [Select][+][-]
1. MyDateTime := MyDateTime +  45;
2.

Winni
« Last Edit: May 25, 2022, 05:53:39 pm by winni »

#### Remy Lebeau

• Hero Member
• Posts: 1109
##### Re: DateUtils.Inc* with double instead on Int64
« Reply #4 on: May 25, 2022, 06:08:35 pm »
All in all the inner calculation does

Code: Pascal  [Select][+][-]
1. Function IncSecond(const AValue: TDateTime; const ANumberOfSeconds: Int64): TDateTime;
2. begin
3.   if AValue>=0 then
4.     Result:=AValue+ANumberOfSeconds/SecsPerDay
5.   else
6.     Result:=IncNegativeTime(Avalue,ANumberOfSeconds/SecsPerDay);
7.   MaybeSkipTimeWarp(AValue,Result);
8. end;
9.

Delphi stopped relying on floating-point math in the DateUtils unit over a decade ago, it was causing too many problems (rounding issues, etc).  Now, most of the date/time calculations are performed by first converting TDateTime to TTimeStamp, manipulating the TTimeStamp as needed using integer math, and then converting the result back to TDateTime.  Much more accurate, albeit maybe slightly less efficient.
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

#### wp

• Hero Member
• Posts: 9718
##### Re: DateUtils.Inc* with double instead on Int64
« Reply #5 on: May 25, 2022, 06:17:51 pm »
If you know the basics of TDateTime thren you don't need IncSeconds and friends.[...]
Your summary is correct. However, this simple calculation results in an "inverted" time when the date is negative. This case is covered correctly by the IncXXX functions:
Code: Pascal  [Select][+][-]
1. program Project1;
2.
3. uses
4.   SysUtils, DateUtils;
5.
6. var
7.   t, t0: TDateTime;
8. begin
9.   t0 := EncodeTime(9, 0, 0, 0);   // 9:00 (AM). But note that the date part is 0
10.   WriteLn(FormatDateTime('hh:nn', t0));
11.
12.   // 1 day earlier
13.   // We're expecting the time to be 9:00 again. But the simple subtraction makes it 15:00 (3:00 PM)
14.   // This is because the date part is negative now.
15.   t := t0-1.0;
16.   WriteLn(FormatDateTime('hh:nn', t));
17.
18.   // Now the same calculation but using the IncDay function -> the result is correct.
19.   t := IncDay(t0, -1);
20.   WriteLn(FormatDateTime('hh:nn', t));
21.
23. end.
Mainly Lazarus trunk / fpc 3.2.0 / all 32-bit on Win-10, but many more...

#### winni

• Hero Member
• Posts: 3091
##### Re: DateUtils.Inc* with double instead on Int64
« Reply #6 on: May 25, 2022, 06:49:40 pm »
Hi!

But that is not a special problem of TDateTime:

You  allways run in trouble with negative time and/or date.

The greatest disadvantage of TDateTime is the offset date  30. December 1899.
This means you can use TDateTime for office use but it is impossible to do some historical  research before 1900 with TDateTime.

They should have taken an offset date 1.1.0001  or - even better -  use the scientific Julian Days starting at 1.1. -4712  (4713 BC).

Winni

#### tt

• Jr. Member
• Posts: 69
##### Re: DateUtils.Inc* with double instead on Int64
« Reply #7 on: May 27, 2022, 09:09:19 am »
Hi!

If you know the basics of TDateTime thren you don't need IncSeconds and friends.

Code: Pascal  [Select][+][-]
1. Type
2. TDateTime = Double;
3.

The Integer part contains the days since 30. December 1899

The fractional part contains the time and is organized this way:

1 hour = 1.0 / 24
1 minute = 1.0 / (24*60)
1 second = 1.0/ (24*60*60)

To increment your DateTime with one second you can do
Code: Pascal  [Select][+][-]
1. MyDateTime := MyDateTime + 1/ (24*60*60);

To increment your DateTime with 45 days you can do:

Code: Pascal  [Select][+][-]
1. MyDateTime := MyDateTime +  45;
2.

Winni

You are right with the direct calculations, I also did so several times.

But lately I migrated to IncXXX because I perceived them comfortable, reader friendly, and able to manage transparently the oddities of the TDateTime calculations.

I was just wondering if was senseful to extend them allowing fractional quantities increment/decrement, like add 2.58 seconds or 7.652 hours.

#### SymbolicFrank

• Hero Member
• Posts: 965
##### Re: DateUtils.Inc* with double instead on Int64
« Reply #8 on: June 07, 2022, 11:58:07 am »
There's about 2^62 seconds in the lifespan of the universe. Fits a single Int64. So set 0000-01-01T00:00 to be 0. Universal time.

The main frustration: leap seconds. Although time zones will be as usual.

#### MarkMLl

• Hero Member
• Posts: 4381
##### Re: DateUtils.Inc* with double instead on Int64
« Reply #9 on: June 07, 2022, 02:01:15 pm »
Pardon me for jumping in, but can anybody comment on why TDateTime isn't an (80-bit) extended on platforms that support it?

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

#### PascalDragon

• Hero Member
• Posts: 4113
• Compiler Developer
##### Re: DateUtils.Inc* with double instead on Int64
« Reply #10 on: June 07, 2022, 02:10:08 pm »
Pardon me for jumping in, but can anybody comment on why TDateTime isn't an (80-bit) extended on platforms that support it?

Because Delphi did so. And the accuracy of Double is probably sufficient for the intended purpose.

#### winni

• Hero Member
• Posts: 3091
##### Re: DateUtils.Inc* with double instead on Int64
« Reply #11 on: June 07, 2022, 02:40:45 pm »
Hi!

TDateTime is a Double since Delphi 1.0

Winni

#### MarkMLl

• Hero Member
• Posts: 4381
##### Re: DateUtils.Inc* with double instead on Int64
« Reply #12 on: June 07, 2022, 02:43:44 pm »
Because Delphi did so. And the accuracy of Double is probably sufficient for the intended purpose.

Hmm. But we're both  further from the epoch (1900?) than when Borland selected it (late 90s?) and expecting to be able to use smaller intervals for timeouts etc. as computers speed up (assuming, of course, that that trend continues).

Since a TDateTime should be treated as opaque, is binary compatibility that important?

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

#### SymbolicFrank

• Hero Member
• Posts: 965
##### Re: DateUtils.Inc* with double instead on Int64
« Reply #13 on: June 07, 2022, 03:15:49 pm »
Exact time is a bit more challenging, as you need 144 bits to store the amount of Planck time units for each second. So, if we take 192 bits for that and add the 64 bits for the seconds, we end up with 256 bits and a universe-shattering precision that is never going to be outdated

Edit: if you count seconds in Planck time, the value won't be exact, but extremely close. And as you convert from a large integer of Planck time to days and seconds, it doesn't matter.
« Last Edit: June 07, 2022, 03:25:34 pm by SymbolicFrank »

#### winni

• Hero Member
• Posts: 3091
##### Re: DateUtils.Inc* with double instead on Int64
« Reply #14 on: June 07, 2022, 03:17:41 pm »
Since a TDateTime should be treated as opaque, is binary compatibility that important?

MarkMLl

Hi!

There is so much code around since more than 25 years that relies on the internal structure of TDateTime.
If you change this you break a lot of existing code.

TDateTime is sufficient for Office Apps.
If you got other needs then use another Type of DateTime.

If you make historical  research the use the Julian Days.

If you need milliseconds then use QWords like getTickCount64.

Winni