16
\$\begingroup\$

Who doesn't like to chill on a Sunday morning in summer with a chilled beer and TV or in winter playing badminton or ultimate with friends?

I always think knowing how many days you have to chill in a month keeps you well-informed and helps you plan what you want to do. Be it sitting in front of your pc and solving a code-golf problem or going out to play football.

So, help me write a program or function which takes as input 2 positive integers, Y and M and outputs the number of Sundays in that particular year(Y) and month(M) (according to the Gregorian Calendar), followed by the date of each Sunday.

Also, do keep in mind that the shortest code wins.

Input Constraints

1000 <= Y <= 9999

1 <= M <= 12

Output

These test cases will have output will have the dates of each Sunday of that month in that year in the format DD-MM-YYYY.

Sample Test Cases

Test Case 1

Sample Input

2017 1

Sample Output

5
01-01-2017
08-01-2017
15-01-2017
22-01-2017
29-01-2017

Test Case 2

Sample Input

2018 2

Sample Output

4
04-02-2018
11-02-2018
18-02-2018
25-02-2018

Test Case 3

Sample Input

2016 11

Sample Output

4
06-11-2016
13-11-2016
20-11-2016
27-11-2016
\$\endgroup\$
  • 2
    \$\begingroup\$ I recommend allowing any date format, including a Date() object, and any output format, including [4, [<dateobj>, <dateobj>, <dateobj>, <dateobj>]] (where <dateobj> is an actual date object, and [] is an actual array). \$\endgroup\$ – wizzwizz4 Apr 9 '17 at 9:33
  • 2
    \$\begingroup\$ When the output format is the defining part of a challenge, community consensus is that it's boring. In future I recommend using the Sandbox, but as nobody's answered yet you could get away with changing it. \$\endgroup\$ – wizzwizz4 Apr 9 '17 at 9:46
  • 1
    \$\begingroup\$ I'll make an edit. You can roll it back if you think it damages the challenge. \$\endgroup\$ – wizzwizz4 Apr 9 '17 at 10:01
  • 1
    \$\begingroup\$ So how flexible is the output format? For example, can it have / instead of -? Or can it be month, then day, then year? \$\endgroup\$ – Luis Mendo Apr 9 '17 at 17:06
  • 1
    \$\begingroup\$ Any particular locale? Note that prior to 1582, the Julian calendar was in common use, with countries transitioning to Gregorian as late as 1952 for Greece. In England they jumped the calendar ahead 11 days in the month of September, 1752, leading to mass riots. Recommendation is to use something called the "Proleptic Gregorian Calendar" which pretends the current calendar was in use for as far back as you need. \$\endgroup\$ – user15259 Apr 9 '17 at 19:01

15 Answers 15

0
\$\begingroup\$

MATL, 46 45 42 35 bytes

8BhtYOw47B~+YOq&:t8XO!s310=)tnw24XO

Input is an array of the form [2017 1]. Output format is 29/01/2017.

Try it online! Or verify all test cases.

Explanation

8B       % Push [1 0 0 0] (8 in binary)
h        % Implicit input. Concatenate. Gives something like [2017 1 1 0 0 0],
         % corresponding to the first day of input year and month
tYO      % Duplicate. Convert to serial date number
w        % Swap
47B~     % Push [0 1 0 0 0 0] (47 in binary, then negated)
+        % Add. Gives something like [2017 2 1 0 0 0]: first day of next month
YO       % Convert to serial number
q        % Subtract 1. This corresponds to last day of input month
&:       % Binary range. Gives an array with 28, 29, 30 or 31 days
t8XO     % Duplicate. Convert each number to three letters telling day of the week
!s       % Transpose, Sum of each column
310=     % True for values that equal 310, which is the sum of 'Sun' in ASCII
)        % Apply as a logical index
tnw      % Duplicate, number of elements, swap. This is the first part of output
24XO     % Convert to date format 'dd/mm/yyyy'. Gives 2D char array. Implicit display
\$\endgroup\$
4
\$\begingroup\$

