I'm using Delphi 11 with the new DateUtils library but i'm not able to get a date of same day in the past, for a given number of years. i must retirn the same day of week for a given date of n years ago. so if today is sunday i must return the same sunday of n years ago. i added the complete source of a real test application written in delphi with a bug fixed
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls, system.DateUtils, system.Types;
type
TForm1 = class(TForm)
dtDataOggi: TDateTimePicker;
Label1: TLabel;
edYears: TEdit;
bnCalcola: TButton;
procedure bnCalcolaClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
function annobisestile(value : tDate) : integer;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.bnCalcolaClick(Sender: TObject);
var
DataAppoggio : tDate;
NumberOfYearToSubtract : integer;
annobis : integer; // is leap year?
annoappoggio : integer;
giorno : boolean;
febb28 :tDate;
i : integer;
begin
DataAppoggio := dtDataOggi.date;
NumberOfYearToSubtract := strToInt(edYears.Text);
annobis := 0;
annoappoggio := yearOf(DataAppoggio);
febb28 := encodedate(annoappoggio ,2,28);
if CompareDate(febb28,DataAppoggio) = GreaterThanValue then
Giorno := true
else
Giorno := false;
DataAppoggio := IncYear(DataAppoggio, -NumberOfYearToSubtract);
// check if adataappoggio is before feb 28 so i must add a day
if giorno then begin
for I := 0 to NumberOfYearToSubtract do begin
//annobiststile is a custom functions that returns 1 if the given year is a leap year
annobis := annobis annobisestile(encodeDate(annoappoggio,01,01));
annoappoggio := annoappoggio -1;
end;
end
else begin
for I := 0 to NumberOfYearToSubtract -1 do begin
annobis := annobis annobisestile(encodeDate(annoappoggio,01,01));
annoappoggio := annoappoggio -1;
end;
end;
label1.Caption := incDay(DataAppoggio, NumberOfYearToSubtract annobis).ToString;
end;
function TForm1.annobisestile(value: tDate): integer;
begin
if IsInLeapYear(value) then
result := 1
else
result := 0;
end;
this functions return the exact day of a given numbers of past years but if this years are 3 or more, it does not mattch the same WeekOfTheYear. any idea? thank you.
CodePudding user response:
You're overcomplicating things. You don't need function annobisestile
and you can replace TForm1.bnCalcolaClick
with the following method.
In a nutshell, this subtracts the specified number of years, then adjusts the date by the number of days that it's off the original day of the week.
(This was done with 10.4, which doesn't have the new TDateTime helpers, so I've used DateToStr()
instead of .toString
.)
procedure TForm1.bnCalcolaClick(Sender: TObject);
var
DataAppoggio : tDate;
NumberOfYearToSubtract : integer;
DOW : Integer;
begin
DataAppoggio := dtDataOggi.date;
NumberOfYearToSubtract := strToInt(edYears.Text);
DOW := DayOfWeek(DataAppoggio);
DataAppoggio := IncYear(DataAppoggio,-NumberOfYearToSubtract);
DataAppoggio := IncDay(DataAppoggio,DOW-DayOfWeek(DataAppoggio));
label1.Caption := DateToStr(DataAppoggio);
end;
CodePudding user response:
The solution is straight forward if you need the date of same week number and same day of the week n
years before (or later). The System.DateUtils
unit has all necessary functions.
First use functions YearOf()
, WeekOf()
and DayOfTheWeek()
to get InputYear
, InputWeek
and InputDOW
(day-of-week) from the InputDate
.
Then use the EncodeDateWeek()
function to convert InputYear
YearsToAdd
, InputWeek
, InputDOW
to a TDateTime
;
A complete sample code follows:
procedure TForm2.Button3Click(Sender: TObject);
var
InputDate: TDate;
InputYear: word;
InputWeek: word;
InputDOW: word;
YearsToAdd: word;
dt: TDate;
begin
InputDate := dtDataOggi.date;
InputYear := YearOf(InputDate);
InputWeek := WeekOf(InputDate);
InputDOW := DayOfTheWeek(InputDate); // ISO 8601 Monday is first dow,
// use DayOfWeek() for Sunday as first dow
YearsToAdd := strToInt(edYears.Text); // use '-' in input for subtraction
dt := EncodeDateWeek(InputYear YearsToAdd, InputWeek, InputDOW);
Memo1.Lines.Add(DateToStr(InputDate));
Memo1.Lines.Add(DateToStr(dt));
end;