我使用这段代码来获取Delphi中两个日期选择器之间的区别。
Scanner sc = new Scanner(textfile);
int lenght = 0;
while (sc.hasNextLine()) {
try {
for (int j = 0; j != 0; j++) {
ImageMatrixGUI.getInstance().addImage(Land);
ArrayImages.add(Land);
}
char tipo = sc.next().charAt(0);
System.out.println(tipo);
if (tipo == 'p') {
ImageMatrixGUI.getInstance().addImage(pine);
}
}
}
当我运行该程序时,默认情况下弹出两个日期选择器的表单我将日期设置为月份差异。
如果我尝试更改结束日期,在第一次更改中它可以正常工作,但如果我再次尝试更改它,则不会根据开始日期和结束日期之间的月份差异更新标签。 基本上onchange事件不会捕获所有事件,或者至少是我理解的事件。我需要正确获取updateLabelandBtn过程的输出。
这是从另一种形式调用的子表单:
procedure TForm.CreateForm;
var
currDate : TDateTime;
begin
currDate := Now;
dtpStartDate.Date := currDate;
dtpEndDate.Date := IncMonth(currDate);
end;
procedure TForm.updateLabelandBtn;
var
monthsDiff :Double;
begin
monthsDiff := (MonthOf( dtpEndDate.Date ) - MonthOf( dtpStartDate.Date )) + ((DayOf( dtpEndDate.Date ) - DayOf( dtpStartDate.Date))/32);
if (dtpEndDate.Date > dtpStartDate.Date ) then
begin
if (monthsDiff >1 ) then
begin
lblMsg.Caption := 'Wait';
btnStart.Enabled := True;
end
end
else
begin
btnStart.Enabled := False;
lblMsg.Caption := 'start date should be smaller than end date.';
end;
end;
procedure TForm.dtpEndDateChange(Sender: TObject);
begin
updateLabelandBtn;
end;
procedure TForm.dtpStartDateChange(Sender: TObject);
begin
updateLabelandBtn;
end;
end.
输入示例:
begin
try
Form.CreateForm;
if Form.ShowModal = mrOk then
RunQuery;
finally
Form.Release
end
答案 0 :(得分:2)
首先,你的差异计算相当奇怪,所以我建议改为使用DaysBetween()
和DaysInMonth()
函数:
<击> 撞击>
<击>if DaysBetween(dtpEndDate.Date, dtpStartDate.Date) >= DaysInMonth(dtpStartDate.Date) then
击> <击> 撞击> (见下面的编辑)
这可以正确接受,例如2月1日和3月1日以及7月1日和8月1日或1月15日(明年15月12日)
其次,据我所知,从开始到结束必须至少有一个月的时间。如果未满足此条件,则应添加错误消息。
编辑&#34; saastn&#34;在他们自己的答案中评论了这个答案,并指出了开始日期是在下个月不存在的一天的错误,结束日期是在下个月的第一个或第二个月。例如,开始日期= 31.1,结束日期= 1.3。为了涵盖这些日期,他们建议也考虑月份序数的差异,因此公式变为
if ((DaysBetween(dtpEndDate.Date, dtpStartDate.Date) >= DaysInMonth(dtpStartDate.Date)) or
(MonthOf(dtpEndDate.Date) - MonthOf(dtpStartDate.Date) >= 2)) then
请在&#34; saastn&#34;
的答案中进一步阅读答案 1 :(得分:2)
考虑到已接受的答案,似乎这个问题已经缩小到&#34;如何检查两个日期之间的差异是否少于一个月?&#34; 。 Toms建议使用DaysBetween
和DaysInMonth
函数。以下函数使用他的逻辑:
function DatesDiffLessThanAMonth_Tom(const FromDate, ToDate: TDate): Boolean;
begin
Result :=
(DaysBetween(ToDate, FromDate) <= DaysInMonth(FromDate));
end;
它适用于大多数情况,但仍然有一些例外:
FromDate ToDate DsIM1 DsB
2016-01-30 - 2016-03-01 31 31
2016-01-31 - 2016-03-01 31 30
2016-01-31 - 2016-03-02 31 31
2016-03-31 - 2016-05-01 31 31
2016-05-31 - 2016-07-01 31 31
2016-08-31 - 2016-10-01 31 31
2016-10-31 - 2016-12-01 31 31
2017-01-29 - 2017-03-01 31 31
2017-01-30 - 2017-03-01 31 30
2017-01-30 - 2017-03-02 31 31
2017-01-31 - 2017-03-01 31 29
2017-01-31 - 2017-03-02 31 30
2017-01-31 - 2017-03-03 31 31
2017-03-31 - 2017-05-01 31 31
2017-05-31 - 2017-07-01 31 31
2017-08-31 - 2017-10-01 31 31
2017-10-31 - 2017-12-01 31 31
我们可以将日期的一个月考虑在内以克服这个问题:
function DatesDiffLessThanAMonth_Tom_Mod(const FromDate, ToDate: TDate): Boolean;
begin
Result :=
(DaysBetween(ToDate, FromDate) <= DaysInMonth(FromDate)) and
(MonthOf(ToDate) - MonthOf(FromDate) < 2);
end;
我用另一个功能检查了这一点,我相信它更具可读性和更快(2938毫秒相比,18221216呼叫为4125毫秒),并且它们都返回了从1900到5000的相同结果:
function DatesDiffLessThanAMonth(const FromDate, ToDate: TDate): Boolean;
var
Y1, M1, D1, Y2, M2, D2: Word;
begin
DecodeDate(FromDate, Y1, M1, D1);
DecodeDate(ToDate, Y2, M2, D2);
Result :=
((Y1 = Y2) and (M1 = M2)) or
((Y1 = Y2) and (M1 = M2 -1) and (D2 <= D1)) or
((Y1 = Y2 - 1) and (M1 = 12) and (M2 = 1) and (D2<=D1));
end;
此功能的另一个优点是它可以用于其他12个日历系统,如Solar Hijri (Jalali)和Islamic (the Lunar one)日历。实际上我基本上为Hijri日历开发了这个功能。我不知道此日历包含DaysBetween
和DaysInMonth
函数的任何可靠日期库,而在Hijri中编码和解码日期well tested libraries并将它们转换为阳历日历
答案 2 :(得分:1)
'then'和'lblMsg.Caption:='等待'之间应该有'开始'。在格式化代码时很容易看到问题。
if (dtpEndDate.Date > dtpStartDate.Date ) then
begin
if (monthsDiff >1 )
then lblMsg.Caption := 'Wait'; // oops!
btnStart.Enabled := True;
end
应该是
if (dtpEndDate.Date > dtpStartDate.Date ) then
begin
if (monthsDiff >1 ) then
begin
lblMsg.Caption := 'Wait';
btnStart.Enabled := True;
end
end
else
begin
btnStart.Enabled := False;
lblMsg.Caption := 'start date should be smaller than end date.';
end;
答案 3 :(得分:1)
使用MonthSpan或MonthsBetween存在一个基本问题,即两者都基于一个月的平均长度(每月30.4375天)给出近似值。我怀疑你想要更像以下内容:
function LogicalMonthSpan( const pDate1, pDate2 : TDateTime ) : Double;
begin
Result := (YearOf( pDate2 ) - YearOf(pDate1))* 12 + (MonthOf( pDate2 ) - MonthOf( pDate1 )) + ((DayOf( PDate2 ) - DayOf( pDate1))/32);
end;
将考虑2月15日至3月16日> 1个月,而MonthSpan会显示它不到1个月