Five weekends: Difference between revisions
(Ada solution added) |
|||
Line 14: | Line 14: | ||
Count and/or show all of the years which do not have at least one five-weekend month (there should be 29). |
Count and/or show all of the years which do not have at least one five-weekend month (there should be 29). |
||
=={{header|Ada}}== |
|||
<lang Ada> |
|||
with Ada.Text_IO; use Ada.Text_IO; |
|||
with Ada.Calendar.Formatting; use Ada.Calendar; |
|||
use Ada.Calendar.Formatting; |
|||
procedure Five_Weekends is |
|||
Months : Natural := 0; |
|||
begin |
|||
for Year in Year_Number range 1901..2100 loop |
|||
for Month in Month_Number range 1..12 loop |
|||
begin |
|||
if Day_Of_Week (Formatting.Time_Of (Year, Month, 31)) = Sunday then |
|||
Put_Line (Year_Number'Image (Year) & Month_Number'Image (Month)); |
|||
Months := Months + 1; |
|||
end if; |
|||
exception |
|||
when Time_Error => |
|||
null; |
|||
end; |
|||
end loop; |
|||
end loop; |
|||
Put_Line ("Number of months:" & Integer'Image (Months)); |
|||
end Five_Weekends; |
|||
</lang> |
|||
Sample output: |
|||
<pre style="height:30ex;overflow:scroll"> |
|||
1901 3 |
|||
1902 8 |
|||
1903 5 |
|||
1904 1 |
|||
1904 7 |
|||
1905 12 |
|||
1907 3 |
|||
1908 5 |
|||
1909 1 |
|||
1909 10 |
|||
1910 7 |
|||
1911 12 |
|||
1912 3 |
|||
1913 8 |
|||
1914 5 |
|||
1915 1 |
|||
1915 10 |
|||
1916 12 |
|||
1918 3 |
|||
1919 8 |
|||
1920 10 |
|||
1921 7 |
|||
1922 12 |
|||
1924 8 |
|||
1925 5 |
|||
1926 1 |
|||
1926 10 |
|||
1927 7 |
|||
1929 3 |
|||
1930 8 |
|||
1931 5 |
|||
1932 1 |
|||
1932 7 |
|||
1933 12 |
|||
1935 3 |
|||
1936 5 |
|||
1937 1 |
|||
1937 10 |
|||
1938 7 |
|||
1939 12 |
|||
1940 3 |
|||
1941 8 |
|||
1942 5 |
|||
1943 1 |
|||
1943 10 |
|||
1944 12 |
|||
1946 3 |
|||
1947 8 |
|||
1948 10 |
|||
1949 7 |
|||
1950 12 |
|||
1952 8 |
|||
1953 5 |
|||
1954 1 |
|||
1954 10 |
|||
1955 7 |
|||
1957 3 |
|||
1958 8 |
|||
1959 5 |
|||
1960 1 |
|||
1960 7 |
|||
1961 12 |
|||
1963 3 |
|||
1964 5 |
|||
1965 1 |
|||
1965 10 |
|||
1966 7 |
|||
1967 12 |
|||
1968 3 |
|||
1969 8 |
|||
1970 5 |
|||
1971 1 |
|||
1971 10 |
|||
1972 12 |
|||
1974 3 |
|||
1975 8 |
|||
1976 10 |
|||
1977 7 |
|||
1978 12 |
|||
1980 8 |
|||
1981 5 |
|||
1982 1 |
|||
1982 10 |
|||
1983 7 |
|||
1985 3 |
|||
1986 8 |
|||
1987 5 |
|||
1988 1 |
|||
1988 7 |
|||
1989 12 |
|||
1991 3 |
|||
1992 5 |
|||
1993 1 |
|||
1993 10 |
|||
1994 7 |
|||
1995 12 |
|||
1996 3 |
|||
1997 8 |
|||
1998 5 |
|||
1999 1 |
|||
1999 10 |
|||
2000 12 |
|||
2002 3 |
|||
2003 8 |
|||
2004 10 |
|||
2005 7 |
|||
2006 12 |
|||
2008 8 |
|||
2009 5 |
|||
2010 1 |
|||
2010 10 |
|||
2011 7 |
|||
2013 3 |
|||
2014 8 |
|||
2015 5 |
|||
2016 1 |
|||
2016 7 |
|||
2017 12 |
|||
2019 3 |
|||
2020 5 |
|||
2021 1 |
|||
2021 10 |
|||
2022 7 |
|||
2023 12 |
|||
2024 3 |
|||
2025 8 |
|||
2026 5 |
|||
2027 1 |
|||
2027 10 |
|||
2028 12 |
|||
2030 3 |
|||
2031 8 |
|||
2032 10 |
|||
2033 7 |
|||
2034 12 |
|||
2036 8 |
|||
2037 5 |
|||
2038 1 |
|||
2038 10 |
|||
2039 7 |
|||
2041 3 |
|||
2042 8 |
|||
2043 5 |
|||
2044 1 |
|||
2044 7 |
|||
2045 12 |
|||
2047 3 |
|||
2048 5 |
|||
2049 1 |
|||
2049 10 |
|||
2050 7 |
|||
2051 12 |
|||
2052 3 |
|||
2053 8 |
|||
2054 5 |
|||
2055 1 |
|||
2055 10 |
|||
2056 12 |
|||
2058 3 |
|||
2059 8 |
|||
2060 10 |
|||
2061 7 |
|||
2062 12 |
|||
2064 8 |
|||
2065 5 |
|||
2066 1 |
|||
2066 10 |
|||
2067 7 |
|||
2069 3 |
|||
2070 8 |
|||
2071 5 |
|||
2072 1 |
|||
2072 7 |
|||
2073 12 |
|||
2075 3 |
|||
2076 5 |
|||
2077 1 |
|||
2077 10 |
|||
2078 7 |
|||
2079 12 |
|||
2080 3 |
|||
2081 8 |
|||
2082 5 |
|||
2083 1 |
|||
2083 10 |
|||
2084 12 |
|||
2086 3 |
|||
2087 8 |
|||
2088 10 |
|||
2089 7 |
|||
2090 12 |
|||
2092 8 |
|||
2093 5 |
|||
2094 1 |
|||
2094 10 |
|||
2095 7 |
|||
2097 3 |
|||
2098 8 |
|||
2099 5 |
|||
2100 1 |
|||
2100 10 |
|||
Number of months: 201 |
|||
</pre> |
|||
=={{header|D}}== |
=={{header|D}}== |
||
<lang d>import std.gregorian ; // this module currently work in progress |
<lang d>import std.gregorian ; // this module currently work in progress |
||
Line 49: | Line 280: | ||
output match [[#Python|python]] one. |
output match [[#Python|python]] one. |
||
=={{header|GAP}}== |
=={{header|GAP}}== |
||
<lang gap># return a list of two lists : |
<lang gap># return a list of two lists : |
Revision as of 20:25, 17 November 2010
You are encouraged to solve this task according to the task description, using any language you may know.
The month of October in 2010 has five Fridays, five Saturdays, and five Sundays.
The task
- Write a program to show all months that have this same characteristic of five full weekends from the year 1900 through 2100 (Gregorian calendar).
- Show the number of months with this property (there should be 201).
- Show at least the first and last five dates, in order.
Algorithm suggestions
- Count the number of Fridays, Saturdays, and Sundays in every month.
- Find all of the 31-day months that begin on Friday.
Extra credit
Count and/or show all of the years which do not have at least one five-weekend month (there should be 29).
Ada
<lang Ada> with Ada.Text_IO; use Ada.Text_IO; with Ada.Calendar.Formatting; use Ada.Calendar;
use Ada.Calendar.Formatting;
procedure Five_Weekends is
Months : Natural := 0;
begin
for Year in Year_Number range 1901..2100 loop for Month in Month_Number range 1..12 loop begin if Day_Of_Week (Formatting.Time_Of (Year, Month, 31)) = Sunday then Put_Line (Year_Number'Image (Year) & Month_Number'Image (Month)); Months := Months + 1; end if; exception when Time_Error => null; end; end loop; end loop; Put_Line ("Number of months:" & Integer'Image (Months));
end Five_Weekends; </lang> Sample output:
1901 3 1902 8 1903 5 1904 1 1904 7 1905 12 1907 3 1908 5 1909 1 1909 10 1910 7 1911 12 1912 3 1913 8 1914 5 1915 1 1915 10 1916 12 1918 3 1919 8 1920 10 1921 7 1922 12 1924 8 1925 5 1926 1 1926 10 1927 7 1929 3 1930 8 1931 5 1932 1 1932 7 1933 12 1935 3 1936 5 1937 1 1937 10 1938 7 1939 12 1940 3 1941 8 1942 5 1943 1 1943 10 1944 12 1946 3 1947 8 1948 10 1949 7 1950 12 1952 8 1953 5 1954 1 1954 10 1955 7 1957 3 1958 8 1959 5 1960 1 1960 7 1961 12 1963 3 1964 5 1965 1 1965 10 1966 7 1967 12 1968 3 1969 8 1970 5 1971 1 1971 10 1972 12 1974 3 1975 8 1976 10 1977 7 1978 12 1980 8 1981 5 1982 1 1982 10 1983 7 1985 3 1986 8 1987 5 1988 1 1988 7 1989 12 1991 3 1992 5 1993 1 1993 10 1994 7 1995 12 1996 3 1997 8 1998 5 1999 1 1999 10 2000 12 2002 3 2003 8 2004 10 2005 7 2006 12 2008 8 2009 5 2010 1 2010 10 2011 7 2013 3 2014 8 2015 5 2016 1 2016 7 2017 12 2019 3 2020 5 2021 1 2021 10 2022 7 2023 12 2024 3 2025 8 2026 5 2027 1 2027 10 2028 12 2030 3 2031 8 2032 10 2033 7 2034 12 2036 8 2037 5 2038 1 2038 10 2039 7 2041 3 2042 8 2043 5 2044 1 2044 7 2045 12 2047 3 2048 5 2049 1 2049 10 2050 7 2051 12 2052 3 2053 8 2054 5 2055 1 2055 10 2056 12 2058 3 2059 8 2060 10 2061 7 2062 12 2064 8 2065 5 2066 1 2066 10 2067 7 2069 3 2070 8 2071 5 2072 1 2072 7 2073 12 2075 3 2076 5 2077 1 2077 10 2078 7 2079 12 2080 3 2081 8 2082 5 2083 1 2083 10 2084 12 2086 3 2087 8 2088 10 2089 7 2090 12 2092 8 2093 5 2094 1 2094 10 2095 7 2097 3 2098 8 2099 5 2100 1 2100 10 Number of months: 201
D
<lang d>import std.gregorian ; // this module currently work in progress import std.stdio, std.algorithm, std.array, std.range ;
Date[] m5w(Date start = Date(1900,1,1), Date end = Date(2100,12,31) ) {
Date[] res ; for(Date when = Date(start.year, start.month, 1) ; // adjust to 1st day when < end ; when = Date(when.year, 1 + when.month, 1)) { if(when.endOfMonthDay == 31) // Such month must has 3 + 4*7 if(when.dayOfWeek == 5 ) // days and start at friday res ~= when ; // for 5 FULL weekends. } return res ;
}
bool noM5wByYear(int year) {
return (m5w(Date(year,1,1), Date(year,12,31)).length == 0 ) ;
}
void main() {
auto m = m5w() ; // use default input writefln("There are %d months of which the first and last five are:", m.length) ; foreach(d;m[0..5]~m[$-5..$]) writefln("%s", d.toSimpleString[0..$-2]) ;
auto noM5w = filter!(noM5wByYear)(iota(1900,2101)) ; writefln("There are %d years in the range that do not have " "months with five weekends", array(noM5w).length) ;
}</lang>
output match python one.
GAP
<lang gap># return a list of two lists :
- first is the list of months with five weekends between years y1 and y2 (included)
- second is the list of years without such months, in the same interval
FiveWeekends := function(y1, y2)
local L, yL, badL, d, m, y; L := [ ]; badL := [ ]; for y in [y1 .. y2] do yL := [ ]; for m in [1, 3, 5, 7, 8, 10, 12] do if WeekDay([1, m, y]) = "Fri" then d := StringDate([1, m, y]); Add(yL, d{[4 .. 11]}); fi; od; if Length(yL) = 0 then Add(badL, y); else Append(L, yL); fi; od; return [ L, badL ];
end;
r := FiveWeekends(1900, 2100);; n := Length(r[1]);
- 201
Length(r[2]);
- 29
r[1]{[1 .. 5]};
- [ "Mar-1901", "Aug-1902", "May-1903", "Jan-1904", "Jul-1904" ]
r[1]{[n-4 .. n]};
- [ "Mar-2097", "Aug-2098", "May-2099", "Jan-2100", "Oct-2100" ]</lang>
J
<lang j>require 'types/datetime numeric' find5wkdMonths=: verb define
years=. range 2{. y months=. 1 3 5 7 8 10 12 m5w=. (#~ 0 = weekday) >,{years;months;31 NB. 5 full weekends iff 31st is Sunday(0) >'MMM YYYY' fmtDate toDayNo m5w
)</lang> Usage: <lang j> # find5wkdMonths 1900 2100 NB. number of months found 201
(5&{. , '...' , _5&{.) find5wkdMonths 1900 2100 NB. First and last 5 months found
Mar 1901 Aug 1902 May 1903 Jan 1904 Jul 1904 ... Mar 2097 Aug 2098 May 2099 Jan 2100 Oct 2100
# (range -. {:"1@(_ ". find5wkdMonths)) 1900 2100 NB. number of years without 5 weekend months
29</lang>
Java
<lang java>import java.util.Calendar; import java.util.GregorianCalendar;
public class FiveFSS {
private static boolean[] years = new boolean[201]; //dreizig tage habt september... private static int[] month31 = {Calendar.JANUARY, Calendar.MARCH, Calendar.MAY, Calendar.JULY, Calendar.AUGUST, Calendar.OCTOBER, Calendar.DECEMBER};
public static void main(String[] args) { StringBuilder months = new StringBuilder(); int numMonths = 0; for (int year = 1900; year <= 2100; year++) { for (int month : month31) { Calendar date = new GregorianCalendar(year, month, 1); if (date.get(Calendar.DAY_OF_WEEK) == Calendar.FRIDAY) { years[year - 1900] = true; numMonths++; //months are 0-indexed in Calendar months.append((date.get(Calendar.MONTH) + 1) + "-" + year +"\n"); } } } System.out.println("There are "+numMonths+" months with five weekends from 1900 through 2100:"); System.out.println(months); System.out.println("Years with no five-weekend months:"); for (int year = 1900; year <= 2100; year++) { if(!years[year - 1900]){ System.out.println(year); } } }
}</lang> Output (middle results cut out):
There are 201 months with five weekends from 1900 through 2100: 3-1901 8-1902 5-1903 1-1904 7-1904 12-1905 3-1907 5-1908 1-1909 10-1909 7-1910 ... 12-2090 8-2092 5-2093 1-2094 10-2094 7-2095 3-2097 8-2098 5-2099 1-2100 10-2100 Years with no five-weekend months: 1900 1906 1917 1923 1928 1934 1945 1951 1956 1962 1973 1979 1984 1990 2001 2007 2012 2018 2029 2035 2040 2046 2057 2063 2068 2074 2085 2091 2096
k
<lang k> cal_j:(_jd[19000101]+!(-/_jd 21010101 19000101)) / enumerate the calendar is_we:(cal_j!7) _lin 4 5 6 / identify friday saturdays and sundays m:__dj[cal_j]%100 / label the months mi:&15=+/'is_we[=m] / group by month and sum the weekend days `0:,"There are ",($#mi)," months with five weekends" m5:(?m)[mi] `0:$5#m5 `0:,"..." `0:$-5#m5 y:1900+!201 / enumerate the years in the range y5:?_ m5%100 / label the years of the months yn5:y@&~y _lin y5 / find any years not in the 5 weekend month list `0:,"There are ",($#yn5)," years without any five-weekend months" `0:,1_,/",",/:$yn5</lang> Output:
There are 201 months with five weekends 190103 190208 190305 190401 190407 ... 209703 209808 209905 210001 210010 There are 29 years without any five-weekend months 1900,1906,1917,1923,1928,1934,1945,1951,1956,1962,1973,1979,1984,1990,2001,2007,2012,2018,2029,2035,2040,2046,2057,2063,2068,2074,2085,2091,2096
Perl 6
<lang perl6># A month has 5 weekends iff it has 31 days and starts on Friday.
- Note: [@happy.end X- ^5].reverse is a workaround; Rakudo does not yet allow [*-5..*].
my @years = 1900 .. 2100; my @ym = @years X < 01 03 05 07 08 10 12 >; # Months with 31 days
my @happy = @ym.map({ Date.new: "$^a-$^b-01" }).grep: { .day-of-week == 5 };
say 'Happy month count: ', +@happy; say 'First happy months: '~ @happy[^5]; say 'Last happy months: '~ @happy[@happy.end X- ^5].reverse; say 'Dreary years count: ', @years - @happy».year.uniq; </lang> Output:
Happy month count: 201 First happy months: 1901-03-01 1902-08-01 1903-05-01 1904-01-01 1904-07-01 Last happy months: 2097-03-01 2098-08-01 2099-05-01 2100-01-01 2100-10-01 Dreary years count: 29
PicoLisp
<lang PicoLisp>(setq Lst
(make (for Y (range 1900 2100) (for M (range 1 12) (and (date Y M 31) (= "Friday" (day (date Y M 1))) (link (list (get *Mon M) Y)) ) ) ) ) )
(prinl "There are " (length Lst) " months with five weekends:") (mapc println (head 5 Lst)) (prinl "...") (mapc println (tail 5 Lst)) (prinl) (setq Lst (diff (range 1900 2100) (uniq (mapcar cadr Lst)))) (prinl "There are " (length Lst) " years with no five-weekend months:") (println Lst)</lang> Output:
There are 201 months with five weekends: (Mar 1901) (Aug 1902) (May 1903) (Jan 1904) (Jul 1904) ... (Mar 2097) (Aug 2098) (May 2099) (Jan 2100) (Oct 2100) There are 29 years with no five-weekend months: (1900 1906 1917 1923 1928 1934 1945 1951 1956 1962 1973 1979 1984 1990 2001 2007 2012 2018 2029 2035 2040 2046 2057 2063 2068 2074 2085 2091 2096)
Python
<lang python>from datetime import timedelta, date
DAY = timedelta(days=1) START, STOP = date(1900, 1, 1), date(2101, 1, 1) WEEKEND = {6, 5, 4} # Sunday is day 6 FMT = '%Y %m(%B)'
def fiveweekendspermonth(start=START, stop=STOP):
'Compute months with five weekends between dates' when = start lastmonth = weekenddays = 0 fiveweekends = [] while when < stop: year, mon, _mday, _h, _m, _s, wday, _yday, _isdst = when.timetuple() if mon != lastmonth: if weekenddays >= 15: fiveweekends.append(when - DAY) weekenddays = 0 lastmonth = mon if wday in WEEKEND: weekenddays += 1 when += DAY return fiveweekends
dates = fiveweekendspermonth() indent = ' ' print('There are %s months of which the first and last five are:' % len(dates)) print(indent +('\n'+indent).join(d.strftime(FMT) for d in dates[:5])) print(indent +'...') print(indent +('\n'+indent).join(d.strftime(FMT) for d in dates[-5:]))
print('\nThere are %i years in the range that do not have months with five weekends'
% len(set(range(START.year, STOP.year)) - {d.year for d in dates}))</lang>
Alternate Algorithm
The condition is equivalent to having a thirty-one day month in which the last day of the month is a Sunday. <lang python>LONGMONTHS = (1, 3, 5, 7, 8, 10, 12) # Jan Mar May Jul Aug Oct Dec def fiveweekendspermonth2(start=START, stop=STOP):
return [date(yr, month, 31) for yr in range(START.year, STOP.year) for month in LONGMONTHS if date(yr, month, 31).timetuple()[6] == 6 # Sunday ]
dates2 = fiveweekendspermonth2() assert dates2 == dates</lang>
Sample Output
There are 201 months of which the first and last five are: 1901 03(March) 1902 08(August) 1903 05(May) 1904 01(January) 1904 07(July) ... 2097 03(March) 2098 08(August) 2099 05(May) 2100 01(January) 2100 10(October) There are 29 years in the range that do not have months with five weekends
Ruby
<lang ruby># if the last day of the month falls on a Sunday and the month has 31 days,
- this is the only case where the month has 5 weekends.
start = Date.parse("1900-01-01") stop = Date.parse("2100-12-31") dates = (start..stop).find_all do |day|
day.mday == 31 and day.wday == 0
end
puts "There are #{dates.size} months with 5 weekends from 1900 to 2100:" puts dates[0, 5].map { |d| d.strftime("%b %Y") }.join("\n") puts "..." puts dates[-5, 5].map { |d| d.strftime("%b %Y") }.join("\n")
years_with_5w = dates.map(&:year)
years = (1900...2100).to_a - years_with_5w
puts "There are #{years.size} years without months with 5 weekends:" puts years.join(", ")</lang>
Output
There are 201 months with 5 weekends from 1900 to 2100: Mar 1901 Aug 1902 May 1903 Jan 1904 Jul 1904 ... Mar 2097 Aug 2098 May 2099 Jan 2100 Oct 2100 There are 29 years without months with 5 weekends: 1900, 1906, 1917, 1923, 1928, 1934, 1945, 1951, 1956, 1962, 1973, 1979, 1984, 1990, 2001, 2007, 2012, 2018, 2029, 2035, 2040, 2046, 2057, 2063, 2068, 2074, 2085, 2091, 2096
Tcl
<lang tcl>package require Tcl 8.5
set months {} set years {} for {set year 1900} {$year <= 2100} {incr year} {
set count [llength $months] foreach month {Jan Mar May Jul Aug Oct Dec} {
set date [clock scan "$month/01/$year" -format "%b/%d/%Y" -locale en_US] if {[clock format $date -format %u] == 5} { # Month with 31 days that starts on a Friday => has 5 weekends lappend months "$month $year" }
} if {$count == [llength $months]} {
# No change to number of months; year must've been without lappend years $year
}
} puts "There are [llength $months] months with five weekends" puts [join [list {*}[lrange $months 0 4] ... {*}[lrange $months end-4 end]] \n] puts "There are [llength $years] years without any five-weekend months" puts [join $years ","]</lang> Output:
There are 201 months with five weekends Mar 1901 Aug 1902 May 1903 Jan 1904 Jul 1904 ... Mar 2097 Aug 2098 May 2099 Jan 2100 Oct 2100 There are 29 years without any five-weekend months 1900,1906,1917,1923,1928,1934,1945,1951,1956,1962,1973,1979,1984,1990,2001,2007,2012,2018,2029,2035,2040,2046,2057,2063,2068,2074,2085,2091,2096