Long year

From Rosetta Code
Task
Long year
You are encouraged to solve this task according to the task description, using any language you may know.

Most years have 52 weeks, some have 53, according to ISO8601.


Task

Write a function which determines if a given year is long (53 weeks) or not, and demonstrate it.

11l

Translation of: C++
F is_long_year(year)
   F p(year)
      R (year + (year I/ 4) - (year I/ 100) + (year I/ 400)) % 7
   R p(year) == 4 | p(year - 1) == 3

L(year) 2000..2100
   I is_long_year(year)
      print(year, end' ‘ ’)
Output:
2004 2009 2015 2020 2026 2032 2037 2043 2048 2054 2060 2065 2071 2076 2082 2088 2093 2099

Action!

BYTE FUNC P(CARD y)
RETURN ((y+(y/4)-(y/100)+(y/400)) MOD 7)

BYTE FUNC IsLongYear(CARD y)
  IF P(y)=4 OR P(y-1)=3 THEN
    RETURN (1)
  FI
RETURN (0)

PROC Main()
  CARD y
  BYTE LMARGIN=$52,oldLMARGIN

  oldLMARGIN=LMARGIN
  LMARGIN=0 ;remove left margin on the screen
  Put(125) PutE() ;clear the screen

  FOR y=1900 TO 2400
  DO
    IF IsLongYear(y) THEN
      PrintC(y) Put(32)
    FI
  OD

  LMARGIN=oldLMARGIN ;restore left margin on the screen
RETURN
Output:

Screenshot from Atari 8-bit computer

1903 1908 1914 1920 1925 1931 1936 1942 1948 1953 1959 1964 1970 1976 1981 1987
1992 1998 2004 2009 2015 2020 2026 2032 2037 2043 2048 2054 2060 2065 2071 2076
2082 2088 2093 2099 2105 2111 2116 2122 2128 2133 2139 2144 2150 2156 2161 2167
2172 2178 2184 2189 2195 2201 2207 2212 2218 2224 2229 2235 2240 2246 2252 2257
2263 2268 2274 2280 2285 2291 2296 2303 2308 2314 2320 2325 2331 2336 2342 2348
2353 2359 2364 2370 2376 2381 2387 2392 2398

Ada

The Ada calendar package handles dates for years 1901 through 2399. This program outputs all the long years within that range.

-------------------------------------------------------------
-- Calculate long years
-- Reference: https://en.wikipedia.org/wiki/ISO_week_date#Weeks_per_year
-------------------------------------------------------------
with Ada.Text_IO;             use Ada.Text_IO;
with Ada.Calendar;            use Ada.Calendar;
with Ada.Calendar.Formatting; use Ada.Calendar.Formatting;

procedure Main is
   First_Day : Time;
   Last_Day  : Time;
   package AC renames Ada.Calendar;
   type Counter is mod 10;
   Count : Counter := 0;
begin
   for Yr in Year_Number loop

      First_Day := AC.Time_Of (Year => Yr, Month => 1, Day => 1);
      Last_Day  := AC.Time_Of (Year => Yr, Month => 12, Day => 31);
      
      -- If Jan 1 is Thursday or Dec 31 is Thursday then
      -- the year is a long year
      
      if Day_Of_Week (First_Day) = Thursday
        or else Day_Of_Week (Last_Day) = Thursday
      then
         if Count = 0 then
            New_Line;
         end if;
         Put (Yr'Image);
         Count := Count + 1;
      end if;
   end loop;
end Main;
Output:
 1903 1908 1914 1920 1925 1931 1936 1942 1948 1953
 1959 1964 1970 1976 1981 1987 1992 1998 2004 2009
 2015 2020 2026 2032 2037 2043 2048 2054 2060 2065
 2071 2076 2082 2088 2093 2099 2105 2111 2116 2122
 2128 2133 2139 2144 2150 2156 2161 2167 2172 2178
 2184 2189 2195 2201 2207 2212 2218 2224 2229 2235
 2240 2246 2252 2257 2263 2268 2274 2280 2285 2291
 2296 2303 2308 2314 2320 2325 2331 2336 2342 2348
 2353 2359 2364 2370 2376 2381 2387 2392 2398

ALGOL 68

Translation of: ALGOL W
BEGIN # find "long years" - years which have 53 weeks this is equivalent to #
      # finding years where 1st Jan or 31st Dec are Thursdays               #
    # returns the day of the week of the specified date (d/m/y), Sunday = 1 #
    PROC day of week = ( INT d, m, y )INT:
         BEGIN
            INT mm := m;
            INT yy := y;
            IF mm <= 2 THEN
                mm := mm + 12;
                yy := yy - 1
            FI;
            INT j = yy OVER 100;
            INT k = yy MOD  100;
            (d + ( ( mm + 1 ) * 26 ) OVER 10 + k + k OVER 4 + j OVER 4 + 5 * j ) MOD 7
         END # day of week # ;
    # returns TRUE if year is a long year, FALSE otherwise                  #
    PROC is long year = ( INT year )BOOL:
        day of week( 1, 1, year ) = 5 OR day of week( 31, 12, year ) = 5;
    # show long years from 2000-2099                                        #
    print( ( "long years 2000-2099:" ) );
    FOR year FROM 2000 TO 2099 DO
        IF is long year( year ) THEN print( ( " ", whole( year, 0 ) ) ) FI
    OD
END
Output:
long years 2000-2099: 2004 2009 2015 2020 2026 2032 2037 2043 2048 2054 2060 2065 2071 2076 2082 2088 2093 2099

ALGOL-M

BEGIN

COMMENT
  FIND ISO CALENDAR YEARS HAVING 53 WEEKS. THE SIMPLEST
  TEST IS THAT A GIVEN YEAR WILL BE "LONG" IF EITHER THE
  FIRST OR LAST DAY IS A THURSDAY;

% CALCULATE P MOD Q %
INTEGER FUNCTION MOD(P, Q);
INTEGER P, Q;
BEGIN
   MOD := P - Q * (P / Q);
END;

COMMENT
  RETURN DAY OF WEEK (SUN=0, MON=1, ETC.) FOR A GIVEN
  GREGORIAN CALENDAR DATE USING ZELLER'S CONGRUENCE;
INTEGER FUNCTION DAYOFWEEK(MO, DA, YR);
INTEGER MO, DA, YR;
BEGIN
  INTEGER Y, C, Z;
  IF MO < 3 THEN
    BEGIN
      MO := MO + 10;
      YR := YR - 1;
    END
  ELSE MO := MO - 2;
  Y := MOD(YR, 100);
  C := YR / 100;
  Z := (26 * MO - 2) / 10;
  Z := Z + DA + Y + (Y / 4) + (C /4) - 2 * C + 777;
  DAYOFWEEK := MOD(Z, 7);
END;

% RETURN 1 IF YEAR IS LONG, OTHERWISE 0 %
INTEGER FUNCTION ISLONGYEAR(YR);
INTEGER YR;
BEGIN
  INTEGER THURSDAY;
  THURSDAY := 4;
  IF (DAYOFWEEK(1,1,YR) = THURSDAY) OR 
     (DAYOFWEEK(12,31,YR) = THURSDAY) THEN
       ISLONGYEAR := 1
  ELSE
       ISLONGYEAR := 0;
END;
   
% MAIN PROGRAM STARTS HERE %
INTEGER YEAR;
WRITE("ISO YEARS THAT WILL BE LONG IN THIS CENTURY:");
WRITE("");
FOR YEAR := 2000 STEP 1 UNTIL 2099 DO
  BEGIN
    IF ISLONGYEAR(YEAR) = 1 THEN WRITEON(YEAR);
  END;

END
Output:
ISO YEARS THAT WILL BE LONG IN THIS CENTURY:
  2004  2009  2015  2020  2026  2032  2037  2043  2048  2054  2060  2065  2071 2076
  2082  2088  2093  2099

ALGOL W

Uses the Day_of_week procedure from the Day_of_the_week task.

begin % find "long years" - years which have 53 weeks %
      % this is equivalent to finding years where     %
      % 1st Jan or 31st Dec are Thursdays             %
    % finds the day of the week - Sunday = 1          %
    integer procedure Day_of_week ( integer value d, m, y );
        begin
            integer j, k, mm, yy;
            mm := m;
            yy := y;
            if mm <= 2 then begin
                mm := mm + 12;
                yy := yy - 1;
            end if_m_le_2;
            j := yy div 100;
            k := yy rem 100;
            (d + ( ( mm + 1 ) * 26 ) div 10 + k + k div 4 + j div 4 + 5 * j ) rem 7
        end Day_of_week;
    % returns true if year is a long year, false otherwise %
    logical procedure isLongYear ( integer value year );
        Day_of_week( 1, 1, year ) = 5 or Day_of_week( 31, 12, year ) = 5;
    % show long years from 2000-2099 %
    write( "long years 2000-2099:" );
    for year := 2000 until 2099 do begin
        if isLongYear( year ) then writeon( I_W := 5, S_W := 0, year )
    end for_year
end.
Output:
long years 2000-2099: 2004 2009 2015 2020 2026 2032 2037 2043 2048 2054 2060 2065 2071 2076 2082 2088 2093 2099

Amazing Hopper

Task solves with Amazing Hopper flavour Basico:

#include <basico.h>

#proto esañolargo(_X_)

algoritmo

   año=1800, c=5
   
   imprimir ("Long (53 week) years between 1800 and 2100:\n\n" )
   
   iterar grupo ( ++año, #( año<=2100 ), \
       cuando ( #( es año largo( año )==4 || es año largo( año-1 )==3 ) ){ \
           imprimir ( año, " ", solo si( #( c==0 ) , NL; c=6 ), --c ) } )
        
terminar

subrutinas

es año largo (y)
retornar ' #( (y + floor(y / 4) - floor(y / 100) + floor(y / 400)) % 7 ) '
Output:
Long (53 week) years between 1800 and 2100:

1801 1807 1812 1818 1824 1829 
1835 1840 1846 1852 1857 1863 
1868 1874 1880 1885 1891 1896 
1903 1908 1914 1920 1925 1931 
1936 1942 1948 1953 1959 1964 
1970 1976 1981 1987 1992 1998 
2004 2009 2015 2020 2026 2032 
2037 2043 2048 2054 2060 2065 
2071 2076 2082 2088 2093 2099

APL

dec31weekday  {7|+⌊(÷4)+⌊(÷400)-⌊÷100}
isolongyear  {(4 = dec31weekday )  3 = dec31weekday  - 1}
Output:
      {⍵/⍨isolongyear ⍵}1800+⍳300
1801 1807 1812 1818 1824 1829 1835 1840 1846 1852 1857 1863 1868 1874 1880 1885 
      1891 1896 1903 1908 1914 1920 1925 1931 1936 1942 1948 1953 1959 1964
      1970 1976 1981 1987 1992 1998 2004 2009 2015 2020 2026 2032 2037 2043
      2048 2054 2060 2065 2071 2076 2082 2088 2093 2099

AppleScript

on isLongYear(y)
    -- ISO8601 weeks begin on Mondays and belong to the year in which they have the most days.
    -- A year which begins on a Thursday, or which begins on a Wednesday and is a leap year,
    -- has majority stakes in the weeks it overlaps at *both* ends and so has 53 weeks instead of 52.
    -- Leap years divisible by 400 begin on Saturdays and so don't so need to be considered in the leap year check.
    
    tell (current date) to set {Jan1, its day, its month, its year} to {it, 1, January, y}
    set startWeekday to Jan1's weekday
    
    return ((startWeekday is Thursday) or ((startWeekday is Wednesday) and (y mod 4 is 0) and (y mod 100 > 0)))
end isLongYear

set longYears to {}
repeat with y from 2001 to 2100
    if (isLongYear(y)) then set end of longYears to y
end repeat

return longYears
Output:
{2004, 2009, 2015, 2020, 2026, 2032, 2037, 2043, 2048, 2054, 2060, 2065, 2071, 2076, 2082, 2088, 2093, 2099}

On the other hand, since the cycle repeats every 400 years, it's possible to cheat with a precalculated look-up list:

on isLongYear(y)
    return (y mod 400 is in {4, 9, 15, 20, 26, 32, 37, 43, 48, 54, 60, 65, 71, 76, 82, 88, 93, 99, 105, 111, 116, 122, 128, 133, 139, 144, 150, 156, 161, 167, 172, 178, 184, 189, 195, 201, 207, 212, 218, 224, 229, 235, 240, 246, 252, 257, 263, 268, 274, 280, 285, 291, 296, 303, 308, 314, 320, 325, 331, 336, 342, 348, 353, 359, 364, 370, 376, 381, 387, 392, 398})
end isLongYear

set longYears to {}
repeat with y from 2001 to 2100
    if (isLongYear(y)) then set end of longYears to y
end repeat

return longYears

Arturo

Translation of: Nim
longYear?: function [year][
    date: to :date .format: "dd/MM/yyyy" ~"01/01/|year|"

    or? date\Day = "Thursday" 
        and? leap? year
             date\Day = "Wednesday"
]

print "Years with 53 weeks between 2000 and 2100:"
print select 2000..2100 => longYear?
Output:
Years with 53 weeks between 2000 and 2100:
2004 2009 2015 2020 2026 2032 2037 2043 2048 2054 2060 2065 2071 2076 2082 2088 2093 2099 

AutoHotkey

Long_year(y) {
	A := Mod(y + floor(y/4) - floor(y/100) + floor(y/400), 7)
	y--, B := Mod(y + floor(y/4) - floor(y/100) + floor(y/400), 7)
	return A=4 || B=3
}
Examples:
loop, 100{
	y := 1999+A_Index
	res .= Long_year(y) ? Y " ": ""
}
MsgBox % "Long Years 2000-2100 : " res
return
Output:
Long Years 2000-2100 : 2004 2009 2015 2020 2026 2032 2037 2043 2048 2054 2060 2065 2071 2076 2082 2088 2093 2099 

AWK

# syntax: GAWK -f LONG_YEAR.AWK
BEGIN {
    for (cc=19; cc<=21; cc++) {
      printf("%2d00-%2d99: ",cc,cc)
      for (yy=0; yy<=99; yy++) {
        ccyy = sprintf("%02d%02d",cc,yy)
        if (is_long_year(ccyy)) {
          printf("%4d ",ccyy)
        }
      }
      printf("\n")
    }
#
    printf("\n%4d-%4d: ",by=1970,ey=2037)
    for (y=by; y<=ey; y++) {
      if (strftime("%V",mktime(sprintf("%d 12 28 0 0 0",y))) == 53) {
        printf("%4d ",y)
      }
    }
    printf("\n")
    exit(0)
}
function is_long_year(year,  i) {
    for (i=0; i<=1; i++) {
      year -= i
      if ((year + int(year/4) - int(year/100) + int(year/400)) % 7 == 4-i) {
        return(1)
      }
    }
    return(0)
}
Output:
1900-1999: 1903 1908 1914 1920 1925 1931 1936 1942 1948 1953 1959 1964 1970 1976 1981 1987 1992 1998
2000-2099: 2004 2009 2015 2020 2026 2032 2037 2043 2048 2054 2060 2065 2071 2076 2082 2088 2093 2099
2100-2199: 2105 2111 2116 2122 2128 2133 2139 2144 2150 2156 2161 2167 2172 2178 2184 2189 2195

1970-2037: 1970 1976 1981 1987 1992 1998 2004 2009 2015 2020 2026 2032 2037


BASIC

Applesoft BASIC

Translation of: Commodore BASIC
 10  DEF  FN M7(N) = N - 7 *  INT (N / 7)
 20  DEF  FN WD(Y) =  FN M7(Y +  INT (Y / 4) -  INT (Y / 100) +  INT (Y / 400))
 30  DEF  FN LY(Y) = (4 =  FN WD(Y)) OR (3 =  FN WD(Y - 1))
 40  HOME : INVERSE : PRINT "****     LIST OF ISO LONG YEARS     ****": NORMAL 
 50  INPUT "START YEAR? ";S
 60  INPUT "END YEAR? ";E
 70  PRINT : FOR Y = S TO E
 80  IF  FN LY(Y) THEN  PRINT S$Y;:S$ = " "
 90  NEXT Y

ASIC

Translation of: Commodore BASIC
REM Long year
CLS
PRINT "****     List of ISO long years     ****"
PRINT "Start year";
INPUT S
PRINT "End year";
INPUT E
PRINT
FOR Y = S TO E
  GOSUB CALCLY:
  IF LY <> 0 THEN
    PRINT Y;
  ENDIF
NEXT Y
PRINT
END

CALCLY:
  REM Nonzero if Y is long
  LY = 0
  AY = Y
  GOSUB CALCWD:
  IF WD = 4 THEN
    LY = -1
  ENDIF
  AY = Y - 1
  GOSUB CALCWD:
  IF WD = 3 THEN
    LY = -1
  ENDIF
RETURN

CALCWD:
  REM Weekday of AY-12-31, 0 = Sunday
  WD = AY
  TMP = AY / 4
  WD = WD + TMP
  TMP = AY / 100
  WD = WD - TMP
  TMP = AY / 400
  WD = WD + TMP
  WD = WD MOD 7
RETURN
Output:
****     List of ISO long years     ****
Start year?1995
End year?2045

  1998  2004  2009  2015  2020  2026  2032  2037  2043

BASIC256

function p(y)
	return (y + int(y/4) - int(y/100) + int(y/400)) mod 7
end function

function isLongYear(y)
	return (p(y) = 4) or (p(y - 1) = 3)
end function

for y = 2000 to 2100
	if isLongYear(y) then print y
next y
end
Output:
2004
2009
2015
2020
2026
2032
2037
2043
2048
2054
2060
2065
2071
2076
2082
2088
2093
2099

BBC BASIC

      INSTALL @lib$ + "DATELIB"

      REM The function as per specification.
      DEF FNLongYear(year%)=FN_dow(FN_mjd(1, 1, year%)) == 4 OR FN_dow(FN_mjd(31, 12, year%)) == 4

      REM Demonstrating its use.
      PROCPrintLongYearsInCentury(20)
      PROCPrintLongYearsInCentury(21)
      PROCPrintLongYearsInCentury(22)
      END

      DEF PROCPrintLongYearsInCentury(century%)
      LOCAL year%, start%
      start%=century% * 100 - 100
      PRINT "The long years between ";start% " and ";start% + 100 " are ";
      FOR year%=start% TO start% + 99
        IF FNLongYear(year%) PRINT STR$year% + " ";
      NEXT
      PRINT
      ENDPROC
Output:
The long years between 1900 and 2000 are 1903 1908 1914 1920 1925 1931 1936 1942 1948 1953 1959 1964 1970 1976 1981 1987 1992 1998
The long years between 2000 and 2100 are 2004 2009 2015 2020 2026 2032 2037 2043 2048 2054 2060 2065 2071 2076 2082 2088 2093 2099
The long years between 2100 and 2200 are 2105 2111 2116 2122 2128 2133 2139 2144 2150 2156 2161 2167 2172 2178 2184 2189 2195

Chipmunk Basic

Works with: Chipmunk Basic version 3.6.4
Translation of: Commodore BASIC
10 cls
20 rem WD(Y) = WEEKDAY OF Y-12-31, 0 = SUNDAY
30 def fnwd(Y) = (Y + INT(Y / 4) - INT(Y / 100) + INT(Y / 400)) mod 7
40 rem LY(Y) = NONZERO IF Y IS LONG
50 def fnly(Y) = (4 = FNWD(Y)) OR (3 = FNWD(Y-1))
60 print "****     LIST OF ISO LONG YEARS     ****"
70 input "START YEAR? ",s
80 input "END YEAR? ",e
90 print
100 for y = s to e
110  if fn ly(y) then print y,
120 next y
130 print
140 end
Output:
Similar as Commodore BASIC entry.

Commodore BASIC

100 REM M7(N) = N MOD 7
110 DEF FNM7(N) = N - 7*INT(N / 7)
120 :
130 REM WD(Y) = WEEKDAY OF Y-12-31, 0 = SUNDAY
140 DEF FNWD(Y) = FNM7(Y + INT(Y / 4) - INT(Y / 100) + INT(Y / 400))
150 :
160 REM LY(Y) = NONZERO IF Y IS LONG
170 DEF FNLY(Y) = (4 = FNWD(Y)) OR (3 = FNWD(Y-1))
180 :
190 PRINT CHR$(147); CHR$(18); "****     LIST OF ISO LONG YEARS     ****"
200 INPUT "START YEAR"; S
210 INPUT "END YEAR"; E
220 PRINT
230 :
240 FOR Y = S TO E
250 : IF FNLY(Y) THEN PRINT Y,
260 NEXT Y
270 PRINT
Output:
****     LIST OF ISO LONG YEARS     ****

START YEAR? 1995
END YEAR? 2045

 1998      2004      2009      2015
 2020      2026      2032      2037
 2043

READY.

FreeBASIC

function p(y as unsigned integer) as unsigned integer
    return ( y + int(y/4) - int(y/100) + int(y/400) ) mod 7
end function

function islongyear( y as uinteger ) as boolean
    if p(y) = 4 then return true
    if p(y-1) = 3 then return true
    return false
end function

print islongyear(1998)
print islongyear(2020)
print islongyear(2021)
Output:
true
true
false

Gambas

Translation of: BASIC256
Public Sub Main() 
  
  For y As Integer = 2000 To 2100 
    If isLongYear(y) Then Print y, 
  Next
  
End 

Function p(y As Integer) As Integer 
  
  Return (y + (y \ 4) - (y \ 100) + (y \ 400)) Mod 7 
  
End Function 

Function isLongYear(y As Integer) As Boolean 
  
  If p(y) = 4 Then Return True 
  If p(y - 1) = 3 Then Return True 
  Return False 
  
End Function
Output:
Same as BASIC256 entry.

GW-BASIC

10 INPUT "Enter a year: ", Y
20 X = Y
30 GOSUB 100
40 IF P = 4 THEN L = 1
50 X = Y - 1
60 GOSUB 100
70 IF P = 3 THEN L = 1
80 IF L = 1 THEN PRINT Y; " is a long year." ELSE PRINT Y;" is not a long year."
90 END
100 P = X + INT(X/4) - INT(X/100) + INT(X/400)
110 P = P MOD 7
120 RETURN

IS-BASIC

100 PROGRAM "Longyear.bas"
110 DEF RD(Y)=Y*365+INT(Y/4)-INT(Y/100)+INT(Y/400)
120 DEF LONGYEAR(Y)=(4=MOD(RD(Y),7)) OR(4=MOD((RD(Y-1)+1),7))
130 INPUT PROMPT "Start year: ":S
140 INPUT PROMPT "End year:   ":E
150 FOR Y=S TO E
160   IF LONGYEAR(Y) THEN PRINT Y,
170 NEXT
180 PRINT

MSX Basic

Translation of: Commodore BASIC
10 CLS
20 REM WD(Y) = WEEKDAY OF Y-12-31, 0 = SUNDAY
30 DEF FNWD(Y) = (Y + INT(Y/4) - INT(Y/100) + INT(Y/400)) MOD 7
40 REM LY(Y) = NONZERO IF Y IS LONG
50 DEF FNLY(Y) = (4 = FNWD(Y)) OR (3 = FNWD(Y-1))
60 PRINT "***    LIST OF ISO LONG YEARS    ***"
70 INPUT "START YEAR ";S
80 INPUT "  END YEAR ";E
90 PRINT
100 FOR Y = S TO E
110  IF FNLY(Y) THEN PRINT Y,
120 NEXT Y
130 PRINT
140 END
Output:
Similar as Commodore BASIC entry.

Nascom BASIC

Translation of: Commodore BASIC
Works with: Nascom ROM BASIC version 4.7
10 REM Long year
20 REM FNM7(N)=MOD(N,7)
30 DEF FNM7(N)=N-7*INT(N/7)
40 REM FNWD(Y)=Weekday of Y-12-31, 0 Sunday
50 DEF FND(Y)=Y+INT(Y/4)-INT(Y/100)+INT(Y/400)
60 DEF FNWD(Y)=FNM7(FND(Y))
70 REM FNLY(Y)=Nonzero if Y is long
80 DEF FNLY(Y)=(4=FNWD(Y))OR(3=FNWD(Y-1))
90 CLS
100 PRINT "****     ";
110 PRINT "List of ISO long years";
120 PRINT "     ****"
130 INPUT "Start year";S
140 INPUT "End year";E
150 PRINT
160 FOR Y=S TO E
170 IF FNLY(Y) THEN PRINT Y;
180 NEXT Y
190 PRINT
200 END
Output:
****     List of ISO long years     ****
Start year? 1995
End year? 2045

 1998  2004  2009  2015  2020  2026  2032  2037  2043

Palo Alto Tiny BASIC

Translation of: Commodore BASIC
10 REM LONG YEAR
20 PRINT "*** LIST OF ISO LONG YEARS ***"
30 INPUT "START YEAR"B
40 INPUT "END YEAR"E
50 FOR Y=B TO E
60 GOSUB 200
70 IF L#0 PRINT Y," ",
80 NEXT Y
90 PRINT
100 STOP
190 REM L NONZERO IF Y IS LONG
200 LET L=0,J=Y
210 GOSUB 400
220 IF W=4 LET L=1
230 LET J=Y-1
240 GOSUB 400
250 IF W=3 LET L=1
260 RETURN
370 REM CALCULATE DAY OF WEEK W GIVEN
380 REM OF J-12-31, GIVEN YEAR J
390 REM SUNDAY = 0, SATURDAY = 6
400 LET W=J+J/4-J/100+J/400
410 LET W=W-(W/7)*7
420 RETURN
Output:
*** LIST OF ISO LONG YEARS ***
START YEAR:1995
END YEAR:2045
   1998    2004    2009    2015    2020    2026    2032    2037    2043

PureBasic

Translation of: BASIC256
Procedure.b p(y)
  ProcedureReturn (y + Int(y/4) - Int(y/100) + Int(y/400)) % 7
EndProcedure

Procedure.b isLongYear(y)
  ProcedureReturn Bool((p(y) = 4) Or (p(y - 1) = 3))
EndProcedure

If OpenConsole()
  For y = 2000 To 2100
    If isLongYear(y)
      PrintN(Str(y))
    EndIf
  Next y
  
  Print(""): Input()
  CloseConsole()
EndIf
Output:
Same as BASIC256 entry.

QuickBASIC

Works with: QB version 4.x
Works with: PDS version 7.x
Works with: QBasic version 1.x
Works with: VB-DOS version 1.0

Translated from Delphi

DEFINT A-Z

DECLARE FUNCTION p% (Yr AS INTEGER)
DECLARE FUNCTION LongYear% (Yr AS INTEGER)

DIM iYi, iYf, i

CLS
PRINT "This program calculates which are 53-week years in a range."
PRINT
INPUT "Initial year"; iYi
INPUT "Final year (could be the same)"; iYf
IF iYf >= iYi THEN
  FOR i = iYi TO iYf
    IF LongYear(i) THEN
      PRINT i; " ";
    END IF
  NEXT i
END IF
PRINT
PRINT
PRINT "End of program."
END

FUNCTION LongYear% (Yr AS INTEGER)
  LongYear% = (p%(Yr) = 4) OR (p%(Yr - 1) = 3)
END FUNCTION

FUNCTION p% (Yr AS INTEGER)
  p% = (Yr + INT(Yr / 4) - INT(Yr / 100) + INT(Yr / 400)) MOD 7
END FUNCTION
Output:
This program calculates which are 53-week years in a range.

Initial year? 1900
Final year (can be the same)? 1999
 1903   1908   1914   1920   1925   1931   1936   1942   1948   1953   1959
 1964   1970   1976   1981   1987   1992   1998

End of program.

Run BASIC

Translation of: BASIC256
function p(y)
  p = (y + int(y/4) - int(y/100) + int(y/400)) mod 7
end function

function isLongYear(y)
  isLongYear = (p(y) = 4) or (p(y -1) = 3)
end function

for y = 2000 to 2100
  if isLongYear(y) then print y
next y
end
Output:
Same as BASIC256 entry.

S-BASIC

$lines

rem - compute p mod q
function mod(p, q = integer) = integer
end = p - q * (p/q)

comment
  return day of week (Sun = 0, Mon = 1, etc.) for a
  given Gregorian calendar date using Zeller's congruence
end
function dayofweek (mo, da, yr = integer) = integer
  var y, c, z = integer
  if mo < 3 then
    begin
      mo = mo + 10
      yr = yr - 1
    end
  else mo = mo - 2
  y = mod(yr,100)
  c = int(yr / 100)
  z = int((26 * mo - 2) / 10)
  z = z + da + y + int(y/4) + int(c/4) - 2 * c + 777
  z = mod(z,7)
end = z

comment
  The simplest of several possible tests is that
  any ISO year starting or ending on a
  Thursday is "long", i.e., spans 53 weeks
end
function islongyear(yr = integer) = integer
  var thursday, result = integer
  thursday = 4
  if (dayofweek(1,1,yr) = thursday) or \
     (dayofweek(12,31,yr) = thursday) then
       result = -1  rem "true"
  else
       result = 0   rem "false"
end = result

rem - main program begins here

var year = integer
print "ISO years that will be long in this century:"
for year = 2000 to 2099
  if islongyear(year) then print year;
next year

end
Output:
ISO years that will be long in this century:
 2004 2009 2015 2020 2026 2032 2037 2043 2048 2054 2060 2065 2071 2076 2082 2088
 2093 2099

Tiny BASIC

    PRINT "What year would you like?"
    INPUT Y
    LET X = Y
    GOSUB 100
    IF P = 4 THEN LET L = 1
    LET X = Y - 1
    GOSUB 100
    IF P = 3 THEN LET L = 1
    IF L = 1 THEN PRINT Y," is a long year."
    IF L = 0 THEN PRINT Y," is not a long year."
    END
100 LET P = X + X/4 - X/100 + X/400
110 IF P < 7 THEN RETURN
    LET P = P - 7
    GOTO 110
Output:
What year would you like?
2020
2020 is a long year.

What year would you like?
2021
2021 is not a long year.

True BASIC

Translation of: BASIC256
FUNCTION p(y) = REMAINDER((y + INT(y/4) - INT(y/100) + INT(y/400)), 7)

FUNCTION isLongYear(y)
    IF p(y) = 4 THEN
       LET isLongYear = 1
    ELSEIF p(y-1) = 3 THEN
       LET isLongYear = 1
    ELSE
       LET isLongYear = 0
    END IF
END FUNCTION

FOR y = 2000 TO 2100
    IF isLongYear(y) > 0 THEN PRINT y
NEXT y
END
Output:
Same as BASIC256 entry.

Visual Basic

Works with: Visual Basic version 5
Works with: Visual Basic version 6
Works with: VBA version Access 97
Works with: VBA version 6.5
Works with: VBA version 7.1
Option Explicit

Function IsLongYear(ByVal Year As Integer) As Boolean
  Select Case vbThursday
  Case VBA.DatePart("w", VBA.DateSerial(Year, 1, 1)), _
       VBA.DatePart("w", VBA.DateSerial(Year, 12, 31))
    IsLongYear = True
  End Select
End Function

Sub Main()
'test
Dim l As Long
  For l = 1990 To 2021
    Select Case l
    Case 1992, 1998, 2004, 2009, 2015, 2020
      Debug.Assert IsLongYear(l)
    Case Else
      Debug.Assert Not IsLongYear(l)
    End Select
  Next l
End Sub

Visual Basic for DOS

Translation of: Delphi
OPTION EXPLICIT

DECLARE FUNCTION p (Yr AS INTEGER) AS INTEGER
DECLARE FUNCTION LongYear (Yr AS INTEGER) AS INTEGER

DIM iYi AS INTEGER, iYf AS INTEGER, i AS INTEGER

CLS
PRINT "This program calculates which are 53-week years in a range."
PRINT
INPUT "Initial year"; iYi
INPUT "Final year (could be the same)"; iYf
IF iYf >= iYi THEN
  FOR i = iYi TO iYf
    IF LongYear(i) THEN
      PRINT i; " ";
    END IF
  NEXT i
END IF
PRINT
PRINT
PRINT "End of program."
END

FUNCTION p (Yr AS INTEGER) AS INTEGER
  p = (Yr + INT(Yr / 4) - INT(Yr / 100) + INT(Yr / 400)) MOD 7
END FUNCTION

FUNCTION LongYear (Yr AS INTEGER) AS INTEGER
  LongYear = (p(Yr) = 4) OR (p(Yr - 1) = 3)
END FUNCTION

XBasic

Works with: Windows XBasic
Translation of: BASIC256
PROGRAM  "LongYear"
VERSION  "0.0000"

DECLARE FUNCTION Entry ()
DECLARE FUNCTION p (y)
DECLARE FUNCTION isLongYear (y)

FUNCTION  Entry ()
  FOR y = 2000 TO 2100
    IF isLongYear(y) THEN PRINT y,
  NEXT y
END FUNCTION

FUNCTION p (y)
  RETURN (y + INT(y/4) - INT(y/100) + INT(y/400)) MOD 7
END FUNCTION

FUNCTION isLongYear (y)
  RETURN (p(y) = 4) OR (p(y - 1) = 3)
END FUNCTION
END PROGRAM
Output:
Same as BASIC256 entry.

Yabasic

Translation of: BASIC256
sub p(y)
	return mod((y + int(y/4) - int(y/100) + int(y/400)), 7)
end sub

sub isLongYear(y)
	return (p(y) = 4) or (p(y - 1) = 3)
end sub

for y = 2000 to 2100
	if isLongYear(y)  print y
next y
end
Output:
Same as BASIC256 entry.

BCPL

get "libhdr"

let p(y) = (y + y/4 - y/100 + y/400) rem 7
let longyear(y) = p(y)=4 | p(y-1)=3

let start() be 
    for y = 2000 to 2100
        if longyear(y) do writef("%N*N", y)
Output:
2004
2009
2015
2020
2026
2032
2037
2043
2048
2054
2060
2065
2071
2076
2082
2088
2093
2099

C#

using static System.Console;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;

public static class Program
{
    public static void Main()
    {
        WriteLine("Long years in the 21st century:");
        WriteLine(string.Join(" ", 2000.To(2100).Where(y => ISOWeek.GetWeeksInYear(y) == 53)));
    }
    
    public static IEnumerable<int> To(this int start, int end) {
        for (int i = start; i < end; i++) yield return i;
    }
    
}
Output:
Long years in the 21st century:
2004 2009 2015 2020 2026 2032 2037 2043 2048 2054 2060 2065 2071 2076 2082 2088 2093 2099

C

#include <stdio.h>
#include <math.h>

// https://webspace.science.uu.nl/~gent0113/calendar/isocalendar.htm

int p(int year) {
	return (int)((double)year + floor(year/4) - floor(year/100) + floor(year/400)) % 7;
}

int is_long_year(int year) {
	return p(year) == 4 || p(year - 1) == 3;
}

void print_long_years(int from, int to) {
	for (int year = from; year <= to; ++year) {
		if (is_long_year(year)) {
			printf("%d ", year);
		}
	}
}

int main() {

	printf("Long (53 week) years between 1800 and 2100\n\n");
	print_long_years(1800, 2100);
	printf("\n");
	return 0;
}
Output:
Long (53 week) years between 1800 and 2100

1801 1807 1812 1818 1824 1829 1835 1840 1846 1852 1857 1863 1868 1874 1880 1885 1891 1896 1903 1908 1914 1920 1925 1931 1936 1942 1948 1953 1959 1964 1970 1976 1981 1987 1992 1998 2004 2009 2015 2020 2026 2032 2037 2043 2048 2054 2060 2065 2071 2076 2082 2088 2093 2099 


C++

// Reference:
// https://en.wikipedia.org/wiki/ISO_week_date#Weeks_per_year

#include <iostream>

inline int p(int year) {
    return (year + (year/4) - (year/100) + (year/400)) % 7;
}

bool is_long_year(int year) {
    return p(year) == 4 || p(year - 1) == 3;
}

void print_long_years(int from, int to) {
    for (int year = from, count = 0; year <= to; ++year) {
        if (is_long_year(year)) {
            if (count > 0)
                std::cout << ((count % 10 == 0) ? '\n' : ' ');
            std::cout << year;
            ++count;
        }
    }
}

int main() {
    std::cout << "Long years between 1800 and 2100:\n";
    print_long_years(1800, 2100);
    std::cout << '\n';
    return 0;
}
Output:
Long years between 1800 and 2100:
1801 1807 1812 1818 1824 1829 1835 1840 1846 1852
1857 1863 1868 1874 1880 1885 1891 1896 1903 1908
1914 1920 1925 1931 1936 1942 1948 1953 1959 1964
1970 1976 1981 1987 1992 1998 2004 2009 2015 2020
2026 2032 2037 2043 2048 2054 2060 2065 2071 2076
2082 2088 2093 2099

Clojure

(defn long-year? [year] 
  (-> (java.time.LocalDate/of year 12 28) 
      (.get (.weekOfYear (java.time.temporal.WeekFields/ISO))) 
      (= 53)))

(filter long-year? (range 2000 2100))
Output:
(2004 2009 2015 2020 2026 2032 2037 2043 2048 2054 2060 2065 2071 2076 2082 2088 2093 2099)

CLU

% We can't hide one procedure inside another, but
% we can hide the helper `p' in a cluster

longyear = cluster is test
    rep = null
    
    p = proc (n: int) returns (int)
        return ((n + n/4 - n/100 + n/400) // 7)
    end p

    test = proc (y: int) returns (bool)
        return (p(y)=4 | p(y-1)=3)
    end test
end longyear

start_up = proc ()
    po: stream := stream$primary_output()
    
    for i: int in int$from_to(2000, 2100) do
        if longyear$test(i) then
            stream$putl(po, int$unparse(i))
        end
    end
end start_up
Output:
2004
2009
2015
2020
2026
2032
2037
2043
2048
2054
2060
2065
2071
2076
2082
2088
2093
2099


Common Lisp

(defun december-31-weekday (year) 
   (mod (+ year (floor year 4) (- (floor year 100)) (floor year 400)) 7))

(defun iso-long-year-p (year) 
    (or (= 4 (december-31-weekday year)) (= 3 (december-31-weekday (1- year)))))

(format t "Long years between 1800 and 2100:~&~a~%"
    (loop for y from 1800 to 2100 if (iso-long-year-p y) collect y))
Output:
Long years between 1800 and 2100:
(1801 1807 1812 1818 1824 1829 1835 1840 1846 1852 1857 1863 1868 1874 1880
 1885 1891 1896 1903 1908 1914 1920 1925 1931 1936 1942 1948 1953 1959 1964
 1970 1976 1981 1987 1992 1998 2004 2009 2015 2020 2026 2032 2037 2043 2048
 2054 2060 2065 2071 2076 2082 2088 2093 2099)

Cowgol

include "cowgol.coh";

sub longyear(year: uint16): (r: uint8) is
    sub p(y: uint16): (d: uint8) is
        d := ((y + y/4 - y/100 + y/400) % 7) as uint8;
    end sub;

    r := 0;
    if p(year) == 4 or p(year-1) == 3 then
        r := 1;
    end if;
end sub;

var year: uint16 := 2000;
while year <= 2100 loop
    if longyear(year) != 0 then
        print_i16(year);
        print_nl();
    end if;
    year := year + 1;
end loop;
Output:
2004
2009
2015
2020
2026
2032
2037
2043
2048
2054
2060
2065
2071
2076
2082
2088
2093
2099

Dc

Translation of: Tcl
Works with: GNU dc version 1.3.95
[0q]s0
[1q]s1
[1r- r 1r- * 1r-]sO                             # O = logical OR
##.............................................................................
#     C: for( initcode ; condcode ; incrcode ) {body}
# .[q]           [1]        [2]        [3]       [4]
# #           [initcode] [condcode] [incrcode] [body] (for)
[ [q]S. 4:.3:.2:.x [2;.x 0=. 4;.x 3;.x 0;.x]d0:.x
    Os.L.o
]sF                                             # F = for
##.............................................................................
#                           [1]         [0]
# (.)       [cond_code] [then_code] [else_code] (if_CTE)
[ []S. 0:. 1:. x [0=0 1]x ;. s.L. x]sI          # I = if
##-----------------------------------------------------------------------------
[S. l. l.4/+ l.100/- l.400/+ 7% s.L.]sp         # p
##.............................................................................
[S. [l.    lpx 4=1 0]x
    [l. 1- lpx 3=1 0]x lOx
    s.L.
]si                                             # i = is_long_year
##.............................................................................
[
    # f = from
    # t = to
    # y = year
    # c = count
    st sf                       # fetch args from stack
    [lfsy 0sc]
        [ly lt <0 1]            # cond
        [ly 1+ sy]              # incr y
    [
        [ly lix]                # is_long_year(y)
        [
            [lc 0 <1 0]         # 0<c
            [
                [ lc 10% 0=1 0]         # (c % 10) == 0
                [ AP ]
                [ [ ]P ]
                lIx             # if
            ]
            []
            lIx         # if
            ly n
            lc 1+ sc
        ]
        []
        lIx             # if
    ] lFx       # for
]sD                     # D = doit = print_long_years
##.............................................................................
 
[Long years between 1800 and 2100:]P AP
1800 2100 lDx
AP
Output:
Long years between 1800 and 2100:
1801 1807 1812 1818 1824 1829 1835 1840 1846 1852
1857 1863 1868 1874 1880 1885 1891 1896 1903 1908
1914 1920 1925 1931 1936 1942 1948 1953 1959 1964
1970 1976 1981 1987 1992 1998 2004 2009 2015 2020
2026 2032 2037 2043 2048 2054 2060 2065 2071 2076
2082 2088 2093 2099

Delphi

Note: The Library System.DateUtils implement a WeeksInYear,but not working, return 52 always.

Translation of: C++
program Long_year;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

function p(const Year: Integer): Integer;
begin
  Result := (Year + (Year div 4) - (Year div 100) + (Year div 400)) mod 7;
end;

function IsLongYear(const Year: Integer): Boolean;
begin
  Result := (p(Year) = 4) or (p(Year - 1) = 3);
end;

procedure PrintLongYears(const StartYear: Integer; const EndYear: Integer);
var
  Year, Count: Integer;
begin
  Count := 0;
  for Year := 1800 to 2100 do
    if IsLongYear(Year) then
    begin
      if Count mod 10 = 0 then
        Writeln;
      Write(Year, ' ');
      inc(Count);
    end;
end;

var
  Year: Integer;

begin
  Writeln('Long years between 1800 and 2100:');
  PrintLongYears(1800, 2100);
  Readln;
end.

Draco

proc p(word y) word:
    (y + y/4 - y/100 + y/400) % 7
corp

proc longyear(word y) bool:
    p(y) = 4 or p(y-1) = 3
corp

proc main() void:
    word y;
    for y from 2000 upto 2100 do
        if longyear(y) then writeln(y) fi
    od
corp
Output:
2004
2009
2015
2020
2026
2032
2037
2043
2048
2054
2060
2065
2071
2076
2082
2088
2093
2099

EasyLang

func p y .
   return (y + y div 4 - y div 100 + y div 400) mod 7
.
func longyear y .
   return if p y = 4 or p (y - 1) = 3
.
for y = 2000 to 2100
   if longyear y = 1
      write y & " "
   .
.
Output:
2004 2009 2015 2020 2026 2032 2037 2043 2048 2054 2060 2065 2071 2076 2082 2088 2093 2099 

Elixir

defmodule ISO do
  def long_year?(y) do
    {:ok, jan1} = Date.new(y,1,1)
    {:ok, dec31} = Date.new(y,12,31)
    Date.day_of_week(jan1) == 4 or Date.day_of_week(dec31) == 4
  end
end

IO.inspect(Enum.filter(1990..2050, &ISO.long_year?/1))
Output:
[1992, 1998, 2004, 2009, 2015, 2020, 2026, 2032, 2037, 2043, 2048]

Factor

Works with: Factor version 0.99 2019-10-06
USING: calendar formatting io kernel math.ranges sequences ;

: long-year? ( n -- ? ) 12 28 <date> week-number 53 = ;

"Year  Long?\n-----------" print 1990 2021 [a,b]
[ dup long-year? "yes" "no" ? "%d  %s\n" printf ] each
Output:
Year  Long?
-----------
1990  no
1991  no
1992  yes
1993  no
1994  no
1995  no
1996  no
1997  no
1998  yes
1999  no
2000  no
2001  no
2002  no
2003  no
2004  yes
2005  no
2006  no
2007  no
2008  no
2009  yes
2010  no
2011  no
2012  no
2013  no
2014  no
2015  yes
2016  no
2017  no
2018  no
2019  no
2020  yes
2021  no

Forth

: dec31wd ( year -- weekday ) dup dup 4 / swap dup 100 / swap 400 / swap - + + 7 mod ;
: long? ( year -- flag ) dup dec31wd 4 = if drop 1 else 1 - dec31wd 3 = if 1 else 0 then then ;
: demo ( startyear endyear -- ) cr swap do i long? if i . then loop cr ;
Output:
1995 2045 demo
1998 2004 2009 2015 2020 2026 2032 2037 2043
ok

Fortran

program longyear
    use iso_fortran_env, only: output_unit, input_unit
    implicit none

    integer             :: start, ende, i, counter
    integer, parameter  :: line_break=10

    write(output_unit,*) "Enter beginning of interval"
    read(input_unit,*) start
    write(output_unit,*) "Enter end of interval"
    read(input_unit,*) ende

    if (start>=ende) error stop "Last year must be after first year!"

    counter = 0
    do i = start, ende
        if (is_long_year(i)) then
            write(output_unit,'(I0,x)', advance="no") i
            counter = counter + 1
            if (modulo(counter,line_break) == 0) write(output_unit,*)
        end if
    end do
contains
    pure function p(year)
        integer, intent(in) :: year
        integer             :: p

        p = modulo(year + year/4 - year/100 + year/400, 7)
    end function p

    pure function is_long_year(year)
        integer, intent(in) :: year
        logical             :: is_long_year

        is_long_year = p(year) == 4 .or. p(year-1) == 3
    end function is_long_year
end program longyear
Output:
 Enter beginning of interval
1800
 Enter end of interval
2100
1801 1807 1812 1818 1824 1829 1835 1840 1846 1852 
1857 1863 1868 1874 1880 1885 1891 1896 1903 1908 
1914 1920 1925 1931 1936 1942 1948 1953 1959 1964 
1970 1976 1981 1987 1992 1998 2004 2009 2015 2020 
2026 2032 2037 2043 2048 2054 2060 2065 2071 2076 
2082 2088 2093 2099 %                                      

Go

package main

import (
    "fmt"
    "time"
)

func main() {
    centuries := []string{"20th", "21st", "22nd"}
    starts := []int{1900, 2000, 2100} 
    for i := 0; i < len(centuries); i++ {
        var longYears []int
        fmt.Printf("\nLong years in the %s century:\n", centuries[i])
        for j := starts[i]; j < starts[i] + 100; j++ {
            t := time.Date(j, time.December, 28, 0, 0, 0, 0, time.UTC)
            if _, week := t.ISOWeek(); week == 53 {
                longYears = append(longYears, j)
            }
        }
        fmt.Println(longYears)
    }
}
Output:
Long years in the 20th century:
[1903 1908 1914 1920 1925 1931 1936 1942 1948 1953 1959 1964 1970 1976 1981 1987 1992 1998]

Long years in the 21st century:
[2004 2009 2015 2020 2026 2032 2037 2043 2048 2054 2060 2065 2071 2076 2082 2088 2093 2099]

Long years in the 22nd century:
[2105 2111 2116 2122 2128 2133 2139 2144 2150 2156 2161 2167 2172 2178 2184 2189 2195]

Haskell

import Data.Time.Calendar (fromGregorian)
import Data.Time.Calendar.WeekDate (toWeekDate)

longYear :: Integer -> Bool
longYear y =
  let (_, w, _) = toWeekDate $ fromGregorian y 12 28
   in 52 < w

main :: IO ()
main = mapM_ print $ filter longYear [2000 .. 2100]
Output:
2004
2009
2015
2020
2026
2032
2037
2043
2048
2054
2060
2065
2071
2076
2082
2088
2093
2099

J

Translation of: C
   p   =:  1 4 _100 400&(7 | [: <. +/ @: %~)"1 0 
   ily =:  (4=p) +. 3=p@:<:
   ply =:  (#~ ily)@:([ + 1+i.@:-~)
Output:
   ply/ 1800 2100
1801 1807 1812 1818 1823 1829 1835 1840 1846 1852 1857 1863 1869 1874 1880 1885 1891 1897 1902 1908 1914 1919 1925 1930 1936 1942 1947 1953 1959 1964 1970 1976 1981 1987 1992 1998 2004 2009 2015 2021 2026 2032 2038 2043 2049 2054 2060 2066 2071 2077 2083 2...

Java

import java.time.LocalDate;
import java.time.temporal.WeekFields;

public class LongYear {

    public static void main(String[] args) {
        System.out.printf("Long years this century:%n");
        for (int year = 2000 ; year < 2100 ; year++ ) {
            if ( longYear(year) ) {
                System.out.print(year + "  ");
            }
        }
    }
    
    private static boolean longYear(int year) {
        return LocalDate.of(year, 12, 28).get(WeekFields.ISO.weekOfYear()) == 53;
    }

}
Output:
Long years this century:
2004  2009  2015  2020  2026  2032  2037  2043  2048  2054  2060  2065  2071  2076  2082  2088  2093  2099  

JavaScript

Translation of: TypeScript
const isLongYear = (year) => {
  const jan1 = new Date(year, 0, 1);
  const dec31 = new Date(year, 11, 31);
  return (4 == jan1.getDay() || 4 == dec31.getDay())
}

for (let y = 1995; y <= 2045; y++) {
  if (isLongYear(y)) {
    console.log(y)
  }
}
Output:
1998
2004
2009
2015
2020
2026
2032
2037
2043

jq

Works with: jq

Works with gojq, the Go implementation of jq

Using Zeller's congruence

# Use Zeller's Congruence to determine the day of the week, given
# year, month and day as integers in the conventional way.
# Emit 0 for Saturday, 1 for Sunday, etc.
#
def day_of_week($year; $month; $day):
  if $month == 1 or $month == 2 then
    [$month + 12, $year - 1]
  else
    [$month, $year]
  end 
  | $day + (13*(.[0] + 1)/5|floor)
    +  (.[1]%100)       + ((.[1]%100)/4|floor)
    +  (.[1]/400|floor) - 2*(.[1]/100|floor) 
  | . % 7 ;

def has53weeks:
  day_of_week(.; 1; 1) == 5 or day_of_week(.; 12; 31) == 5;

# To display results neatly:
def nwise($n):
  def n: if length <= $n then . else .[0:$n] , (.[$n:] | n) end;
  n;

"Long years from 1900 to 2100 inclusive:",
([range(1900;2101) | select(has53weeks)] | nwise(10) | join(", "))
Output:
Long years from 1900 to 2100 inclusive:
1903, 1908, 1914, 1920, 1925, 1931, 1936, 1942, 1948, 1953
1959, 1964, 1970, 1976, 1981, 1987, 1992, 1998, 2004, 2009
2015, 2020, 2026, 2032, 2037, 2043, 2048, 2054, 2060, 2065
2071, 2076, 2082, 2088, 2093, 2099

Using mktime and gmtime

# Use jq's mktime and gmtime to produce the day of week,
# with 0 for Sunday, 1 for Monday, etc
# $year $month $day are conventional
def day_of_week_per_gmtime($year; $month; $day):
   [$year, $month - 1, $day, 0, 0, 1, 0, 0] | mktime | gmtime | .[-2];

# 4 corresponds to Thursday
def has53weeks:
  day_of_week_per_gmtime(.; 1; 1) == 4 or day_of_week(.; 12; 31) == 4;

def nwise($n):
  def n: if length <= $n then . else .[0:$n] , (.[$n:] | n) end;
  n;

"Long years from 1900 to 2100 inclusive:",
([range(1900;2101) | select(has53weeks)] | nwise(10) | join(", "))
Output:

As above.

Julia

using Dates

has53weeks(year) = week(Date(year, 12, 28)) == 53

println(" Year  53 weeks?\n----------------")
for year in 1990:2021
    println(year, "   ", has53weeks(year) ? "Yes" : "No")
end
Output:
 Year  53 weeks?
----------------
1990   No
1991   No
1992   Yes
1993   No
1994   No
1995   No
1996   No
1997   No
1998   Yes
1999   No
2000   No
2001   No
2002   No
2003   No
2004   Yes
2005   No
2006   No
2007   No
2008   No
2009   Yes
2010   No
2011   No
2012   No
2013   No
2014   No
2015   Yes
2016   No
2017   No
2018   No
2019   No
2020   Yes
2021   No

Kotlin

fun main() {
    val has53Weeks = { year: Int -> LocalDate.of(year, 12, 28).get(WeekFields.ISO.weekOfYear()) == 53 }
    println("Long years this century:")
    (2000..2100).filter(has53Weeks)
        .forEach { year -> print("$year ")}
}
Output:
Long years this century:
2004 2009 2015 2020 2026 2032 2037 2043 2048 2054 2060 2065 2071 2076 2082 2088 2093 2099 


Works with: UCB Logo
to div :x :y
  output int quotient :x :y
end

to dec31_weekday :year
   output remainder (sum :year div :year 4 div :year -100 div :year 400) 7
end

to iso_long_year? :year
   output or 4 = dec31_weekday :year 3 = dec31_weekday difference :year 1
end

for [y 1995 2045 1] [if iso_long_year? :y [print :y]]
Output:
1998
2004
2009
2015
2020
2026
2032
2037
2043

Lua

function isLongYear (y)
    local function p (y)
        local f = math.floor
        return (y + f(y/4) - f(y/100) + f(y/400)) % 7
    end
    return p(y) == 4 or p(y - 1) == 3
end

print("Long years in the 21st century:")
for year = 2001, 2100 do
    if isLongYear(year) then io.write(year .. " ") end
end
Output:
Long years in the 21st century:
2004 2009 2015 2020 2026 2032 2037 2043 2048 2054 2060 2065 2071 2076 2082 2088 2093 2099

Mathematica/Wolfram Language

firstyear = 2000;
lastyear = 2099;
years = Range[firstyear, lastyear];
firstday = Table[DayName[{years[[n]], 01, 01}], {n, Length[years]}];
lastday = Table[DayName[{years[[n]], 12, 31}], {n, Length[years]}];
Table[If[years[[n]] >= 1582, 
  If[firstday[[n]] == Thursday || lastday[[n]] == Thursday, 
   Style[years[[n]] " long year \n", Bold, Red] , 
   years[[n]] " short \n"], "error \n"], {n, Length[years]}]
Output:
{2000 short 
 , 2001 short 
 , 2002 short 
 , 2003 short 
 , 2004 long year 
 , 2005 short 
 , 2006 short 
 , 2007 short 
 , 2008 short 
 , 2009 long year 
 , 2010 short 
 , 2011 short 
 , 2012 short 
 , 2013 short 
 , 2014 short 
 , 2015 long year 
 , 2016 short 
 , 2017 short 
 , 2018 short 
 , 2019 short 
 , 2020 long year 
 , 2021 short 
 , 2022 short 
 , 2023 short 
 , 2024 short 
 , 2025 short 
 , 2026 long year 
 , 2027 short 
 , 2028 short 
 , 2029 short 
 , 2030 short 
 , 2031 short 
 , 2032 long year 
 , 2033 short 
 , 2034 short 
 , 2035 short 
 , 2036 short 
 , 2037 long year 
 , 2038 short 
 , 2039 short 
 , 2040 short 
 , 2041 short 
 , 2042 short 
 , 2043 long year 
 , 2044 short 
 , 2045 short 
 , 2046 short 
 , 2047 short 
 , 2048 long year 
 , 2049 short 
 , 2050 short 
 , 2051 short 
 , 2052 short 
 , 2053 short 
 , 2054 long year 
 , 2055 short 
 , 2056 short 
 , 2057 short 
 , 2058 short 
 , 2059 short 
 , 2060 long year 
 , 2061 short 
 , 2062 short 
 , 2063 short 
 , 2064 short 
 , 2065 long year 
 , 2066 short 
 , 2067 short 
 , 2068 short 
 , 2069 short 
 , 2070 short 
 , 2071 long year 
 , 2072 short 
 , 2073 short 
 , 2074 short 
 , 2075 short 
 , 2076 long year 
 , 2077 short 
 , 2078 short 
 , 2079 short 
 , 2080 short 
 , 2081 short 
 , 2082 long year 
 , 2083 short 
 , 2084 short 
 , 2085 short 
 , 2086 short 
 , 2087 short 
 , 2088 long year 
 , 2089 short 
 , 2090 short 
 , 2091 short 
 , 2092 short 
 , 2093 long year 
 , 2094 short 
 , 2095 short 
 , 2096 short 
 , 2097 short 
 , 2098 short 
 , 2099 long year 
 }

Modula-2

MODULE LongYear;
FROM InOut IMPORT WriteCard, WriteLn;

VAR year: CARDINAL;

PROCEDURE isLongYear(year: CARDINAL): BOOLEAN;
    PROCEDURE p(year: CARDINAL): CARDINAL;
    BEGIN
        RETURN (year + year DIV 4 - year DIV 100 + year DIV 400) MOD 7;
    END p;
BEGIN
    RETURN (p(year) = 4) OR (p(year-1) = 3);
END isLongYear;

BEGIN
    FOR year := 2000 TO 2100 DO
        IF isLongYear(year) THEN
            WriteCard(year, 4);
            WriteLn;
        END;
    END;
END LongYear.
Output:
2004
2009
2015
2020
2026
2032
2037
2043
2048
2054
2060
2065
2071
2076
2082
2088
2093
2099

Nim

import times

proc has53weeks(year: Positive): bool =
  let dt = initDateTime(monthday = 1, month = mJan, year = year, hour = 0, minute = 0, second= 0)
  result = dt.weekday == dThu or year.isLeapYear and dt.weekday == dWed

when isMainModule:
  echo "Years with 53 weeks between 2000 and 2100:"
  for year in 2000..2100:
    if year.has53weeks:
      echo year
Output:
Years with 53 weeks between 2000 and 2100:
2004
2009
2015
2020
2026
2032
2037
2043
2048
2054
2060
2065
2071
2076
2082
2088
2093
2099

МК-61/52

П0	ИП0	4	/	[x]	+	ИП0	1	ВП	2
/	[x]	-	ИП0	4	ВП	2	/	[x]	+
^	^	7	/	[x]	7	*	-	П1	4
-	x#0	40	ИП1	3	-	x#0	40	0	С/П
1	С/П
Output:
Result for 2020-2030 years: 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0.

Pascal

program long_year(input);
  var
    y: integer;

  function rd_dec31(year: integer): integer;
  begin
    { Rata Die of Dec 31, year }
    rd_dec31 := year * 365 + year div 4 - year div 100 + year div 400
  end;

  function rd_jan1(year: integer): integer;
  begin
    rd_jan1 := rd_dec31(year - 1) + 1
  end;

  function weekday(rd: integer): integer;
  begin
    weekday := rd mod 7;
  end;

  function long_year(year: integer): boolean;
  var
    jan1: integer;
    dec31: integer;
  begin
    jan1 := rd_jan1(year);
    dec31 := rd_dec31(year);
    long_year := (weekday(jan1) = 4) or (weekday(dec31) = 4)
  end;

  begin
    for y := 1990 to 2050 do
      if long_year(y) then
        writeln(y)
  end.
Output:
1993
1999
2004
2010
2016
2021
2027
2032
2038
2044
2049

Free Pascal

Using DateUtils and WeeksInYear to not reinvent this.

program Long_year;

uses
  SysUtils,
  DateUtils;

  procedure PrintLongYears(StartYear, EndYear: Uint32);
  var
    Year, Count: Uint32;
    DateSep: char;
  begin
    DateSep := FormatSettings.DateSeparator;
    Writeln('Long years between ', StartYear, ' and ', EndYear);
    Count := 0;
    for Year := StartYear to EndYear do
      if WeeksInYear(StrToDate('01' + DateSep + '01' + DateSep + IntToStr(Year))) = 53 then
      begin
        if Count mod 10 = 0 then
          Writeln;
        Write(Year, ' ');
        Inc(Count);
      end;
    if Count mod 10 <> 0 then
      Writeln;
    writeln('Found ', Count, ' long years between ', StartYear, ' and ', EndYear);
  end;

begin
  PrintLongYears(1800, 2100);
  {$IFDEF WINDOWS}
  Readln;
  {$ENDIF}
end.
Output:
Long years between 1800 and 2100
1801 1807 1812 1818 1824 1829 1835 1840 1846 1852
1857 1863 1868 1874 1880 1885 1891 1896 1903 1908
1914 1920 1925 1931 1936 1942 1948 1953 1959 1964
1970 1976 1981 1987 1992 1998 2004 2009 2015 2020
2026 2032 2037 2043 2048 2054 2060 2065 2071 2076
2082 2088 2093 2099
Found 54 long years between 1800 and 2100

Perl

use strict;
use warnings;
use DateTime;

for my $century (19 .. 21) {
  for my $year ($century*100 .. ++$century*100 - 1) {
    print "$year " if DateTime->new(year => $year, month => 12, day => 28)->week_number > 52
  }
  print "\n";
}
Output:
1903 1908 1914 1920 1925 1931 1936 1942 1948 1953 1959 1964 1970 1976 1981 1987 1992 1998
2004 2009 2015 2020 2026 2032 2037 2043 2048 2054 2060 2065 2071 2076 2082 2088 2093 2099
2105 2111 2116 2122 2128 2133 2139 2144 2150 2156 2161 2167 2172 2178 2184 2189 2195

Phix

with javascript_semantics
function week_number(integer y,m,d)
    integer doy = day_of_year(y,m,d),
            dow = day_of_week(y,m,d),
            week = floor((doy-dow+10)/7)
    return week
end function
 
for c=20 to 22 do
    sequence long_years = {}
    integer century = (c-1)*100
    for year=century to century+99 do
        if week_number(year,12,28)=53 then
            long_years &= year
        end if
    end for
    printf(1,"Long years in the %d%s century:%v\n", {c,ord(c),long_years})
end for
Output:
Long years in the 20th century:{1903,1908,1914,1920,1925,1931,1936,1942,1948,1953,1959,1964,1970,1976,1981,1987,1992,1998}
Long years in the 21st century:{2004,2009,2015,2020,2026,2032,2037,2043,2048,2054,2060,2065,2071,2076,2082,2088,2093,2099}
Long years in the 22nd century:{2105,2111,2116,2122,2128,2133,2139,2144,2150,2156,2161,2167,2172,2178,2184,2189,2195}

PHP

function isLongYear($year) {
  return (53 == strftime('%V', gmmktime(0,0,0,12,28,$year)));
}

for ($y=1995; $y<=2045; ++$y) {
  if (isLongYear($y)) {
    printf("%s\n", $y);
  }
}
Output:
1998
2004
2009
2015
2020
2026
2032
2037
2043

PL/0

Translation of: Commodore BASIC

The program waits for two numbers: startyear and endyear. Then displays long years from startyear to endyear.

var startyear, endyear, year, longyear, ayear, weekday;

procedure calcweekday;
begin
  weekday := ayear + ayear / 4 - ayear / 100 + ayear / 400;
  weekday := weekday - (weekday / 7) * 7
end;

procedure calclongyear;
begin
  longyear := 0; ayear := year;
  call calcweekday;
  if weekday = 4 then longyear := 1;
  ayear := year - 1;
  call calcweekday;
  if weekday = 3 then longyear := 1
end;

begin
  ? startyear;
  ? endyear;
  year := startyear;
  while year <= endyear do
  begin
    call calclongyear;
    if longyear <> 0 then ! year;
    year := year + 1
  end
end.
Input:
1995
2045
Output:
    1998
    2004
    2009
    2015
    2020
    2026
    2032
    2037
    2043

PowerShell

Function Is-Long-Year {
  param([Int]$year)
  53 -eq (Get-Date -Year $year -Month 12 -Day 28 -UFormat %V)
}

For ($y=1995; $y -le 2045; $y++) {
  If (Is-Long-Year $y) {
    Write-Host $y
  }
}
Output:
1998
2004
2009
2015
2020
2026
2032
2037
2043

Prolog

Translation of: C++
Works with: SWI Prolog
% See https://en.wikipedia.org/wiki/ISO_week_date#Weeks_per_year

p(Year, P):-
    P is (Year + (Year//4) - (Year//100) + (Year//400)) mod 7.

long_year(Year):-
    p(Year, 4),
    !.
long_year(Year):-
    Year_before is Year - 1,
    p(Year_before, 3).

print_long_years(From, To):-
    writef("Long years between %w and %w:\n", [From, To]),
    print_long_years(From, To, 0),
    nl.

print_long_years(From, To, _):-
    From > To,
    !.
print_long_years(From, To, Count):-
    long_year(From),
    !,
    (Count > 0 ->
        (0 is Count mod 10 -> nl ; write(' '))
        ;
        true
    ),
    write(From),
    Count1 is Count + 1,
    Next is From + 1,
    print_long_years(Next, To, Count1).
print_long_years(From, To, Count):-
    Next is From + 1,
    print_long_years(Next, To, Count).

main:-
     print_long_years(1800, 2100).
Output:
Long years between 1800 and 2100:
1801 1807 1812 1818 1824 1829 1835 1840 1846 1852
1857 1863 1868 1874 1880 1885 1891 1896 1903 1908
1914 1920 1925 1931 1936 1942 1948 1953 1959 1964
1970 1976 1981 1987 1992 1998 2004 2009 2015 2020
2026 2032 2037 2043 2048 2054 2060 2065 2071 2076
2082 2088 2093 2099

Python

Works with: Python version 3.7
'''Long Year ?'''

from datetime import date


# longYear :: Year Int -> Bool
def longYear(y):
    '''True if the ISO year y has 53 weeks.'''
    return 52 < date(y, 12, 28).isocalendar()[1]


# --------------------------TEST---------------------------
# main :: IO ()
def main():
    '''Longer (53 week) years in the range 2000-2100'''
    for year in [
            x for x in range(2000, 1 + 2100)
            if longYear(x)
    ]:
        print(year)


# MAIN ---
if __name__ == '__main__':
    main()
Output:
2004
2009
2015
2020
2026
2032
2037
2043
2048
2054
2060
2065
2071
2076
2082
2088
2093
2099

Quackery

dayofweek is defined at Day of the week#Quackery

  [ dup dip
      [ 1 1 rot dayofweek 4 = ]
    31 12 rot dayofweek 4 = or ] is longyear ( n --> b )

  say "Long Years in the 21st Century" cr
  cr
  100 times
    [ 2000 i^ + longyear if 
      [ 2000 i^ + echo sp ] ]
Output:
Long Years in the 21st Century

2004 2009 2015 2020 2026 2032 2037 2043 2048 2054 2060 2065 2071 2076 2082 2088 2093 2099 


Raku

(formerly Perl 6)

Works with: Rakudo version 2019.11

December 28 is always in the last week of the year. (By ISO8601)

sub is-long ($year) { Date.new("$year-12-28").week[1] == 53 }

# Testing
say   "Long years in the 20th century:\n", (1900..^2000).grep: &is-long;
say "\nLong years in the 21st century:\n", (2000..^2100).grep: &is-long;
say "\nLong years in the 22nd century:\n", (2100..^2200).grep: &is-long;
Output:
Long years in the 20th century:
(1903 1908 1914 1920 1925 1931 1936 1942 1948 1953 1959 1964 1970 1976 1981 1987 1992 1998)

Long years in the 21st century:
(2004 2009 2015 2020 2026 2032 2037 2043 2048 2054 2060 2065 2071 2076 2082 2088 2093 2099)

Long years in the 22nd century:
(2105 2111 2116 2122 2128 2133 2139 2144 2150 2156 2161 2167 2172 2178 2184 2189 2195)

REXX

/*REXX program determines If a (calendar) year is a short or long  year */
/*                                                    (52 or 53 weeks). */
Parse Arg lo hi .                              /* obtain optional args. */
current=left(date('S'),4)
If lo=='' | lo=="," | lo=='*' Then lo=current  /*Not given? Use default.*/
If hi=='' | hi==","           Then hi=lo       /* "    "     "     "    */
If                    hi=='*' Then hi=current  /*an asterisk: current yr*/

Do yr=lo To hi                        /* process single yr  or range of */
  Say '     year ' yr ' is a ',
      right(word('short long',is_long(yr)+1),5) ' year'
  End
Exit
/*----------------------------------------------------------------------*/
wd_1231:
/*************************************************************************
* returns the day of the week of 31 December year
*************************************************************************/
  Parse Arg year
  Return (year+year%4-year%100+year%400)//7

is_long:
  Parse Arg year
  Return wd_1231(year)==4 |,    /* year ends in a Thursday              */
         wd_1231(year-1)==3     /* or previous year ends in a Wednesday */
output   when using the inputs of:     1990   2030

(Shown at three-quarter size.)

     year  1990  is a  short  year
     year  1991  is a  short  year
     year  1992  is a   long  year
     year  1993  is a  short  year
     year  1994  is a  short  year
     year  1995  is a  short  year
     year  1996  is a  short  year
     year  1997  is a  short  year
     year  1998  is a   long  year
     year  1999  is a  short  year
     year  2000  is a  short  year
     year  2001  is a  short  year
     year  2002  is a  short  year
     year  2003  is a  short  year
     year  2004  is a   long  year
     year  2005  is a  short  year
     year  2006  is a  short  year
     year  2007  is a  short  year
     year  2008  is a  short  year
     year  2009  is a   long  year
     year  2010  is a  short  year
     year  2011  is a  short  year
     year  2012  is a  short  year
     year  2013  is a  short  year
     year  2014  is a  short  year
     year  2015  is a   long  year
     year  2016  is a  short  year
     year  2017  is a  short  year
     year  2018  is a  short  year
     year  2019  is a  short  year
     year  2020  is a   long  year
     year  2021  is a  short  year
     year  2022  is a  short  year
     year  2023  is a  short  year
     year  2024  is a  short  year
     year  2025  is a  short  year
     year  2026  is a   long  year
     year  2027  is a  short  year
     year  2028  is a  short  year
     year  2029  is a  short  year
     year  2030  is a  short  year

Ring

see "long years 2000-2099: "
for year = 2000 to 2100
    num1 = (year-1900)%7 
    num2 = floor((year-1904)/4)
    num3 = (num1+num2+5)%7 
    if num3 = 0 or (num1 = 6 and num3 = 1)
       see "" + year + " "
    ok
next
Output:
long years 2000-2099: 2004 2009 2015 2020 2026 2032 2037 2043 2048 2054 2060 2065 2071 2076 2082 2088 2093 2099 

RPL

This is a direct transcription from Wikipedia's formula.

Works with: Halcyon Calc version 4.2.7
Code Comments
 ≪ 
  DUP 1 -
  1 2 START
     → y ≪ y DUP 4 / IP + y 100 / IP - y 400 / IP + 7 MOD ≫
     SWAP 
     NEXT
     3 == SWAP 4 == OR
≫ 'LONG?' STO
( year -- weekday )

 Calling 2 times...
  ... p() as a nested function, to get p(y-1)...
  ...then p(y)



The following line of code delivers what is required:

≪ {} 2023 2100 FOR y IF y LONG? THEN y + END NEXT ≫ EVAL
Output:
1: { 2026 2032 2037 2043 2048 2054 2060 2065 2071 2076 2082 2088 2093 2099 }

Ruby

require 'date'

def long_year?(year = Date.today.year)
  Date.new(year, 12, 28).cweek == 53
end

(2020..2030).each{|year| puts "#{year} is long? #{ long_year?(year) }." }
Output:
2020 is long? true.
2021 is long? false.
2022 is long? false.
2023 is long? false.
2024 is long? false.
2025 is long? false.
2026 is long? true.
2027 is long? false.
2028 is long? false.
2029 is long? false.
2030 is long? false.

Rust

extern crate time; // 0.2.16

use time::Date;

fn main() {
    (2000..=2099)
        .filter(|&year| is_long_year(year))
        .for_each(|year| println!("{}", year));
}

fn is_long_year(year: i32) -> bool {
    Date::try_from_ymd(year, 12, 28).map_or(false, |date| date.week() == 53)
}
Output:
2004
2009
2015
2020
2026
2032
2037
2043
2048
2054
2060
2065
2071
2076
2082
2088
2093
2099

Scala

Output:
Best seen running in your browser by Scastie (remote JVM).
import java.time.temporal.TemporalAdjusters.firstInMonth
import java.time.temporal.{ChronoField, IsoFields}
import java.time.{DayOfWeek, LocalDate, Month}

import scala.util.{Failure, Try}

private object LongYear extends App {
  private val (currentCentury, maxWeekNumber) = (LocalDate.now().getYear / 100, ChronoField.ALIGNED_WEEK_OF_YEAR.range().getMaximum)
  private val centuries = currentCentury * 100 until (currentCentury + 1) * 100
  private val results = List(
    centuries.filter(isThursdayFirstOrLast),
    centuries.filter(year => maxIsoWeeks(year) == maxWeekNumber),
    centuries.filter(mostThursdaysInYear)
  )

  // Solution 1, the first or respectively last day of the year is a Thursday.
  private def isThursdayFirstOrLast(_year: Int): Boolean = {

    LocalDate.of(_year, Month.DECEMBER, 31).get(ChronoField.DAY_OF_WEEK) == DayOfWeek.THURSDAY.getValue ||
    LocalDate.of(_year, Month.JANUARY, 1).get(ChronoField.DAY_OF_WEEK) == DayOfWeek.THURSDAY.getValue
  }

  // Solution 2, if last week that contains at least four days of the month of December.
  private def maxIsoWeeks(_year: Int) = {
    // The last week that contains at least four days of the month of December.
    LocalDate.of(_year, Month.DECEMBER, 28).get(IsoFields.WEEK_OF_WEEK_BASED_YEAR)
  }

  // Solution 3, if there are 52 Thursdays in a year
  private def mostThursdaysInYear(_year: Int) = {
    val datum = LocalDate.of(_year, Month.JANUARY, 1).`with`(firstInMonth(DayOfWeek.THURSDAY))

    datum.plusDays(52 * 7).getYear == _year
  }

  println(s"Years in this ${currentCentury + 1}st century having ISO week $maxWeekNumber :")

  Try { // Testing the solutions
    assert(results.tail.forall(_ == results.head), "Discrepancies in results.")
  } match {
    case Failure(ex) => Console.err.println(ex.getMessage)
    case _ =>
  }

  results.zipWithIndex.foreach(solution => println(s"Solution ${solution._2}: ${solution._1.mkString(" ")}"))

}

Scheme

Works with: MIT Scheme
Works with: Guile
Works with: Racket

The demo code uses iota as defined in SRFI-1, so won't work in Schemes lacking that function. Racket requires the addition of (require srfi/1).

(define (dec31wd year) 
    (remainder (apply + (map (lambda (d) (quotient year d)) '(1 4 -100 400))) 7))

(define (long? year) (or (= 4 (dec31wd year)) (= 3 (dec31wd (- year 1)))))

(display "Long years between 1800 and 2100:") (newline)
(display (filter long? (iota 300 1800)))
Output:
Long years between 1800 and 2100:
(1801 1807 1812 1818 1824 1829 1835 1840 1846 1852 1857 1863 1868 1874 1880 1885 1891 1896 1903 1908 1914 1920 1925 1931 1936 1942 1948 1953 1959 1964 1970 1976 1981 1987 1992 1998 2004 2009 2015 2020 2026 2032 2037 2043 2048 2054 2060 2065 2071 2076 2082 2088 2093 2099)

Sidef

func is_long_year(year) {
    Date.parse("#{year}-12-28", "%Y-%m-%d").week == 53
}

say (  "Long years in the 20th century:\n", (1900..^2000).grep(is_long_year))
say ("\nLong years in the 21st century:\n", (2000..^2100).grep(is_long_year))
say ("\nLong years in the 22nd century:\n", (2100..^2200).grep(is_long_year))
Output:
Long years in the 20th century:
[1903, 1908, 1914, 1920, 1925, 1931, 1936, 1942, 1948, 1953, 1959, 1964, 1970, 1976, 1981, 1987, 1992, 1998]

Long years in the 21st century:
[2004, 2009, 2015, 2020, 2026, 2032, 2037, 2043, 2048, 2054, 2060, 2065, 2071, 2076, 2082, 2088, 2093, 2099]

Long years in the 22nd century:
[2105, 2111, 2116, 2122, 2128, 2133, 2139, 2144, 2150, 2156, 2161, 2167, 2172, 2178, 2184, 2189, 2195]

Snobol

               DEFINE('DEC31WD(Year)')       :(END_DEC31WD)
DEC31WD        DEC31WD = REMDR(Year + (Year / 4) - (Year / 100) + (Year / 400), 7) :(RETURN)
END_DEC31WD

               DEFINE('ISOLONG(Year)')       :(END_ISOLONG)
ISOLONG        EQ(DEC31WD(Year), 4)          :S(RETURN)
               EQ(DEC31WD(Year - 1), 3)      :S(RETURN)F(FRETURN)
END_ISOLONG

               DEFINE('ISODEMO(Start,End)')  :(END_ISODEMO)
ISODEMO        OUTPUT = 'ISO long years between ' Start ' and ' End ':'
               Year = Start
LOOP           OUTPUT = ISOLONG(Year) Year
               Year = Year + 1
               LE(YEAR, 2045)                :S(LOOP) F(RETURN)
END_ISODEMO

                ISODEMO(1995, 2045)
END
Output:
ISO long years between 1995 and 2045:
1998
2004
2009
2015
2020
2026
2032
2037
2043

Swift

func isLongYear(_ year: Int) -> Bool {
  let year1 = year - 1
  let p = (year + (year / 4) - (year / 100) + (year / 400)) % 7
  let p1 = (year1 + (year1 / 4) - (year1 / 100) + (year1 / 400)) % 7

  return p == 4 || p1 == 3
}

for range in [1900...1999, 2000...2099, 2100...2199] {
  print("\(range): \(range.filter(isLongYear))")
}
Output:
1900...1999: [1903, 1908, 1914, 1920, 1925, 1931, 1936, 1942, 1948, 1953, 1959, 1964, 1970, 1976, 1981, 1987, 1992, 1998]
2000...2099: [2004, 2009, 2015, 2020, 2026, 2032, 2037, 2043, 2048, 2054, 2060, 2065, 2071, 2076, 2082, 2088, 2093, 2099]
2100...2199: [2105, 2111, 2116, 2122, 2128, 2133, 2139, 2144, 2150, 2156, 2161, 2167, 2172, 2178, 2184, 2189, 2195]

Tcl

Translation of: C++
## Reference: https://en.wikipedia.org/wiki/ISO_week_date#Weeks_per_year

proc p {year} {
    return [expr {($year + ($year/4) - ($year/100) + ($year/400)) % 7}]
}
 
proc is_long_year {year} {
    return [expr {[p $year] == 4 || [p [expr {$year - 1}]] == 3}]
}
 
proc print_long_years {from to} {
    for {set year $from; set count 0} {$year <= $to} {incr year} {
        if {[is_long_year $year]} {
            if {$count > 0} {
                puts -nonewline [expr {($count % 10 == 0) ? "\n" : " "}]
            }
            puts -nonewline $year
            incr count
        }
    }
}
 
puts "Long years between 1800 and 2100:"
print_long_years 1800 2100
puts ""
Output:
Long years between 1800 and 2100:
1801 1807 1812 1818 1824 1829 1835 1840 1846 1852
1857 1863 1868 1874 1880 1885 1891 1896 1903 1908
1914 1920 1925 1931 1936 1942 1948 1953 1959 1964
1970 1976 1981 1987 1992 1998 2004 2009 2015 2020
2026 2032 2037 2043 2048 2054 2060 2065 2071 2076
2082 2088 2093 2099

Terraform

Works with: Terraform version 0.13+

Contents of main module:

module "iso-long-years" {
  source = "./iso-long-years"
  start_year = 1995
  end_year = 2045
}

output "long-years" {
   value = module.iso-long-years.long-years
}

Contents of iso-long-years module:

variable start_year {
  type = number
}

variable end_year {
  type = number
}

locals {
  year_list = range(var.start_year, var.end_year+1)
}

module "iso-long-year" {
  for_each = toset([for y in local.year_list: tostring(y)])
  source = "../iso-long-year"
  year = each.key
}

output "long-years" {
  value = compact([for y in [for n in local.year_list: tostring(n)]:
    module.iso-long-year[y].isLong ? y : ""])
}

Contents of iso-long-year module:

variable year {
  type = string
  default = ""
}

locals {
  ystr = var.year != "" ? var.year : split("-",timestamp())[0]
  y = tonumber(local.ystr)
  e = local.y - 1
  dec31 = local.y * 365 + floor(local.y/4) - floor(local.y/100) + floor(local.y/400)
  jan1 = local.e * 365 + floor(local.e/4) - floor(local.e/100) + floor(local.e/400) + 1
}

output isLong {
  value = (local.dec31 % 7 == 4 || local.jan1 % 7 == 4)
}
Output:
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

long-years = [
  "1998",
  "2004",
  "2009",
  "2015",
  "2020",
  "2026",
  "2032",
  "2037",
  "2043",
]

TypeScript

const isLongYear = (year: number): boolean => {
  const jan1: Date = new Date(year, 0, 1);
  const dec31: Date = new Date(year, 11, 31);
  return (4 == jan1.getDay() || 4 == dec31.getDay())
}

for (let y: number = 1995; y <= 2045; y++) {
  if (isLongYear(y)) {
    console.log(y)
  }
}
Output:
1998
2004
2009
2015
2020
2026
2032
2037
2043

UNIX Shell

Thursdays check using cal(1) and grep(1)

long_year() {
  cal 1 $1 | grep -q ' 3 *$' && return 0
  cal 12 $1 | grep -q ' 26 *$'
}

Straightforward check using GNU date(1)

December 28th is always in the last week of the year, so just check whether or not that's week 53:

long_year() {
  expr $(date -d "$1-12-28" +%V) = 53 >/dev/null
}

Direct computation with built-in arithmetic in newer shells

Works with: Bourne Again SHell
Works with: Korn Shell
Works with: Zsh
dec31wd() {
  # return weekday (time_t tm_wday, 0=Sunday) of December 31st of the given year
  typeset -i y=$1
  echo $(( (y + y / 4 - y / 100 + y / 400) % 7 ))
}

# the year is long if the year starts or ends on a Thursday (starts on a
# Thursday = the previous year ends on a Wednesday)
long_year() {
   typeset -i y=$1
   (( 4 == $(dec31wd $y) || 3 == $(dec31wd $(( y - 1 ))) ))
}

Demo code for any of the above:

for y in $(seq 1995 2045); do
  if long_year $y; then
    echo $y
  fi
done | column
Output:
1998    2004    2009    2015    2020    2026    2032    2037    2043

Wren

Translation of: Go
Library: Wren-date
import "./date" for Date

var centuries = ["20th", "21st", "22nd"]
var starts = [1900, 2000, 2100]
for (i in 0...centuries.count) {
    var longYears = []
    System.print("\nLong years in the %(centuries[i]) century:")
    for (j in starts[i]...starts[i]+100) {
        var t = Date.new(j, 12, 28)
        if (t.weekOfYear[1] == 53) {
            longYears.add(j)
        }
    }
    System.print(longYears)
}
Output:
Long years in the 20th century:
[1903, 1908, 1914, 1920, 1925, 1931, 1936, 1942, 1948, 1953, 1959, 1964, 1970, 1976, 1981, 1987, 1992, 1998]

Long years in the 21st century:
[2004, 2009, 2015, 2020, 2026, 2032, 2037, 2043, 2048, 2054, 2060, 2065, 2071, 2076, 2082, 2088, 2093, 2099]

Long years in the 22nd century:
[2105, 2111, 2116, 2122, 2128, 2133, 2139, 2144, 2150, 2156, 2161, 2167, 2172, 2178, 2184, 2189, 2195]

XPL0

Translation of: Commodore BASIC
Works with: EXPL-32
\Long year
code Rem=2, CrLf=9, IntIn=10, IntOut=11, Text=12, Clear=40;
integer S, E, Y;
    
  function integer Weekday(Y);
  \Weekday of Y-12-31, 0 Sunday
  integer Y;
  return Rem((Y + Y / 4 - Y / 100 + Y / 400) / 7);

  function integer IsLongYear(Y);
  integer Y;
  return 4 = Weekday(Y) ! 3 = Weekday(Y - 1);

begin
Clear;   
Text(0, "****     List of ISO long years     ****");
CrLf(0);
Text(0, "Start year: "); S:= IntIn(0);
Text(0, "End year: "); E:= IntIn(0);
CrLf(0);
for Y:= S, E do
  if IsLongYear(Y) then [IntOut(0, Y); Text(0, " ")];
CrLf(0);
end
Output:
****     List of ISO long years     ****
Start year: 1995
End year: 2045

1998 2004 2009 2015 2020 2026 2032 2037 2043

zkl

fcn isLongYear(y){ Time.Date.weeksInYear(y)==53 }
foreach nm,y in (T(T("20th",1900), T("21st",2000), T("22nd",2100))){
   println("\nLong years in the %s century:\n%s".fmt(nm,
      [y..y+99].filter(isLongYear).concat(" ")));
}
Output:
Long years in the 20th century:
1903 1908 1914 1920 1925 1931 1936 1942 1948 1953 1959 1964 1970 1976 1981 1987 1992 1998

Long years in the 21st century:
2004 2009 2015 2020 2026 2032 2037 2043 2048 2054 2060 2065 2071 2076 2082 2088 2093 2099

Long years in the 22nd century:
2105 2111 2116 2122 2128 2133 2139 2144 2150 2156 2161 2167 2172 2178 2184 2189 2195