如何计算两个TDateTime的相隔时间(年、月、日、时、分、秒)? (100分)

  • 主题发起人 叮叮当当
  • 开始时间
to stucxm : 可以的。
to 叮叮当当:
可以对menxin的程序稍加修改就行了。
r3除与DaysInMonth(StartOfTheMonth(Date2)-1)整数部分
加到月数,余数就是天数。
程序就不写了,这两天手指痛。
 
TO: 冰封
没听懂,我的脑子现在已经满是浆糊了。。。
 
To: 叮叮当当
加一句dec(y, 1899)不就可以了?
 
Sorry,我误解了,因为可以以起始日期开始推算的。
 
我有个现成的vcl,现奉献出来:

{*************************************************************}
{ DateTime Calculator component for Delphi 16/32 }
{ Version: 1.3 }
{ Author: Aleksey Kuznetsov }
{ E-Mail: info@utilmind.com }
{ Home Page: http://www.utilmind.com }
{ Created: May, 12, 1999 }
{ Modified: August, 3, 1999 }
{ Legal: Copyright (c) 1999, UtilMind Solutions }
{*************************************************************}
{ TDTCalc (in English) }
{ Component for calculation of amount of years, months, days, }
{ hours, minutes, seconds and miliseconds past between two }
{ time intervals. }

{ PROPERTIES: }
{ StartTime, EndTime: TDateTime; - Range of time interval. }
{ READ ONLY PROPERTIES: }
{ Years: Int64 }
{ Months: Int64 }
{ Days: Int64 }
{ Hours: Int64 }
{ Minutes: Int64 }
{ Seconds: Int64 }
{ MSeconds: Int64 }
{*************************************************************}
{ Please see demo program for more information. }
{*************************************************************}
{ IMPORTANT NOTE: }
{ This software is provided 'as-is', without any express or }
{ implied warranty. In no event will the author be held }
{ liable for any damages arising from the use of this }
{ software. }
{ Permission is granted to anyone to use this software for }
{ any purpose, including commercial applications, and to }
{ alter it and redistribute it freely, subject to the }
{ following restrictions: }
{ 1. The origin of this software must not be misrepresented, }
{ you must not claim that you wrote the original software. }
{ If you use this software in a product, an acknowledgment }
{ in the product documentation would be appreciated but is }
{ not required. }
{ 2. Altered source versions must be plainly marked as such, }
{ and must not be misrepresented as being the original }
{ software. }
{ 3. This notice may not be removed or altered from any }
{ source distribution. }
{*************************************************************}
unit DTCalc;

interface

uses
{$IFDEF Win32} Windows, {$ELSE} WinTypes, WinProcs, {$ENDIF}
SysUtils, Classes;

type
TDTCalc = class(TComponent)
private
FStartTime, FEndTime: TDateTime;
FYears, FMonths, FDays, FHours, FMinutes: Int64;
FSeconds, FMSeconds: Int64;
procedure SetStartTime(Value: TDateTime);
procedure SetEndTime(Value: TDateTime);
procedure Calculate;
procedure SetNone(Value: Int64);
public
property Years: Int64 read FYears;
property Months: Int64 read FMonths;
property Days: Int64 read FDays;
property Hours: Int64 read FHours;
property Minutes: Int64 read FMinutes;
property Seconds: Int64 read FSeconds;
property MSeconds: Int64 read FMSeconds;
published
property StartTime: TDateTime read FStartTime write SetStartTime;
property EndTime: TDateTime read FEndTime write SetEndTime;
end;

procedure Register;

implementation

procedure TDTCalc.SetStartTime(Value: TDateTime);
begin
FStartTime := Value;
Calculate;
end;

procedure TDTCalc.SetEndTime(Value: TDateTime);
begin
FEndTime := Value;
Calculate;
end;

procedure TDTCalc.Calculate;
var
e: Extended;
TempStr: String;

procedure Truncate(var Value: Int64);
begin
try
Value := Trunc(e);
except
Value := -1;
end;
end;

begin
e := MSecsPerDay * (FEndTime - FStartTime);
Truncate(FMSeconds);
TempStr := IntToStr(FMSeconds);
if TempStr[Length(TempStr)] = '9' then inc(FMSeconds);
e := e / 1000;
Truncate(FSeconds);
e := e / 60;
Truncate(FMinutes);
e := e / 60;
Truncate(FHours);
e := e / 24;
Truncate(FDays);
FMonths := Trunc((FEndTime - FStartTime) / 30.4375);
FYears := Trunc((FEndTime - FStartTime) / 365.25);
end;

procedure TDTCalc.SetNone; begin {} end;

procedure Register;
begin
RegisterComponents('UtilMind', [TDTCalc]);
end;

end.
 
来自:叮叮当当, 时间:2002-5-29 23:15:00, ID:1131940
TO: xiao_ping
menxin的程序最后好像也有问题(计算天数的地方):
r3:=DayOf(Date2)-DayOf(Date1) +IfThen(DayOf(Date1)<=DayOf(Date2),0,DaysInMonth(StartOfTheMonth(Date2)-1));
假如
Date1=2000-01-30
Date2=2000-03-31

StartOfTheMonth(Date2)=2000-03-01
StartOfTheMonth(Date2)-1=2000-02-29 (TDataTime的整数部分就是天数,减1就等于天数减1)
DaysInMonth(StartOfTheMonth(Date2)-1)=29
DayOf(Date1)<=DayOf(Date2) 成立,因此 r3:=DayOf(Date2)-DayOf(Date1) +29=31-30+29=30 (天)
这是错误的,应该是“2个月零1天”。

其实,这程序基本上是可以的,就是你指出的地方有问题,修改的方法如下:
在他的程序最后部分加上
r2:= r2 + r3 div DaysInMonth(StartOfTheMonth(Date2)-1);
r3:= r3 mod DaysInMonth(StartOfTheMonth(Date2)-1);
 
To: hamsoft
你这段程序计算出来的和用HoursBetween、MinutesBetween、SecondsBetween算出来的一样。没法用。
 
只要照我说那样改就成了,虽然我没试过程序,
不过从数学逻辑的角度上看,一定可以。
 
To: 冰封
我试了一下
Date1=2000-01-30
Date2=2000-03-31
是没问题了,可是我又随便设了一下
Date1=2002-05-30
Date2=2002-06-29
就不对了,返回只有“1天”了。
程序比较复杂,我就不分析了。
 
呵呵,晚上上来看到,大概做了一下:对秒数的处理还有点小问题,但可能是数据类型精度
的问题了,困了,不改了,你看着办吧。用D6:
uses
DateUtils;
...

function DeTwoDateTime(Const St,Et :TDateTime):String;
Const
Fmt = '相差 %d 年 %d 月 %d 日 %d 小时 %d 分 %d 秒';
var
Year,Month,Day:Integer;
Hour,Min,Se:Integer;
begin
Year := YearsBetween(et,st);//相差总年数

Month := MonthsBetween(et,st) mod 12;//相差月数(年后的零头)

Day := Trunc(Et - IncMonth(IncYear(St,Year),Month));//取相隔XX年YY月后的天数零头

//下面的东东有点奇怪,你可以注释以后用2002-1-31与2002-6-1试试就明白了。
if (Et - Day) < IncMonth(Et,-1) then //如果间隔天数超过一个月
begin
Month := Month + 1;
Day := Day mod Trunc(Et - IncMonth(Et,-1));
end;


Hour := HoursBetween(Et,St) mod 24 ;//相差总小时
Min := MinutesBetween(Et,St) mod 60 ; //相差分钟
Se := SecondsBetween(Et,st) mod 60 ; // 相差秒数

Result := Format(Fmt,[Year,Month,Day,Hour,Min,Se]);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
t1,t2:TDateTime;
begin
T1:=StrToDateTime('2002-05-31 20:59:59');//如果两个都是整数时有问题,可能是
//Tdatatime类型数据无法准确表示一个小数的缘故。
//不是每个分数都能用一个小数精确表示,涉及分数小数之间的转换,所以精度可能有点问题
//你可以试一下,不影响太多的。
//你用19:00:00 与20:00:00试试就知道了,但17:00:00 与20:00:00是正确的。

T2:=StrToDateTime('2002-06-1 19:00:00');

ShowMessage(DeTwoDateTime(T1,T2));
end;

又想了一下:
对于时间(小时,分,秒等)的处理,应该以字符处理为主,这样就不会有格式的问题了。只是一个分解
字符串的过程,你自己试试吧。

只要是通过直接计算的方法,我想,可能都会存在我上面说的问题的。
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

好,搞定,安心睡觉!
 
TO: 杜宝
谢谢你,但是你的程序在
Date1=2002-05-30
Date2=2003-05-30
会返回“0年11月30天”
 
formatfloat(格式,date1-date2);
 
用DecodeDate函数试试,将日期分解开来
 
用函数daysbettween(),yearsbetween(),monthsbetween()
 
用一个sql函数就行了
 
什么SQL函数?
 
好像没有那么复杂吧
其实,TDatetime可以转换成TTimeStamp;
具体Ttimestamp啥意思,你可以看Delphi的帮助啦

返回秒数
function TForm1.GetDateTimeTo(AStart, AEnd: TDateTime): Real;
var
FStart,FEnd: TTimeStamp;
dd,tt : Real;
begin
FStart := DateTimeToTimeStamp(AStart);
FEnd := DateTimeToTimeStamp(AEnd);
dd := FEnd.Date-FStart.Date;(天数)
tt := (FEnd.Time-FStart.Time)/1000;(从00:00:00起秒数)
dd := dd*24*3600;
Result := dd+tt;
end;
具体应用,你自己参照这改就成了!
 
YearsBetween
MonthsBetween
daysBetween
MinutesBetween
SecondsBetween
MilliSecondBetween
利用上述函数分别来进行计算,然后逐一减去上面得到的数值后再计算
 
不会吧,这么简单的问题说得....
var
t1,t2:TDateTime;
...
t1:=now;
sleep(100);
t2:=now;
showmessage(formatdatetime(''<-这里写上自己要的格式,t1-t2));
..
///////////////////
记住TDateTime之间相减的结果仍然是TDateTime就行了,怎么转换就由你了。
 
顶部