Bookstore

Recent

Author Topic: Get random time from range of times?  (Read 954 times)

ShungFeng

  • New Member
  • *
  • Posts: 20
Get random time from range of times?
« on: February 25, 2020, 03:16:30 pm »
If I have two times (21:30 and 22:30) I want to generate a random time between these two times (e.g. 21:54:24 - note how seconds are included).

I think I might be able to do this by first converting the two given time values to floats and then using this function:

Code: Pascal  [Select]
  1. function RandomFloatRange(const A: float; const B: float): float;
  2. {$IFDEF INLINE}
  3. inline;
  4. {$ENDIF}
  5. var
  6.   c, r: float;
  7. begin
  8.   c := (A + B) * 0.5;
  9.   r := Abs(B - A);
  10.   Result := c + r * (Random - 0.5);
  11. end;  

But I don't know how I can convert a time value to and from a float.

Does anybody know? :D

RayoGlauco

  • Jr. Member
  • **
  • Posts: 99
  • Beers: 1567
Re: Get random time from range of times?
« Reply #1 on: February 25, 2020, 03:31:35 pm »
TDateTime is defined as Double, where the integer part is the date and the fractional part is the time.
Then:   Today +1 = tomorrow   ||   Now + 0.5 = 12 hours later
You can use:

Code: Pascal  [Select]
  1. TDateTime(MyDoubleVariable)  // use a Double as a TDateTime
  2. Double(MyDateTimeVariable)   // use a TDateTime as a Double
  3.  

You also can use the EncodeDate or EncodeTime or EncodeDateTime functions to encode a date or a time or both.
You can use the DecodeDate, DecodeTime and DecodeDateTime functions too.
« Last Edit: February 25, 2020, 03:51:29 pm by RayoGlauco »
To err is human, but to really mess things up, you need a computer.

ShungFeng

  • New Member
  • *
  • Posts: 20
Re: Get random time from range of times?
« Reply #2 on: February 25, 2020, 04:10:51 pm »
Thanks for your answer, but I still don't quite understand how I could use these functions to convert a time value into a float value and back to a time value.

rvk

  • Hero Member
  • *****
  • Posts: 3943
Re: Get random time from range of times?
« Reply #3 on: February 25, 2020, 04:19:35 pm »
Juse use SecondsBetween your two TDateTime and do a Random on the seconds.
After that do IncSecond on the first TDateTime  :D

https://www.freepascal.org/docs-html/current/rtl/dateutils/secondsbetween.html
https://www.freepascal.org/docs-html/current/rtl/dateutils/incsecond.html
« Last Edit: February 25, 2020, 04:25:36 pm by rvk »

RayoGlauco

  • Jr. Member
  • **
  • Posts: 99
  • Beers: 1567
Re: Get random time from range of times?
« Reply #4 on: February 25, 2020, 04:28:51 pm »
This is a complete example:

Code: Pascal  [Select]
  1. program Project1;
  2.  
  3. uses
  4.   SysUtils;
  5.  
  6. var
  7.   time1, time2, randomtime: tDateTime;
  8.   hh, nn, ss, ms: word;
  9.  
  10.   function GetRamdomTimeBetween(const t1: tDateTime; const t2: tDateTime): tDateTime;
  11.   var
  12.     dif: double;
  13.   begin
  14.     dif := t2 - t1;
  15.     Result := t1 + dif * Random;
  16.   end;
  17.  
  18. begin
  19.   randomize;
  20.   time1 := EncodeTime(21, 30, 0, 0);
  21.   time2 := EncodeTime(22, 30, 0, 0);
  22.   randomtime := GetRamdomTimeBetween(time1, time2);
  23.   DecodeTime(randomtime, hh, nn, ss, ms);
  24.   writeln('The random time is:   ',hh:2,':',nn:2);
  25.   readln;
  26. end.
             
To err is human, but to really mess things up, you need a computer.

rvk

  • Hero Member
  • *****
  • Posts: 3943
