我对用于从日期算起星期数的代码有疑问。 该应用程序是报表生成器。 语言是:报表应用程序编程(RAP)RAP语言与对象Pascal相同。
我的书面代码适用于2017年和2018年。 但这不适用于2019年和2020年。
有人知道我在这里做错了吗?
if (AVX['P_DELDATE'] >= 42737) and (AVX['P_DELDATE'] <= 43100) {= Jahr 2017} then begin
Value:= (AVX['P_DELDATE'] - 1 - (42737-1) + 7-((AVX['P_DELDATE'] -1 - (42737-1) ) mod 7))/7;
end else begin
if (AVX['P_DELDATE'] >= 43101) and (AVX['P_DELDATE'] <= 43465) {= Jahr 2018} then begin
Value:= (AVX['P_DELDATE'] - 1 - (43101-1) + 7-((AVX['P_DELDATE'] -1 - (43101-1) ) mod 7))/7;
end;
end else begin
if (AVX['P_DELDATE'] >= 43466) and (AVX['P_DELDATE'] <= 43830) {= Jahr 2019} then begin
Value:= (AVX['P_DELDATE'] - 1 - (43466-1) + 7-((AVX['P_DELDATE'] -1 - (43466-1) ) mod 7))/7;
end;
end else begin
if (AVX['P_DELDATE'] >= 43831) and (AVX['P_DELDATE'] <= 44196) {= Jahr 2020} then begin
Value:= (AVX['P_DELDATE'] - 1 - (43831-1) + 7-((AVX['P_DELDATE'] -1 - (43831-1) ) mod 7))/7;
end;
end;
end;
答案 0 :(得分:1)
您没有说为什么要问进行周数计算
在RAP代码中。除了我找不到AVX
的定义外,
RAP文档中的函数,尝试计算周数
在RAP中使用AVX
显然很容易出错,而不是自我记录,并且是一种几乎不能容忍的方式。
很明显,您的函数(?,或者也许是报告字段)AVX
返回一个数值,其整数部分对应于TDateTime值的整数部分。在示例项目中
下面-我已经包括了它,以显示一种更容易,更不易出错的方式
解决问题的过程中,我包括了一个(希望)与您的RAP功能匹配的函数,如下所示:
function WeekNumber(Day : Integer) : Double;
begin
if (Day >= 42737) and (Day <= 43100) {= Jahr 2017} then begin
result:= (Day - 1 - (42737-1) + 7-((Day -1 - (42737-1) ) mod 7))/7;
end
else begin
if (Day >= 43101) and (Day <= 43465) {= Jahr 2018} then begin
result:= (Day - 1 - (43101-1) + 7-((Day -1 - (43101-1) ) mod 7))/7;
end
else begin
if (Day >= 43466) and (Day <= 43830) {= Jahr 2019} then begin
result:= (Day - 1 - (43466-1) + 7-((Day -1 - (43466-1) ) mod 7))/7;
end
else begin
if (Day >= 43831) and (Day <= 44196) {= Jahr 2020} then begin
result:= (Day - 1 - (43831-1) + 7-((Day -1 - (43831-1) ) mod 7))/7;
end;
end;
end;
end;
end;
(顺便说一句,在进行此转换时,我不得不修复RAP代码中的一些语法错误,如果您自己尝试转换,很快就会发现。)
然后,我添加了一个过程来测试此功能:
procedure TForm1.TestWeekNumber;
var
Date : TDateTime;
i : integer;
procedure TestInner(Date : TDateTime);
var
WN1,
WN2 : Double;
S,
SError : String;
begin
WN1 := WeekOf(Date);
WN2 := WeekNumber(Trunc(Date));
if WN1 = WN2 then
SError := ''
else
SError := '***';
S := Format('Date: %s WeekOf: %g WeekNumber: %g %s',[ DateTimeToStr(Date), WN1, WN2, SError]);
if SError <> '' then
Memo1.Lines.Add(S);
end;
begin
Date := StrToDateTime('01/01/2017');
Memo1.Lines.BeginUpdate;
try
for i := 0 to 1999 do
TestInner(Date + i);
finally
Memo1.Lines.EndUpdate;
end;
end;
这会将您的WeekNumber
与DateUtils.Pas中的标准WeekOf
函数进行比较,该函数返回ISO 8601标准所定义的星期数,即TDateTime输入值,并将这些值写入TMemo当他们产生不同的结果时。以下是输出的摘录:
Date: 01/01/2017 WeekOf: 52 WeekNumber: 1.13989900694441E-307 ***
Date: 31/12/2018 WeekOf: 1 WeekNumber: 53 ***
Date: 07/01/2019 WeekOf: 2 WeekNumber: 1 ***
Date: 14/01/2019 WeekOf: 3 WeekNumber: 2 ***
Date: 21/01/2019 WeekOf: 4 WeekNumber: 3 ***
Date: 28/01/2019 WeekOf: 5 WeekNumber: 4 ***
Date: 04/02/2019 WeekOf: 6 WeekNumber: 5 ***
Date: 11/02/2019 WeekOf: 7 WeekNumber: 6 ***
[...]
Date: 06/01/2020 WeekOf: 2 WeekNumber: 1 ***
Date: 07/01/2020 WeekOf: 2 WeekNumber: 1 ***
Date: 13/01/2020 WeekOf: 3 WeekNumber: 2 ***
Date: 14/01/2020 WeekOf: 3 WeekNumber: 2 ***
Date: 20/01/2020 WeekOf: 4 WeekNumber: 3 ***
Date: 21/01/2020 WeekOf: 4 WeekNumber: 3 ***
Date: 27/01/2020 WeekOf: 5 WeekNumber: 4 ***
Date: 28/01/2020 WeekOf: 5 WeekNumber: 4 ***
Date: 03/02/2020 WeekOf: 6 WeekNumber: 5 ***
Date: 04/02/2020 WeekOf: 6 WeekNumber: 5 ***
Date: 10/02/2020 WeekOf: 7 WeekNumber: 6 ***
如您所见,事情从2018年底开始出现问题,此后, 错误的值似乎暗示了一种“偏离”错误。我离开 您可以自己进行调查并解决此问题。
我自己没有进一步研究它的原因是在我看来 您的操作方式是混乱的,并且可以避免复杂。添加周数实际上是微不足道的 通过添加带有星期数的计算字段来支持您的RBuilder报告 值提供给报表的数据集。这样做的代码如下所示。
或者,您可以使用ReportBuilder的工具来添加WeekNumber
可以采用任何datetime值的RAP运行时语言(例如
任何数据集datetime字段中的值)。参见例如可使用ReportBuilder开发人员指南第p213页的Extending RAP - RAP Pass-Through Functions
此处:Report Builder Developer's Guide。描述什么
可能是最灵活的方法来显示Delphi函数
在报告中,尽管ISTR还有其他内容。
代码(为简单起见,不包括RBuilder组件)
type
TForm1 = class(TForm)
CDS1: TClientDataSet;
DataSource1: TDataSource;
DBGrid1: TDBGrid;
DBNavigator1: TDBNavigator;
procedure FormCreate(Sender: TObject);
procedure CDS1CalcFields(DataSet: TDataSet);
private
procedure CreateDataSetFields;
protected
public
end;
[...]
implementation
uses
DateUtils;
procedure TForm1.FormCreate(Sender: TObject);
var
i : Integer;
begin
CreateDataSetFields; // see below
CDS1.CreateDataSet;
// Insert one row per day for current year
for i := 1 to 365 do begin
CDS1.InsertRecord([i, i + Now - DayOfTheYear(Now)]);
end;
CDS1.First;
end;
procedure TForm1.CDS1CalcFields(DataSet: TDataSet);
begin
// This sets the WeekNo calculated field to the value returned by the DateUtils.WeekOf function
DataSet.FieldByName('WeekNo').AsInteger := WeekOf(DataSet.FieldByName('Date').AsDateTime);
end;
procedure TForm1.CreateDataSetFields;
var
Field : TField;
begin
Field := TIntegerField.Create(Self);
Field.FieldKind := fkData;
Field.FieldName := 'ID';
Field.Name := 'ID';
Field.DataSet := CDS1;
Field := TDateTimeField.Create(Self);
Field.FieldKind := fkData;
Field.FieldName := 'Date';
Field.Name := 'Date';
Field.DataSet := CDS1;
Field := TIntegerField.Create(Self);
Field.FieldKind := fkInternalCalc;
Field.FieldName := 'WeekNo';
Field.Name := 'WeekNo';
Field.DataSet := CDS1;
end;