Python 2, 150,148,145 bytes

from calendar import*
y,m=map(int,input().split())
z=filter(None,zip(*monthcalendar(y,m))[6])
print len(z)
for i in z:print'%02d-%02d-%s'%(i,m,y)

Try it online!

-3 bytes making stuff more pythonic (using zip and filter!)

\$\endgroup\$
  • \$\begingroup\$ It'll be 150 if you bring the print statement up to the previous line and if you add '02' in the first %d in line 3. \$\endgroup\$ – Koishore Roy Apr 9 '17 at 14:10
  • \$\begingroup\$ '02' in the first %d ! huh. missed that. Thanks! anyways. saved two bytes though instead of increasing by two! \$\endgroup\$ – Keerthana Prabhakaran Apr 9 '17 at 14:12
4
\$\begingroup\$

JavaScript (ES6), 107 bytes

f=
(y,m,a=[...Array(32)].map((_,i)=>new Date(y,m-1,i)).filter(d=>d.getMonth()==m-1&!d.getDay()))=>[a.length,a]
<div oninput=o.textContent=[].concat(...f(y.value,m.value)).map((d,i)=&gt;i?d.toDateString():d).join`\n`><input id=y type=number min=1000 max=9999 value=2017><input id=m type=number min=1 max=12><pre id=o>

Edit: Adding an explicit count cost 15 bytes. Formatting the output would cost at least another 33 bytes depending on how strict the output format is.

\$\endgroup\$
  • \$\begingroup\$ > outputs the number of Sundays in that particular year and month; looks like this doesn't currently output the number of Sundays. \$\endgroup\$ – numbermaniac Apr 9 '17 at 11:42
  • \$\begingroup\$ You could use <input type='date'>. \$\endgroup\$ – Matthew Roh Apr 9 '17 at 11:56
  • \$\begingroup\$ @SIGSEGV Not yet supported in Firefox, which is what I use. \$\endgroup\$ – Neil Apr 9 '17 at 15:00
  • 2
    \$\begingroup\$ @Neil Use Chrome m8 \$\endgroup\$ – Matthew Roh Apr 9 '17 at 15:14
  • 3
    \$\begingroup\$ @SIGSEGV I like Chrome even less than Internet Explorer. \$\endgroup\$ – Neil Apr 9 '17 at 16:18
2
\$\begingroup\$

PowerShell, 91 bytes

param($y,$m)($a=(1..31|%{Date "$m/$_/$y"}|?{!$_.dayofweek})).count;$a|%{"{0:d-M-yyyy}"-f$_}

Try it online!

(Special note - this is locale and culture settings dependent. Since TIO is running as en-us, it works correctly there as-is. This code may need to be changed for different locales.)

Takes input as two integers $y and $m. Loops from 1 to 31, getting a new datetime object for each possible date (via the Get-Date cmdlet). Will toss errors to STDERR (ignored by default on code-golf challenges) for months with fewer than 31 days, but that doesn't affect output. We take each of those datetime objects and use a Where-Object (|?{...}) on them, with the clause of !$_.dayofweek. The property .dayofweek is a number from 0 to 6, with 0 conveniently corresponding to Sunday, so the ! of that is truthy, which saves a couple bytes compared to an equality check like -eq0.

The Sundays are then gathered in parens and stored into $a. We then take the .count thereof, and that's placed on the pipeline. Next, we loop through $a and use the -format operator to construct the correct output format. Note that this doesn't output leading zeros for days or months. Those date strings are also left on the pipeline, and an implicit Write-Output at program completion prints them with newline separators.


NB - if the output format was more flexible, we could just leave $a on the pipeline and not need to loop through it. That will stringify the datetime objects as the long-date format including time information, but gets us down to 69 bytes, which would (currently) only be beaten by Mathematica and MATL.

\$\endgroup\$
1
\$\begingroup\$

