周数计算

时间:2019-02-08 11:28:06

标签: pascal week-number

我对用于从日期算起星期数的代码有疑问。 该应用程序是报表生成器。 语言是:报表应用程序编程(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;

1 个答案:

答案 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;