program LastFridays;
{$mode objfpc}{$H+}
uses
SysUtils;
// Simple date structure
type
TDate = record
year : Integer;
month : Integer;
day : Integer;
end;
// Check if a year is leap year
function IsLeap(y: Integer): Boolean;
begin
if (y mod 400 = 0) then Exit(True);
if (y mod 100 = 0) then Exit(False);
Exit(y mod 4 = 0);
end;
// Days in each month
function DaysInMonth(y, m: Integer): Integer;
const
mdays: array[1..12] of Integer =
(31,28,31,30,31,30,31,31,30,31,30,31);
begin
if (m = 2) and IsLeap(y) then
Exit(29)
else
Exit(mdays[m]);
end;
(*
Pure arithmetic weekday:
Returns:
0 = Monday
1 = Tuesday
2 = Wednesday
3 = Thursday
4 = Friday
5 = Saturday
6 = Sunday
Algorithm:
Count days since 0001‑01‑01 (which was a Monday).
*)
function WeekdayMonday0(y, m, d: Integer): Integer;
var
yr, mo: Integer;
days: Int64;
begin
days := 0;
{ Add days for all previous years }
for yr := 1 to y - 1 do
if IsLeap(yr) then
Inc(days, 366)
else
Inc(days, 365);
{ Add days for previous months in this year }
for mo := 1 to m - 1 do
Inc(days, DaysInMonth(y, mo));
{ Add days in this month }
Inc(days, d - 1);
Result := days mod 7; { Monday = 0 }
end;
(*
// Return the last Friday of a specific month
// First day of next month
// Last day of this month
// Walk backward to Friday
*)
function LastFridayOfMonth(y: Integer; m: Integer): TDate;
var
last, d, w: Integer;
resultDate: TDate;
begin
{ Last day of this month }
last := DaysInMonth(y, m);
{ Walk backward to Friday }
for d := last downto 1 do
begin
w := WeekdayMonday0(y, m, d);
{ Friday = 4 }
if w = 4 then
begin
resultDate.year := y;
resultDate.month := m;
resultDate.day := d;
Exit(resultDate);
end;
end;
{ Should never happen }
resultDate.year := y;
resultDate.month := m;
resultDate.day := 1;
Result := resultDate;
end;
// Print all last Fridays of each month in a given year
procedure ListOfLastFridaysOfEachMonthIn(year: Integer);
var
m: Integer;
d: TDate;
begin
for m := 1 to 12 do
begin
d := LastFridayOfMonth(year, m);
WriteLn(d.year, '-', d.month, '-', d.day);
end;
end;
begin
ListOfLastFridaysOfEachMonthIn(2026);
end.
(*
run:
2026-1-30
2026-2-27
2026-3-27
2026-4-24
2026-5-29
2026-6-26
2026-7-31
2026-8-28
2026-9-25
2026-10-30
2026-11-27
2026-12-25
*)