Re: Get random time from range of times?
« Reply #5 on: February 25, 2020, 04:33:03 pm »
And the shorter version with SecondsBetween and IncSecond  :D

Code: Pascal  [Select]
  1. program Project1;
  2. uses
  3.   SysUtils,
  4.   DateUtils;
  5. var
  6.   time1, time2: TDateTime;
  7.   randomsecs: integer;
  8. begin
  9.   randomize;
  10.   time1 := EncodeTime(21, 30, 0, 0);
  11.   time2 := EncodeTime(22, 30, 0, 0);
  12.   randomsecs := Random(SecondsBetween(time1, time2));
  13.   time1 := IncSecond(time1, randomsecs);
  14.   writeln('The random time is:   ', TimeToStr(time1));
  15.   readln;
  16. end.

ShungFeng

  • New Member
  • *
  • Posts: 20
Re: Get random time from range of times?
« Reply #6 on: February 25, 2020, 05:56:40 pm »
Thanks very much guys!

But how can I use EncodeTime with a variable though, instead of a fixed time like in example?

I tried splitting the time into hh, nn and ss:

Code: Pascal  [Select]
  1.     h1 := FormatDateTime('hh', StrToTime(Time1));
  2.     n1 := FormatDateTime('nn', StrToTime(Time1));
  3.     s1 := FormatDateTime('ss', StrToTime(Time1));
  4.     h2 := FormatDateTime('hh', StrToTime(Time2));
  5.     n2 := FormatDateTime('nn', StrToTime(Time2));
  6.     s2 := FormatDateTime('ss', StrToTime(Time2));
  7.     Time1:= EncodeTime(h1, n1, s1, 0);
  8.     Time2 := EncodeTime(h2, n2, s2, 0);

But this does not work and I get the error got AnsiString expected Word.

Thanks very much

rvk

  • Hero Member
  • *****
  • Posts: 3943
Re: Get random time from range of times?
« Reply #7 on: February 25, 2020, 05:59:09 pm »
But how can I use EncodeTime with a variable though, instead of a fixed time like in example?
In what format do you have both times?

If it's in TDatetime or TTime then you can use these directly.

lucamar

  • Hero Member
  • *****
  • Posts: 2579
Re: Get random time from range of times?
« Reply #8 on: February 25, 2020, 06:31:25 pm »
[...] I get the error got AnsiString expected Word.

Of course; look at the signature of EncodeTime() and DecodeTime(). To use them you need something like:

Code: Pascal  [Select]
  1. { Futile but illustrative example }
  2.  
  3. var
  4.   H1, M1, S1, Ms1: Word;
  5.   H2, M2, S2, Ms2: Word;
  6.  
  7.   Time1,
  8.   Time2,
  9.   Retime: TDateTime;
  10.  
  11. begin
  12.   Time1 := Time;
  13.   Time2 := Time + 0.10; {just to make it different}
  14.  
  15.   DecodeTime(Time1, H1, M1, S1, Ms1)
  16.   DecodeTime(Time2, H2, M2, S2, Ms2);
  17.  
  18.   Time1 := EncodeTime(H1, M1, S1, Ms1);
  19.   Time2 := EncodeTime(H2, M2, S2, Ms2);
  20.  
  21. end.

If all you have are string representations of the time components you'll ned to convert them with, for example, StrToInt().

HTH
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.6/FPC 3.0.4 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

RayoGlauco

  • Jr. Member
  • **
  • Posts: 99
  • Beers: 1567
Re: Get random time from range of times?
« Reply #9 on: February 25, 2020, 07:28:09 pm »
ShungFeng, if you have two time values stored as tDateTime, you do not need to convert anyting. Just use GetRamdomTimeBetween(time1,time2) directly, or make your calculations right away.

You are trying to decode your tDateTime variable just to encode it as a tDateTime again!
« Last Edit: February 25, 2020, 07:30:07 pm by RayoGlauco »
To err is human, but to really mess things up, you need a computer.

ShungFeng

  • New Member
  • *
  • Posts: 20
