Delphi генерирует случайное значение даты и времени между диапазоном даты и времени

Я пытаюсь генерировать случайные значения Tdatetime в заданном диапазоне в delphi 5 скажем, у нас есть две даты в следующем формате

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

я хочу сгенерировать даты exaclty "x", увеличенные между этим диапазоном. В качестве примера я хотел бы сгенерировать 7 дат из диапазона 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

проблема в том, что если вторая случайная дата богата датой2, то все остальные даты должны быть такими же, как дата2, но если время достигает 23:59:59, следующая дата будет вне диапазона

как в следующем сценарии

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

!! все даты с этого момента будут

06/01/2018 23:59:59

что вне моего диапазона !!

любая помощь будет оценена по достоинству

После предложения Андреаса вот окончательный код, который работает на D5, поэтому я думаю, что он работает на всех других версиях 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.

person delphifive    schedule 04.09.2018    source источник
comment
Все миллисекунды равны 0? Вы разрешаете дубликаты в списке? Должен ли список начинаться с date1? Должен ли он заканчиваться на date2?   -  person Andreas Rejbrand    schedule 04.09.2018
comment
Это кажется довольно тривиальной проблемой. Я думаю, вам нужно показать нам свой минимально воспроизводимый пример кода, а не только результаты.   -  person Dsm    schedule 04.09.2018
comment
Нет дубликатов (я предпочитаю, чтобы временные диапазоны имели разницу не менее 5 минут между ними. 1-я дата должна быть первой датой в диапазоне, последняя дата должна быть последней датой в диапазоне   -  person delphifive    schedule 04.09.2018


Ответы (1)


Функцию для генерации случайного значения TDateTime между двумя фиксированными значениями можно записать следующим образом (uses DateUtils):

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

Чтобы создать из них отсортированный список, используйте свой любимый метод сортировки. В современном Delphi вы можете использовать встроенный общий список:

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;

Попробуйте:

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;

(Этот подход может привести к дублированию даты и времени. Q явно не упомянул, разрешено это или нет. Кроме того, он работает только с точностью до секунды, а не с точностью до миллисекунды. Вы можете изменить это или, по крайней мере, удалить миллисекунду из AFrom .)

person Andreas Rejbrand    schedule 04.09.2018
comment
да, в моем delphi 5 у меня нет функции SecondsBetween, я собираюсь написать ее сейчас. также я не понимаю, что делает функция IncSecond. - person delphifive; 04.09.2018
comment
Я указал даты 09.04.2018 и 09.07.2018 (формат дд/мм/гггг) и задал 10 случайных дат в диапазоне, который я взял. 10.01.2018 04:58:24 10.05.2018 04:48:24 11.05.2018 12:44:48 11.07.2018 21:48:24 10.08.2018 04:58:48 10.09.2018 10:16:24 11.10.2018 23:42:24 09.11.2018 10:52:48 11.12.2018 05:26:48 09.15.2018 13:52:00 кажется, не получает первое свидание - person delphifive; 04.09.2018
comment
@delphifive Разве не ясно, что вы допустили ошибку. В ваших собственных функциях вы используете SecsPerMin * MinsPerHour * HoursPerDay для преобразования в секунды, но только /60/60 для обратного преобразования. - person Tom Brunberg; 04.09.2018
comment
Спасибо !!!!!!! Исправленный результат: = AFrom + (Round(SecsBetween * Random)/(60*60*24)); - person delphifive; 04.09.2018
comment
@delphifive: вам нужно посмотреть, как преобразовать строки в дату и время в Delphi. Используйте Google. - person Andreas Rejbrand; 04.09.2018
comment
Все работает нормально, теперь я отредактировал правильный код. Большое спасибо, вы спасли мой день сегодня. - person delphifive; 04.09.2018