### Bookstore

 Computer Math and Games in Pascal (preview) Lazarus Handbook

### Author Topic: Extracting time values from TDateTime value  (Read 1616 times)

#### winni

• Hero Member
• Posts: 1359
##### Re: Extracting time values from TDateTime value
« Reply #15 on: April 05, 2020, 12:52:48 am »
Okay but is there any function which automatically takes care of the next unit?
Like SecondsBetween will return e.g. 68s, then MinutesBetween returns 1min but for outputting it I'd need 1min and 8seconds

Hi!

DecodeTime works fine as long as you take care that the time delta is less than 24 hours.

You can do it like this:
Code: Pascal  [Select][+][-]
1. var delta : TDateTime;
2.      h,min,sec,junk : word:
3.     overflowHours: word=0;
4.
5. begin
6. ....
7. delta := abs(delta);
8. if delta >=1.0 then overFlowHours := trunc(delta)*24;
9. decodeTime(delta,h,min,sec,junk);
10. h := h+overflowHours;
11. ...........

Winni

#### asdf1337

• New Member
• Posts: 27
##### Re: Extracting time values from TDateTime value
« Reply #16 on: April 05, 2020, 07:56:46 pm »
Okay but is there any function which automatically takes care of the next unit?
Like SecondsBetween will return e.g. 68s, then MinutesBetween returns 1min but for outputting it I'd need 1min and 8seconds
there is the procedure Periodbetween in the dateutils for the date part and following is a fast and dirty procedure that calculates the timeBetween.
Code: Pascal  [Select][+][-]
1. procedure TimeBetween(const aTime:TDateTime; var Hours, Min, Secs:Integer);
2. const
3.   SecsPerHour = MinsPerHour*SecsPerMin;
4. var
5.   TotalSeconds:UInt64;
6. begin
7.   TotalSeconds := Abs(DateTimeDiff(ANow,AThen))+TDateTimeEpsilon)*SecsPerDay;
8.   //TotalSeconds := TotalSeconds - ((TotalSecods div SecsPerDay)*SecsPerDay); //uncomment this to remove the days.
9.   Hours := TotalSeconds div SecsPerHour;
10.   TotalSeconds := TotalSeconds - (Hours * SecsPerHour);
11.   Min := TotalSeconds div SecsPerMin;
12.   Secs := TotalSeconds - (Min * SecsPerMin);
13. end;
14.
Keep in mind that the above code was typed directly in the browser and never compiled so some attention is mandatory.

Edit:sorry, sorry. Not mod but div

Your code doesn't compile, changed it to

Code: Pascal  [Select][+][-]
1. procedure TimeBetween(const ANow,AThen:TDateTime; out Hours, Min, Secs:Word);
2. const
3.   SecsPerHour = MinsPerHour*SecsPerMin;
4. var
5.   TotalSeconds:UInt64;
6. begin
7.   TotalSeconds := Abs((DateTimeDiff(ANow,AThen))+TDateTimeEpsilon)*SecsPerDay;
8.   //TotalSeconds := TotalSeconds - ((TotalSecods div SecsPerDay)*SecsPerDay); //uncomment this to remove the days.
9.   Hours := TotalSeconds div SecsPerHour;
10.   TotalSeconds := TotalSeconds - (Hours * SecsPerHour);
11.   Min := TotalSeconds div SecsPerMin;
12.   Secs := TotalSeconds - (Min * SecsPerMin);
13. end;
but still fails with
Code: [Select]
`Error: Identifier not found "DateTimeDiff"Error: Identifier not found "TDateTimeEpsilon"`

It also seems that Delphi doesn't have PeriodBetween.
I thought this would be a very common problem and that there are many ready-to-use variants available.

#### jamie

• Hero Member
• Posts: 2947
##### Re: Extracting time values from TDateTime value
« Reply #17 on: April 05, 2020, 08:26:55 pm »
The TDatetime is nothing more than a Float/Double..

The integer part(Whole) is the number of days, the fraction is the ratio of the day...

so a .5 fraction is half the day..

(24*60*60)*Frac(SomeTime) = the number of seconds so far...

etc..

something for you to think about I guess.

Btw, you should ask those DEV developers why they don't have such functions
Number 1 at blue screen app creations!

#### winni

• Hero Member
• Posts: 1359
##### Re: Extracting time values from TDateTime value
« Reply #18 on: April 05, 2020, 08:38:01 pm »
Hi!