Octave, 72 bytes

@(y,m)cellfun(@disp,flip({datestr(x=nweekdate(1:6,1,y,m)(x>1)),nnz(x)}))

nweekdate returns the date number corresponding to the N-th occurrence of a particular weekday in the specified month/year. We use the array 1:6 in place of N to get all occurrences in a month. If there are fewer than N occurrences of that weekday in a month, then the resulting date number is 0. For this reason, we select only the valid dates using (x>1) and then convert them to strings using datestr.

Then to count the number of Sundays, we count the number of non-zero (nnz) date numbers in the result.

We then wrap the entire thing in cellfun to display each value.

\$\endgroup\$
0
\$\begingroup\$

Ruby, 140 132 129 118 bytes

require'date'
d=Date.parse gets.split*?-+'-1'
s=(d...d>>1).select &:sunday?
puts s.size,s.map{|d|d.strftime'%d-%m-%Y'}
\$\endgroup\$
0
\$\begingroup\$

Excel – 103 characters

Put the year in cell A1, and month in cell A2.

The count is in cell D1, and Sundays in cells D2:D6.

Assumes D2:D6 are formatted DD-MM-YYYY.

   A      B       C              D
1  [year] [month] =DATE(A1,B1,1) =COUNTIF(D2:D7,">0")
2                                =C1+7-WEEKDAY(C1,2)
3                                =D2+7
4                                =D3+7
5                                =D4+7
6                                =IF(MONTH(D5+7)=MONTH(C1),D5+7,"")
\$\endgroup\$
0
\$\begingroup\$

Mathematica, 82 68 bytes

