Мне нужно что-то более гибкое, охватывающее разные форматы, поэтому я реализовал TTimeDiff
как:
uses
SysUtils,
DateUtils,
StrUtils,
Math;
type
TTimeDiff = record
type TTimeDiffFormat = (tdfFull, tdfSignificant, tdfAllNonZeros, tdfXNonZeros);
procedure Init(const ANow, AThen: TDateTime);
class function TimeDiff(const ANow, AThen: TDateTime): TTimeDiff; static;
function ToString(const TimeDiffFormat: TTimeDiffFormat; const Delimiter: string = ', ';
const NonZerosCount: Byte = 1): string;
case Integer of
0: (Years, Months, Days, Houres, Minutes, Seconds: Word);
1: (Values: array[0..5] of Word);
end;
{ TTimeDiff }
class function TTimeDiff.TimeDiff(const ANow, AThen: TDateTime): TTimeDiff;
begin
Result.Init(ANow, AThen);
end;
procedure TTimeDiff.Init(const ANow, AThen: TDateTime);
begin
Years := YearsBetween(ANow, AThen);
Months := MonthsBetween(ANow, AThen) mod 12;
Days := DaysBetween(IncMonth(Min(ANow, AThen), Years * 12 + Months), Max(ANow, AThen));
Houres := HoursBetween(ANow, AThen) mod 24;
Minutes := MinutesBetween(ANow, AThen) mod 60;
Seconds := SecondsBetween(ANow, AThen) mod 60;
end;
function TTimeDiff.ToString(const TimeDiffFormat: TTimeDiffFormat; const Delimiter: string = ', ';
const NonZerosCount: Byte = 1): string;
const
Captions: array [0..5] of string = ('year', 'month', 'day', 'hour', 'minute', 'second');
var
I: Integer;
VisitedNonZeros: Byte;
begin
Result := '';
VisitedNonZeros := 0;
for I := 0 to 5 do
begin
if Values[I] > 0 then
Inc(VisitedNonZeros);
if
(TimeDiffFormat = tdfFull) or
((TimeDiffFormat = tdfSignificant) and (VisitedNonZeros > 0)) or
((TimeDiffFormat in [tdfAllNonZeros, tdfXNonZeros]) and (Values[I] > 0))
then
begin
Result := Result + Format('%d %s%s%s', [Values[I], Captions[I], IfThen(Values[I] = 1, '', 's'), Delimiter]);
if (TimeDiffFormat = tdfXNonZeros) and (VisitedNonZeros = NonZerosCount) then
Break;
end;
end;
Result := Copy(Result, 1, Length(Result) - Length(Delimiter));
end;
TTimeDiffFormat
объяснение:
tdfFull
: включает все детали независимо от их значений (годы, месяцы, дни, часы, минуты и секунды соответственно).
tdfSignificant
: исключая ЛЕДИНГОВЫЕ детали с нулевым значением
tdfAllNonZeros
: исключая ВСЕ детали с нулевым значением
tdfXNonZeros
: включает только первые X ненулевых частей, где X по умолчанию установлен в 1
Как использовать:
var
ANow, AThen: TDateTime;
Diff: TTimeDiff;
begin
try
ANow := DateUtils.EncodeDateTime(1993, 11, 3, 21, 22, 18, 0);
AThen := DateUtils.EncodeDateTime(1993, 9, 21, 6, 21, 34, 0);
Writeln('Difference between ');
Writeln(FormatDateTime('YYYY/MM/DD HH:NN:SS', ANow), ' and');
Writeln(FormatDateTime('YYYY/MM/DD HH:NN:SS', AThen), ' is:');
Writeln('');
Diff.Init(ANow, AThen);
with Diff do
begin
Writeln(ToString(tdfFull));
Writeln(ToString(tdfSignificant, ' and '));
Writeln(TTimeDiff.TimeDiff(Athen, ANow).ToString(tdfSignificant), ' (inverted)');
Writeln(ToString(tdfAllNonZeros));
Writeln(ToString(tdfXNonZeros, ', ', 2));
Writeln(ToString(tdfXNonZeros));
readln;
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Результаты:
Difference between
1993/11/03 21:22:18 and
1993/09/21 06:21:34 is:
0 years, 1 month, 13 days, 15 hours, 0 minutes, 43 seconds
1 month and 13 days and 15 hours and 0 minutes and 43 seconds
1 month, 13 days, 15 hours, 0 minutes, 43 seconds (inverted)
1 month, 13 days, 15 hours, 43 seconds
1 month, 13 days
1 month