Why do you make the things such complicated???

Code: Pascal  [Select][+][-]
1. procedure TimeBetween(const aNow, aThen:TDateTime; var Hours, Min, Secs:Integer);
2. var delta : TDateTime;
3.      junk : word;
4.     overflowHours: word=0;
5.
6. begin
7. delta := abs(aNow-aThen);
8. if delta >=1.0 then overFlowHours := trunc(delta)*24;
9. decodeTime(delta,hours,min,secs,junk);
10. hours := hours+overflowHours;
11. end;
12.

Done!

Winni

#### Bart

• Hero Member
• Posts: 3790
##### Re: Extracting time values from TDateTime value
« Reply #19 on: April 05, 2020, 08:48:48 pm »
Why not use DateUtils.PeriodBetween()?

Bart

#### winni

• Hero Member
• Posts: 1359
##### Re: Extracting time values from TDateTime value
« Reply #20 on: April 05, 2020, 08:59:16 pm »
Why do it simple if there is a complicated way?

That is the way we did it simple with Delphi 1 when there were no "Between" functions.

Winni

#### eljo

• Sr. Member
• Posts: 362
##### Re: Extracting time values from TDateTime value
« Reply #21 on: April 06, 2020, 02:33:29 am »
Okay but is there any function which automatically takes care of the next unit?
Like SecondsBetween will return e.g. 68s, then MinutesBetween returns 1min but for outputting it I'd need 1min and 8seconds
there is the procedure Periodbetween in the dateutils for the date part and following is a fast and dirty procedure that calculates the timeBetween.
Code: Pascal  [Select][+][-]
1. procedure TimeBetween(const aTime:TDateTime; var Hours, Min, Secs:Integer);
2. const
3.   SecsPerHour = MinsPerHour*SecsPerMin;
4. var
5.   TotalSeconds:UInt64;
6. begin
7.   TotalSeconds := Abs(DateTimeDiff(ANow,AThen))+TDateTimeEpsilon)*SecsPerDay;
8.   //TotalSeconds := TotalSeconds - ((TotalSecods div SecsPerDay)*SecsPerDay); //uncomment this to remove the days.
9.   Hours := TotalSeconds div SecsPerHour;
10.   TotalSeconds := TotalSeconds - (Hours * SecsPerHour);
11.   Min := TotalSeconds div SecsPerMin;
12.   Secs := TotalSeconds - (Min * SecsPerMin);
13. end;
14.
Keep in mind that the above code was typed directly in the browser and never compiled so some attention is mandatory.

Edit:sorry, sorry. Not mod but div

Your code doesn't compile, changed it to

Code: Pascal  [Select][+][-]
1. procedure TimeBetween(const ANow,AThen:TDateTime; out Hours, Min, Secs:Word);
2. const
3.   SecsPerHour = MinsPerHour*SecsPerMin;
4. var
5.   TotalSeconds:UInt64;
6. begin
7.   TotalSeconds := Abs((DateTimeDiff(ANow,AThen))+TDateTimeEpsilon)*SecsPerDay;
8.   //TotalSeconds := TotalSeconds - ((TotalSecods div SecsPerDay)*SecsPerDay); //uncomment this to remove the days.
9.   Hours := TotalSeconds div SecsPerHour;
10.   TotalSeconds := TotalSeconds - (Hours * SecsPerHour);
11.   Min := TotalSeconds div SecsPerMin;
12.   Secs := TotalSeconds - (Min * SecsPerMin);
13. end;
but still fails with
Code: [Select]
`Error: Identifier not found "DateTimeDiff"Error: Identifier not found "TDateTimeEpsilon"`

It also seems that Delphi doesn't have PeriodBetween.
I thought this would be a very common problem and that there are many ready-to-use variants available.
sorry about that I based my code on the hoursBetween code from the dateutils unit and I did not check what is public and what not. You can find the DAteTimeDiff and the TDateTimeEpsilon in the implementation section of the dateutils unit.

Just copy anything you need in to your own unit to be used in both delphi and FPC some testing might be needed in delphi to make sure that produces the same results.

#### Bart

• Hero Member
• Posts: 3790
##### Re: Extracting time values from TDateTime value
« Reply #22 on: April 06, 2020, 12:53:37 pm »
Why do it simple if there is a complicated way?