d=DateObject;{Length[x=DayRange[d@{#,#2,1},d@{#,#2+1,0},Sunday]],x}&

Anonymous function. Outputs a list of the number of days, followed by a list of the Sundays as DateObjects. Turns out, in Mathematica the 0th day of a month is interpreted as the last day of the previous month.

\$\endgroup\$
0
\$\begingroup\$

C#, 183 bytes

y=>m=>{var s=new string[6];int i=1,n=0;for(DateTime d;i<=DateTime.DaysInMonth(y,m);)if((int)(d=new DateTime(y,m,i++)).DayOfWeek<1)s[++n]=d.ToString("dd-MM-yyyy");s[0]=n+"";return s;};

Anonymous method which returns an array of string, containing first the number of Sundays and then each Sunday in the specified format. If there are only 4 Sunday in a month, the last string is null.

Full program with ungolfed method and test cases:

using System;

class P
{
    static void Main()
    {
        Func<int, Func<int, string[]>> f =
        y=>m=>
        {
            var s=new string[6];
            int i=1,n=0;
            for(DateTime d;i<=DateTime.DaysInMonth(y,m);)
                if((int)(d=new DateTime(y,m,i++)).DayOfWeek<1)
                    s[++n]=d.ToString("dd-MM-yyyy");

            s[0]=n+"";
            return s;
        };

        // test cases:
        var result = f(2017)(1);
        foreach (var x in result)
            Console.WriteLine(x);

        result = f(2018)(2);
        foreach (var x in result)
            Console.WriteLine(x);

        result = f(2016)(11);
        foreach (var x in result)
            Console.WriteLine(x);
    }
}
\$\endgroup\$
0
\$\begingroup\$

REXX, 168 bytes

arg y m
signal on syntax
do d=1 to 31
  m=right(m,2,0);d=right(d,2,0)
  if date(w,y||m||d,s)='Sunday' then queue d'-'m'-'y
  end
syntax:n=queued()
say n
do n
  pull a
  say a
  end
\$\endgroup\$
  • \$\begingroup\$ I guess this does not work with smaller years. Have you tried 1217? \$\endgroup\$ – Titus Apr 14 '17 at 15:36
0
\$\begingroup\$

Bash + bsdmainutils, 94 bytes

a=(`for i in $(cal $2 $1|cut -b1-2);{ echo $i-$2-$1;}`);echo $[${#a[@]}-1];fmt -1 <<<${a[@]:1}

Uses the command cal which prints a calendar, is installed by default in several UNIX/LINUX/BSD (unfortunately not in TIO).

To try it save to file, chmod +x file, and run ./file 2017 9

Saves to array a the first two bytes of cal output appended with the string "MM-YYYY" passed as second and first parameters (needs change if your locale does not starts weeks on sundays).

Next echoes array length substracted by one (first element is the word representing sunday) and the array without the first elemet, one per line fmt -1

\$\endgroup\$
  • \$\begingroup\$ It handles special case 1752 9 \$\endgroup\$ – marcosm Apr 11 '17 at 12:34
0
\$\begingroup\$

SAS, 182 bytes

%macro s(y,m);%let c=%eval(%sysfunc(intck(week,%sysfunc(nwkdom(1,1,&m,&y)),%sysfunc(nwkdom(5,1,&m,&y))))+1);%put&c;%do i=1%to&c;%put%sysfunc(nwkdom(&i,1,&m,&y),ddmmyy10.);%end;%mend;
\$\endgroup\$
0
\$\begingroup\$

T-SQL, 316 311 bytes

DECLARE @ DATE=DATEADD(ww,-52*(2017-@y),'20170101')IF DATEPART(d,@)>7SET @=DATEADD(ww,-1,@);WITH c(d)AS(SELECT d FROM(SELECT DATEADD(ww,ROW_NUMBER()OVER(ORDER BY name)-1,@)d FROM sys.stats)a WHERE @y=DATEPART(yy,d)AND @m=DATEPART(m,d))SELECT CAST(COUNT(*)AS CHAR(1))FROM c UNION SELECT CAST(d AS CHAR(10))FROM c

I don't know if it is a valid answer though, since it outputs the number of sundays after the dates

Try it here

ungolfed:

DECLARE @m INT = 1,@y INT = 2017

DECLARE @ DATE=DATEADD(ww,-52*(2017-@y),'20170101')

IF DATEPART(d,@)>7
    SET @=DATEADD(ww,-1,@)

;WITH c(d)
AS
(SELECT d 
 FROM (SELECT DATEADD(ww,ROW_NUMBER()OVER(ORDER BY name)-1,@)d 
       FROM sys.stats) a 
 WHERE @y = DATEPART(yy,d)
   AND @m = DATEPART(m,d)
)

SELECT CAST(COUNT(*) AS CHAR(1))
FROM c 
UNION 
SELECT CAST(d AS CHAR(10))
FROM c
\$\endgroup\$
0
\$\begingroup\$

PHP, 127 118 112 107 bytes

for([,$y,$m]=$argv;$d++<date(t,($t=strtotime)($y.-$m));)date(w,$t($s="
$d.$m.$y"))?:$r.=$s.!++$c;echo$c,$r;

takes input from command line arguments; run with -r or test it online.

breakdown

for([,$y,$m]=$argv;                     # import arguments to $y and $m
    $d++<date(t,strtotime($y.-$m))      # loop while ($d < number of days in that month)
    ;)
    date(w,strtotime($s="\n$d.$m.$y"))?:    # if date(w) is falsy (0 == sunday)
        $r.=$s.!++$c;                       # then append date to $r and increment $c
echo$c,$r;                              # print result
\$\endgroup\$
0
\$\begingroup\$

Excel VBA, 190 bytes

Function p(y, m)
d = CDate("1/" & m & "/" & y)
e = DateAdd("m", 1, d)
Do While d < e
    If Weekday(d) = 1 Then Debug.Print d: i = i + 1
    d = d + 1
Loop
Debug.Print i
End Function

Sample Output for p(2000, 1) (not sure if this qualifies)

02-01-2000 
09-01-2000 
16-01-2000 
23-01-2000 
30-01-2000 
 5 
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.