Re: Get random time from range of times?
« Reply #10 on: February 27, 2020, 03:02:53 am »
Thank you work now - but what does not work if second time is after 00:00 and first time is before 00:00. (e.g 23:00, 01:00 might return weird time like 07:34)? I can figure out why it does this. Thank you for help!.

rvk

  • Hero Member
  • *****
  • Posts: 3943
Re: Get random time from range of times?
« Reply #11 on: February 27, 2020, 11:36:20 am »
Thank you work now - but what does not work if second time is after 00:00 and first time is before 00:00. (e.g 23:00, 01:00 might return weird time like 07:34)? I can figure out why it does this. Thank you for help!.
That's because 01:00 lies before 23:00 (if you don't count date).
So if you have times crossing over 0:00 you'll need to add 1 day to the second time before you do SecondsBetween.

And after IncSeconds you take only the time-part (Fraction) to eliminate any cross-day boundaries.
(23:30 + 2000 seconds is 1 day and 00:03. But you only want the 00:03 part so Frac(1 day 0:03) is 0:03)

Something like this:
Code: Pascal  [Select]
  1. program Project1;
  2. uses
  3.   SysUtils,
  4.   DateUtils;
  5. var
  6.   time1, time2: TDateTime;
  7.   randomsecs: integer;
  8. begin
  9.   randomize;
  10.   time1 := EncodeTime(23, 30, 0, 0);
  11.   time2 := EncodeTime(01, 30, 0, 0);
  12.   if time2 < time1 then time2 := time2 + 1;
  13.   randomsecs := Random(SecondsBetween(time1, time2));
  14.   time2 := Frac(IncSecond(time1, randomsecs));
  15.   writeln('Time ', TimeToStr(time1), ' plus random ', randomsecs, 's is ', TimeToStr(time2));
  16.   readln;
  17. end.
« Last Edit: February 27, 2020, 11:48:15 am by rvk »

sash

  • Sr. Member
  • ****
  • Posts: 348
Re: Get random time from range of times?
« Reply #12 on: February 28, 2020, 11:51:26 am »
You guys over-complicate things. TDateTime in Pascal is already a float (double) and thus is a subject of simplest arithmetic.
Code: Pascal  [Select]
  1. function RandDateTimeInRange(DTBegin, DTEnd : TDateTime) : TDateTime;
  2. begin
  3.   Result := DTBegin + ((DTEnd - DTBegin) * Random);
  4. end;

This will return random TDateTime in [DTBegin, DTEnd) range. You just have to round and/or format it (discard date part or milliseconds) as you like.
Lazarus 2.0.6 FPC 3.0.4 x86_64-linux-gtk2 @ Ubuntu 19.10 XFCE

RayoGlauco

  • Jr. Member
  • **
  • Posts: 99
  • Beers: 1567
Re: Get random time from range of times?
« Reply #13 on: February 28, 2020, 01:20:04 pm »
Sash, this is the function I posted previously.
I would like to point out that it works ok even if DTBegin is greater than DTEnd.
« Last Edit: February 28, 2020, 01:25:00 pm by RayoGlauco »
To err is human, but to really mess things up, you need a computer.

lucamar

  • Hero Member
  • *****
  • Posts: 2579
Re: Get random time from range of times?
« Reply #14 on: February 28, 2020, 04:40:28 pm »
Thank you work now - but what does not work if second time is after 00:00 and first time is before 00:00. (e.g 23:00, 01:00 might return weird time like 07:34)? I can figure out why it does this. Thank you for help!.

Think a little about it: basicaly you are getting a random number in the interval 0 to 22 (23-1) while what you want is a number between 0 and 2. The easiest way to solve this is by testing and increasing the day if the origin is bigger that the final:

Code: Pascal  [Select]
  1. if Time1 > Time2 then IncDay(Time2, 1);

Note that this will only work if the date part of both are the same, which they probably are if you are setting them only as times; otherwise (Time1 - Time2) would give you the correct results.
« Last Edit: February 28, 2020, 04:42:46 pm by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.6/FPC 3.0.4 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.