简体   繁体   中英

Delphi generate random date time value between range of date time

I am trying to generate random Tdatetime values in given range in delphi 5 lets say we have two dates in the follow format

date1=01/01/2018 12:35:32 
date2=05/01/2018 21:35:32 

i want to generate exaclty "x" dates increased between this range. As an example i would like to generate 7 Dates from range date1->date2

randomdate[0]:=01/01/2018 12:35:32 
randomdate[1]:=01/01/2018 14:35:12 
randomdate[2]:=01/01/2018 16:42:22 
randomdate[3]:=02/01/2018 21:12:01
randomdate[4]:=03/01/2018 11:13:12
randomdate[5]:=04/01/2018 22:20:05
randomdate[6]:=05/01/2018 20:30:05

the problem is that if second random date rich the date2 then all other dates must be the same as date2 but if the time gets 23:59:59 next date will be out of range

like the folow senario

randomdate[0]:=01/01/2018 12:35:32 
randomdate[1]:=05/01/2018 23:59:59
.................................

!! all dates from now on will be

06/01/2018 23:59:59

which is out of my range !!

any help will be appreciate it

After Andreas Suggestion here is the finally code who works on D5 so i guess works on all other versions of delphi

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ComCtrls;

type
  TForm1 = class(TForm)
    RichEdit1: TRichEdit;
    Edit1: TEdit;
    Edit2: TEdit;
    Button1: TButton;
    Edit3: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

function SecondsBetween(const Time1, Time2: TDateTime): Longint;
const SecsPerMin=60;
const MinsPerHour=60;
const HoursPerDay=24;
begin
result := Round(SecsPerMin * MinsPerHour * HoursPerDay * Abs(Time2 - Time1));
end;


function RandomDateTime( AFrom, ATo: TDateTime): TDateTime;
var
  SecsBetween: int64;
begin
  SecsBetween := SecondsBetween(AFrom,ATo);
  result := AFrom + (Round(SecsBetween * Random) / (60*60*24));
end;


function CreateSortedListOfRandomDatetimes( AFrom, ATo: TDateTime; N: integer): TStringlist;
var
  i: Integer;
begin
  result := Tstringlist.Create;
  try
//    result.Capacity := N; // for an unnoticeable increase in performance
    for i := 1 to N do   result.Add(formatdatetime('dd/mm/yyyy hh:nn:ss',RandomDateTime(AFrom, ATo)));
    result.Sort;
  except
    result.Free;
    raise;
  end;
end;


//edit1 Holds the 1st date which is  04/09/2018 16:00:00
//edit2 hold the 2nd date
//edit3 holds the N count value
procedure TForm1.Button1Click(Sender: TObject);
var
  timestamps: Tstringlist;
  i: Integer;
  d1:Tdatetime;
  d2:Tdatetime;
begin
d1:=StrtoDatetime(edit1.text);
d2:=StrtoDatetime(edit2.text);

  timestamps := CreateSortedListOfRandomDatetimes(d1,d2 ,strtoInt(edit3.text));
  try
    RichEdit1.Lines.BeginUpdate;
    try
      RichEdit1.Lines.Clear;
      for i := 0 to timestamps.Count - 1 do
        RichEdit1.Lines.Add(timestamps.strings[i])
    finally
      RichEdit1.Lines.EndUpdate;
    end;
  finally
    timestamps.Free;
  end;

end;

procedure TForm1.FormCreate(Sender: TObject);
begin
randomize;
end;

end.

A function to generate a random TDateTime value between two fixed values can be written like this ( uses DateUtils ):

function RandomDateTime(const AFrom, ATo: TDateTime): TDateTime;
var
  SecsBetween: Int64;
begin
  SecsBetween := SecondsBetween(AFrom, ATo);
  result := IncSecond(AFrom, Round(SecsBetween * Random));
end;

To create a sorted list of these, use your favourite sorting method. In modern Delphi, you could use the built-in generic list:

function CreateSortedListOfRandomDatetimes(const AFrom, ATo: TDateTime; N: integer): TList<TDateTime>;
var
  i: Integer;
begin
  result := TList<TDateTime>.Create;
  try
    result.Capacity := N; // for an unnoticeable increase in performance
    for i := 1 to N do
      result.Add(RandomDateTime(AFrom, ATo));
    result.Sort;
  except
    result.Free;
    raise;
  end;
end;

Try it out:

procedure TForm1.FormCreate(Sender: TObject);
var
  timestamps: TList<TDateTime>;
  i: Integer;
begin
  timestamps := CreateSortedListOfRandomDatetimes(
    EncodeDateTime(2000, 1, 1, 0, 0, 0, 0),
    EncodeDateTime(2000, 12, 31, 23, 59, 59, 999),
    10
  );
  try
    RichEdit1.Lines.BeginUpdate;
    try
      RichEdit1.Lines.Clear;
      for i := 0 to timestamps.Count - 1 do
        RichEdit1.Lines.Add(DateTimeToStr(timestamps[i]))
    finally
      RichEdit1.Lines.EndUpdate;
    end;
  finally
    timestamps.Free;
  end;
end;

(This approach may produce duplicate datetimes. The Q didn't explicitly mention if this is allowed or not. Also, it only works at second precision, not millisecond precision. You may want to change that, or at least remove the millisecond from AFrom .)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM