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.
AppleScript
<lang 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</lang>
- 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:
<lang applescript>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</lang>
AWK
<lang 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)
} </lang>
- 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
C#
<lang csharp>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; }
}</lang>
- 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
Factor
<lang factor>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</lang>
- 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
Go
<lang 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) }
}</lang>
- 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
<lang haskell>import Data.Time.Calendar.WeekDate (toWeekDate) import Data.Time.Calendar (fromGregorian)
longYear :: Integer -> Bool longYear y =
let (_, w, _) = toWeekDate $ fromGregorian y 12 28 in 52 < w
main :: IO () main = mapM_ print $ filter longYear [2000 .. 2100]</lang>
- Output:
2004 2009 2015 2020 2026 2032 2037 2043 2048 2054 2060 2065 2071 2076 2082 2088 2093 2099
Java
<lang 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; }
} </lang>
- Output:
Long years this century: 2004 2009 2015 2020 2026 2032 2037 2043 2048 2054 2060 2065 2071 2076 2082 2088 2093 2099
Julia
<lang 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
</lang>
- 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
Perl
<lang 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";
}</lang>
- 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
Perl 6
December 28 is always in the last week of the year. (By ISO8601) <lang perl6>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;</lang>
- 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)
Phix
Requires 0.8.1+ <lang Phix>include builtins\ordinal.e
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</lang>
- 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}
Python
<lang python>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()</lang>
- Output:
2004 2009 2015 2020 2026 2032 2037 2043 2048 2054 2060 2065 2071 2076 2082 2088 2093 2099
REXX
<lang 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. */ if LO== | LO=="," | LO=='*' then LO= left( date('S'), 4) /*Not given? Use default.*/ if HI== | HI=="," then HI= LO /* " " " " */ if HI=='*' then HI= left( date('S'), 4) /*an asterisk ≡ current yr*/
do j=LO to HI /*process single yr or range of years.*/ say ' year ' j " is a " right( word('short long', weeks(j)-51),5) " year" end /*j*/
exit /*stick a fork in it, we're all done. */ /*──────────────────────────────────────────────────────────────────────────────────────*/ pWeek: parse arg yr; return (yr + yr%4 - yr%100 + yr%400) // 7 /*calculate P*/ weeks: parse arg y; $= 52; if pWeek(y)==4 | pWeek(y-1)==3 then $= $ + 1; return $</lang>
- 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
Ruby
<lang 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) }." } </lang>
- 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.
Swift
<lang 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))")
}</lang>
- 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]
Visual Basic
<lang vb>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 </lang>
zkl
<lang 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(" ")));
}</lang>
- 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