That is the way we did it simple with Delphi 1 when there were no "Between" functions.

Doing calculations with dates a difficult, and is a cause of many WTF's.
General advice is to use built-in (as in: provided with the libraries that come with your development language) functions, do not try to re-invent the wheel.

Bart

#### winni

• Hero Member
• Posts: 1359
##### Re: Extracting time values from TDateTime value
« Reply #23 on: April 06, 2020, 01:03:55 pm »
Hi!

Date and time calculations are not difficult with a clear mind.

My solution (see above) invented the wheel in Delphi 1 times.

The "Between" functions came later.

Winni

#### Bart

• Hero Member
• Posts: 3790
##### Re: Extracting time values from TDateTime value
« Reply #24 on: April 06, 2020, 03:11:32 pm »
Try do simple calculations around the year 0 (not TDateTime(0))...
Of course if that situation will never aplly in your application, then you dont; have to worry about that.

Bart

#### winni

• Hero Member
• Posts: 1359
##### Re: Extracting time values from TDateTime value
« Reply #25 on: April 06, 2020, 03:37:44 pm »
Hi!

Dont tell me about this. TDateTime is useful for daily work and perhaps for buisiness, but not for scientific work.

There are a lot of events, which must be respected:

* The year Zero never existed.
* The 10 missing days in October 1582 due to the change from the Julian to the Gregorian Calender. In Protestant and Orthodox coutries later: In Sweden 1800 and in Russia 1917.

For those reasons there exists the scientific Calendar, starting around -8xxx BC.

Winni

#### asdf1337

• New Member
• Posts: 27
##### Re: Extracting time values from TDateTime value
« Reply #26 on: April 06, 2020, 10:28:35 pm »
Why do it simple if there is a complicated way?

That is the way we did it simple with Delphi 1 when there were no "Between" functions.

Doing calculations with dates a difficult, and is a cause of many WTF's.
General advice is to use built-in (as in: provided with the libraries that come with your development language) functions, do not try to re-invent the wheel.

Bart

That's why I also wanted to use a prebuilt function because I don't want to mess around with it.
I've a function which works like most of the times but rarely the day/month value is fucked up which means it just 'forgets' about it. Sometimes it comes back after a few days and sometimes not. I don't think it's the function because it also uses more or less the function recommended here, maybe TDateTime is a bad choice after all.

#### winni

• Hero Member
• Posts: 1359
##### Re: Extracting time values from TDateTime value
« Reply #27 on: April 06, 2020, 10:48:39 pm »
Hi!

I show you how TDateTime works

OffsetDay = 31.12.1899

DateValue of 0 means the OffsetDay

1 = OffsetDay + 1 day
2 = OffsetDay + 2 days
3 = OffsetDay + 3 days

And now the fractional part, the time:

A half day = 12 hours = 0.5
One hour = 1/24 = 0.0416666666667
One Minute = 1/24/60 = 0.000694444444445

That is the whole "magic" of TDateTime
And it works well for your needs.

I showed you the time difference.
I showed you how to get around the bug with 1900 at decodeDateTime

Now you got everything you need and it should make no errors.

Winni

#### wp

• Hero Member
• Posts: 7090
##### Re: Extracting time values from TDateTime value
« Reply #28 on: April 07, 2020, 12:23:04 am »
In fact, the "OffsetDay" is one day earlier, Dec 30, 1899. I never understood why it was selected like that.

Code: Pascal  [Select][+][-]
1. program Project1;
2.
3. uses
4. SysUtils;
5.
6. begin
7.   WriteLn(FormatDateTime('mmm"/"dd yyyy', 0));   // Dec 30 1899
8.   WriteLn(FormatDateTime('mmm"/"dd yyyy', 1));   // Dec 31, 1899
9.   WriteLn(FormatDateTime('mmm"/"dd yyyy', 2));   // Jan 01, 1900
10.
12. end.
« Last Edit: April 07, 2020, 12:24:46 am by wp »
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

#### winni

• Hero Member
• Posts: 1359
##### Re: Extracting time values from TDateTime value
« Reply #29 on: April 07, 2020, 12:45:41 am »
In fact, the "OffsetDay" is one day earlier, Dec 30, 1899. I never understood why it was selected like that.

Oops - remembered wrong date. Thanx!

Perhaps the Dec 30, 1899 was the Birthday of the grandpa of Anders Hejlsberg?
You'll never know.

Winni