29
\$\begingroup\$

Monday, October 31st, is Halloween. And it got me thinking -- I wonder what other months have the last day of the month also be a Monday?

Input

  • A positive integer in any convenient format representing a year, 10000 > y > 0.
  • The input can be padded with zeros (e.g., 0025 for year 25) if required.

Output

  • A list of the months of that year where the last day of the month is a Monday.
  • This can be as month names (e.g., January, March, October), or shortnames (Jan, Mar, Oct), or numbers (1, 3, 10), as separate lines or a list or delimited, etc., just so long as it's unambiguous to the reader.
  • The output format must be consistent:
    • For all years input (meaning, you can't output month names for some inputs, and month numbers for other inputs)
    • As well as consistent per output (meaning, you can't output 1 for January in the same output as Jul for July)
    • Basically, pick one format and stick to it.

Rules

  • Assume the Gregorian calendar for input/output, even down to y = 1.
  • Leap years must be properly accounted for (as a reminder: every year divisible by 4, except not years divisible by 100, unless also divisible by 400 -- 1700, 1800, 1900 all weren't leap years, but 2000 was).
  • You may use any built-ins or other date calculation tools you like.
  • Either a full program or a function are acceptable. If a function, you can return the output rather than printing it.
  • Standard loopholes are forbidden.
  • This is so all usual golfing rules apply, and the shortest code (in bytes) wins.

Examples

   1 --> Apr, Dec
 297 --> May
1776 --> Sep
2000 --> Jan, Jul
2016 --> Feb, Oct
3385 --> Jan, Feb, Oct

Leaderboard

var QUESTION_ID=97585,OVERRIDE_USER=42963;function answersUrl(e){return"https://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"https://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="<h1>"+e.body.replace(OVERRIDE_REG,"")+"</h1>")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a[2],language:a[1],link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/<a/.test(o)&&(o=jQuery(o).text()),s[o]=s[o]||{lang:e.language,user:e.user,size:e.size,link:e.link}});var t=[];for(var o in s)s.hasOwnProperty(o)&&t.push(s[o]);t.sort(function(e,s){return e.lang>s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i;
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table> </div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table> </div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table>

\$\endgroup\$
9
  • 1
    \$\begingroup\$ Related 1 and Related 2. \$\endgroup\$ Oct 26, 2016 at 18:33
  • 1
    \$\begingroup\$ Related but not duplicates or? \$\endgroup\$
    – ElPedro
    Oct 26, 2016 at 20:13
  • \$\begingroup\$ @ElPedro Related but not duplicates. The first does not allow any built-ins and asks for a fixed date/day combo (Friday the 13th), while the second asks for the last Sunday of every month of the year, limited between 1900 to 3015. \$\endgroup\$ Oct 26, 2016 at 20:17
  • \$\begingroup\$ Sorry @TimmD. My misunderstanding of your comment. \$\endgroup\$
    – ElPedro
    Oct 26, 2016 at 20:56
  • 1
    \$\begingroup\$ @ElPedro No problem! I would rather have a question and have it be clear, than to not have a question and have something unclear. \$\endgroup\$ Oct 26, 2016 at 20:57

39 Answers 39

18
\$\begingroup\$

JavaScript (Firefox 30+), 112 109 103 95 bytes

Look ma, no built-ins!

y=>[for(m of(i=0,y%4|y%400*!(y%100)&&6)+"63153042641")if((i++,y+(y>>2)-(y/100|0)*3/4|0)%7==m)i]

Here's a 107-byte ES6 version:

y=>[...(y%4|y%400*!(y%100)&&6)+"63153042641"].map((m,i)=>(y+(y>>2)-(y/100|0)*3/4|0)%7-m?0:i+1).filter(x=>x)

And here's my previous attempt, 123 113 bytes of ES6:

y=>[(l=y%4|y%400*!(y%100))?[7]:[1,7],[4,12],[9],[3,6],[8,11],[5],l?[1,2,10]:[2,10]][(y+(y>>2)-(y/100|0)*3/4|0)%7]

Explanation

The day of the week of a particular year is calculated like so:

y+(y>>2)-(y/100|0)*3/4|0)%7

In other words:

  • Take y.
  • Add the number of 4th years before y (y>>2).
  • Subtract the number of 100th years before y (y/100|0).
  • Add back in the number of 400th years before y; this is 1/4 of y/100|0, so we use *3/4|0.

Then we modulo the result by 7. If we let 0 mean Sunday, 1 mean Monday, etc., the result corresponds to the day of the week of December 31st of that year. Therefore, for December, we want to check if the result is 1. This gives us the last char in the string.

The last day of November is 31 days before the last day of December. This means that for the last day of November to be a Monday, Dec 31 needs to be a (1 + 31) % 7 = 4 = Thursday.

This procedure is repeated until we get back to March (a 3). Whether or not there is a leap day, the last day of February is 31 days before the last day of March, so we can calculate that too (it's (3 + 31) % 7 = 6). The tricky part is finding the correct value for January:

  • If it is a leap year, the last day of January is 29 days before the last day of Feb, resulting in (6 + 29) % 7 = 0.
  • Otherwise, it is 28 days before the last day of Feb, resulting in (6 + 28) % 7 = 6.

We can calculate whether or not it is a leap year with the following snippet:

!(y%400)|y%100*!(y%4)

This gives 0 if y is not a leap year, and a positive integer otherwise. This leads us to

!(y%400)|y%100*!(y%4)?0:6

for calculating the day for January. However, we can do better by reversing the conditions:

y%4|y%400*!(y%100)?6:0

Since the falsy result is always 0 anyway, we can reduce it to

y%4|y%400*!(y%100)&&6

saving one more precious byte.

Putting it all together, we loop through each char in the string, checking if each is equal to the day of the week of Dec 31st. We keep the indexes of the ones that match, returning this array in the end. And that is how you do leap year calculations without built-ins.

\$\endgroup\$
8
  • \$\begingroup\$ Owww... My brain, did you account for leap years in alla that? \$\endgroup\$ Oct 26, 2016 at 19:54
  • 2
    \$\begingroup\$ @carusocomputing That's what !(y%4)*y%100|!(y%400) is for. every year divisible by 4, except not years divisible by 100, unless also divisible by 400 \$\endgroup\$
    – mbomb007
    Oct 26, 2016 at 20:06
  • \$\begingroup\$ Hopefully y+(y>>2)+(z=y/25>>2)+(z>>2) still saves you a byte. \$\endgroup\$
    – Neil
    Oct 26, 2016 at 20:16
  • \$\begingroup\$ @Neil Thanks, but I found a better way :-) \$\endgroup\$ Oct 26, 2016 at 20:47
  • \$\begingroup\$ Nice; I saved 6 bytes on my Batch port using (y*5/4-(y/100)*3/4). \$\endgroup\$
    – Neil
    Oct 26, 2016 at 21:16
11
\$\begingroup\$

JavaScript (Firefox 30-57), 67 65 64 63 61 bytes

y=>[for(_ of(m='')+1e11)if(new Date(y+400,++m).getDay()==2)m]

Saved 2 4 6 bytes thanks to @ETHproductions. Saved another byte by outputting the months in reverse order.

\$\endgroup\$
11
  • \$\begingroup\$ I think you can save 2 bytes by winging it without .keys(): y=>[for(_ of(m=0,Array(12)))if(new Date(y+400,++m).getDay()==2)m] \$\endgroup\$ Oct 27, 2016 at 0:33
  • \$\begingroup\$ @ETHproductions I can save a further byte by reversing the order! \$\endgroup\$
    – Neil
    Oct 27, 2016 at 7:56
  • \$\begingroup\$ Reverse order is fine. Formatting the output isn't the interesting part of this challenge. \$\endgroup\$ Oct 27, 2016 at 12:36
  • \$\begingroup\$ What's our policy on Array Comprehensions now that they've been removed from the spec? \$\endgroup\$
    – bren
    Oct 27, 2016 at 12:43
  • \$\begingroup\$ You can save another 2 bytes by skipping Array(12) altogether: y=>[for(_ of(m=0,1e11+""))if(new Date(y+400,++m).getDay()==2)m] \$\endgroup\$ Oct 27, 2016 at 14:17
9
\$\begingroup\$

MySQL, 183 134 129 106 bytes

SET @y=2016;SELECT help_topic_id AS m FROM mysql.help_topic HAVING m BETWEEN 1 AND 12 AND 2=DAYOFWEEK(LAST_DAY(CONCAT(@y,-m,-1)))

Replace 2016 with the desired year. Run.

Rev. 2: Used the help_topics table in the default installation instead of creating a temporary table.

Rev.3: Adopted aross´s - trick and noticed I can also omit the quotes for "-1".
However, -1 is required in MySQL: I need a full date.

Rev.4: Restriction m BETWEEN 1 AND 12 could be done as m>0 AND m<13 (-6), but is not needed at all - invalid values will be ignored; warnings will be counted but not listed.

\$\endgroup\$
7
  • \$\begingroup\$ You need really the table shema mysql? mariadb.com/kb/en/mariadb/mysqlhelp_topic-table \$\endgroup\$ Oct 27, 2016 at 20:20
  • \$\begingroup\$ @JörgHülsermann I don´t get your point. \$\endgroup\$
    – Titus
    Oct 28, 2016 at 11:01
  • \$\begingroup\$ Should FROM help_topic without mysql. work? I have try it not \$\endgroup\$ Oct 28, 2016 at 11:10
  • \$\begingroup\$ @JörgHülsermann only if you prepend USE mysql; The correct database must be selected somehow. \$\endgroup\$
    – Titus
    Oct 28, 2016 at 12:38
  • \$\begingroup\$ will this work for year 999 and earlier ? \$\endgroup\$ Nov 3, 2020 at 11:31
5
\$\begingroup\$

Perl, 64 bytes

Includes +1 for -n

Give input on STDIN:

perl -M5.010 mon.pl <<< 2016

mon.pl:

#!/usr/bin/perl -n
map$b.=$/.gmtime$_.e4,-7e6..3e7;say$b=~/on (\S+ )\S.* $_.* 1 /g
\$\endgroup\$
5
\$\begingroup\$

Batch, 160 152 bytes

@set/ay=%1,m=0,j=6*!(!(y%%4)*(y%%100)+(y%%400)),y=(y*5/4-y/100*3/4)%%7
@for %%d in (%j% 6 3 1 5 3 0 4 2 6 4 1)do @set/am+=1&if %%d==%y% call echo %%m%%

Port of @ETHproduction's answer. With month abbreviations for 197 189 bytes:

@set/ay=%1,j=6*!(!(y%%4)*(y%%100)+(y%%400)),y=(y*5/4-y/100*3/4)%%7
@for %%m in (Jan.%j% Feb.6 Mar.3 Apr.1 May.5 Jun.3 Jul.0 Aug.4 Sep.2 Oct.6 Nov.4 Dec.1)do @if %%~xm==.%y% call echo %%~nm
\$\endgroup\$
5
\$\begingroup\$

Mathematica, 62 57 bytes

DayName@DayRange[{#},{#+1},"EndOfMonth"]~Position~Monday&

Anonymous function. Takes a number as input and returns a list of single-element lists of numbers as output. I'm honestly not sure myself how it works anymore.

\$\endgroup\$
5
\$\begingroup\$

Perl+cal, 46 bytes

say`cal $_ $ARGV[0]`=~/\n.{5}\n/&&$_ for 1..12

Example:

$ perl -E 'say`cal $_ $ARGV[0]`=~/\n.{5}\n/&&$_ for 1..12' 2016

2







10


$
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Strictly speaking, this is perl + cal, not just perl :-p. For example, my Windows machine has perl, but this won't work there. \$\endgroup\$
    – philomory
    Oct 26, 2016 at 21:26
  • \$\begingroup\$ Fair point, updated this and my bash attempt. \$\endgroup\$
    – steve
    Oct 26, 2016 at 21:31
4
\$\begingroup\$

J, 48 34 33 bytes

[:I.(2=7|_2#@".@,@{.])&>@calendar

Saved 15 bytes with help from @Adám.

Uses the calendar builtin to generate an array of strings representing the months, then parses each string to determine the whether the last Monday is the last day of the month. It outputs each month as the month number of each. That is, Jan = 0, Feb = 1, ..., Dec = 11.

The output of calendar is

   _3 ]\ calendar 2016
┌─────────────────────┬─────────────────────┬─────────────────────┐
│         Jan         │         Feb         │         Mar         │
│ Su Mo Tu We Th Fr Sa│ Su Mo Tu We Th Fr Sa│ Su Mo Tu We Th Fr Sa│
│                 1  2│     1  2  3  4  5  6│        1  2  3  4  5│
│  3  4  5  6  7  8  9│  7  8  9 10 11 12 13│  6  7  8  9 10 11 12│
│ 10 11 12 13 14 15 16│ 14 15 16 17 18 19 20│ 13 14 15 16 17 18 19│
│ 17 18 19 20 21 22 23│ 21 22 23 24 25 26 27│ 20 21 22 23 24 25 26│
│ 24 25 26 27 28 29 30│ 28 29               │ 27 28 29 30 31      │
│ 31                  │                     │                     │
├─────────────────────┼─────────────────────┼─────────────────────┤
│         Apr         │         May         │         Jun         │
│ Su Mo Tu We Th Fr Sa│ Su Mo Tu We Th Fr Sa│ Su Mo Tu We Th Fr Sa│
│                 1  2│  1  2  3  4  5  6  7│           1  2  3  4│
│  3  4  5  6  7  8  9│  8  9 10 11 12 13 14│  5  6  7  8  9 10 11│
│ 10 11 12 13 14 15 16│ 15 16 17 18 19 20 21│ 12 13 14 15 16 17 18│
│ 17 18 19 20 21 22 23│ 22 23 24 25 26 27 28│ 19 20 21 22 23 24 25│
│ 24 25 26 27 28 29 30│ 29 30 31            │ 26 27 28 29 30      │
│                     │                     │                     │
├─────────────────────┼─────────────────────┼─────────────────────┤
│         Jul         │         Aug         │         Sep         │
│ Su Mo Tu We Th Fr Sa│ Su Mo Tu We Th Fr Sa│ Su Mo Tu We Th Fr Sa│
│                 1  2│     1  2  3  4  5  6│              1  2  3│
│  3  4  5  6  7  8  9│  7  8  9 10 11 12 13│  4  5  6  7  8  9 10│
│ 10 11 12 13 14 15 16│ 14 15 16 17 18 19 20│ 11 12 13 14 15 16 17│
│ 17 18 19 20 21 22 23│ 21 22 23 24 25 26 27│ 18 19 20 21 22 23 24│
│ 24 25 26 27 28 29 30│ 28 29 30 31         │ 25 26 27 28 29 30   │
│ 31                  │                     │                     │
├─────────────────────┼─────────────────────┼─────────────────────┤
│         Oct         │         Nov         │         Dec         │
│ Su Mo Tu We Th Fr Sa│ Su Mo Tu We Th Fr Sa│ Su Mo Tu We Th Fr Sa│
│                    1│        1  2  3  4  5│              1  2  3│
│  2  3  4  5  6  7  8│  6  7  8  9 10 11 12│  4  5  6  7  8  9 10│
│  9 10 11 12 13 14 15│ 13 14 15 16 17 18 19│ 11 12 13 14 15 16 17│
│ 16 17 18 19 20 21 22│ 20 21 22 23 24 25 26│ 18 19 20 21 22 23 24│
│ 23 24 25 26 27 28 29│ 27 28 29 30         │ 25 26 27 28 29 30 31│
│ 30 31               │                     │                     │
└─────────────────────┴─────────────────────┴─────────────────────┘

Usage

   f =: [:I.(2=7|_2#@".@,@{.])&>@calendar
   f 1
3 11
   f 297
4
   f 1776
8
   f 2000
0 6
   f 2016
1 9
   f 3385
0 1 9

Explanation

[:I.(2=7|_2#@".@,@{.])&>@calendar  Input: year Y
                         calendar  Get 12 boxes each containing a month
    (                )&>@          Operate on each box
                    ]                Identity, get the box
         _2       {.                 Take the last two strings
                ,@                   Flatten it
             ".@                     Parse it into an array of integers
           #@                        Get the length
       7|                            Take it modulo 7
     2=                              Test if it equals 2 - it will either
                                     have two days or 9 days in the last
                                     two lines if the end is on a Monday
[:I.                               Return the indices containing a true value
\$\endgroup\$
7
  • \$\begingroup\$ wait, does calendar actually output ascii art? \$\endgroup\$ Oct 26, 2016 at 23:14
  • \$\begingroup\$ @DestructibleWatermelon To be exact, the output format of calendar is an array of 12 boxes where each box contains a 2d array of characters \$\endgroup\$
    – miles
    Oct 26, 2016 at 23:18
  • \$\begingroup\$ I don't even know how to do "each" in J, but this is already much shorter: I.7=;#&.>".&.>,&.>_2{.&.>calendar 2016 If you combine all the "under-open"s you should be able to get it pretty short. \$\endgroup\$
    – Adám
    Oct 27, 2016 at 9:47
  • \$\begingroup\$ @Adám Thanks, it uses a better method but it's not a verb in J. I think it will still help though \$\endgroup\$
    – miles
    Oct 27, 2016 at 9:53
  • \$\begingroup\$ My intention was only to inspire. I know it isn't a verb. \$\endgroup\$
    – Adám
    Oct 27, 2016 at 9:58
4
\$\begingroup\$

C, 119 bytes

t=1248700335,m;main(y){for(scanf("%d",&y),t+=y&3||y%25<1&&y&15;m++,(6+y+y/4-y/100+y/400+t)%7||printf("%d,",m),t;t/=7);}

This uses a table that contains the offset of the weekdays of the last day of every month for a leap year, encoded in a signed 32-bit word using base 7. If it is not a leap year we add 1 to the offset of January (as you can see y&3||y%25<1&&y&15 is used to check for years without leap days). Then we simply loop through every month and check if its last day is a Monday. Quite simple actually, no ugly hacks or tricks. Here it is slightly ungolfed:

t=1248700335,m;
main(y){
  for(
    scanf("%d",&y),t+=y&3||y%25<1&&y&15;
    m++,(6+y+y/4-y/100+y/400+t)%7||printf("%d,",m),t;
    t/=7
  );
}

I might revisit this to rewrite it as a function to save a few characters. The printf also takes up a little too much space...

\$\endgroup\$
2
  • \$\begingroup\$ The printf("%d, ", m) would print something as 1, or 2, 3, so there is always one ',' more... I prefer use only spaces \$\endgroup\$
    – user58988
    Oct 30, 2016 at 15:51
  • \$\begingroup\$ Indeed, I also prefer spaces in the output actually, but I usually write my golfed C solutions so that they don't need any whitespace, so I can just nuke all whitespace from my half-golfed version when I want to check my character count. \$\endgroup\$
    – Fors
    Oct 30, 2016 at 17:00
4
\$\begingroup\$

Java 7 ,186 182 172 bytes

Thanks to kevin for saving 4 bytes
Thanks to @cliffroot for saving 10 bytes

int[]f(int n){int c=n-1,x=c*365+c/4+c/400-c/100,k=0,b[]={3,(n%4<1&n%100>0)|n%400<1?1:0,3,2,3,2,3,3,2,3,2,3},a[]=new int[12];for(int i:b)a[k++]=(x+=i+28)%7==1?1:0;return a;}

ungolfed

int[] f(int n) {
 int c=n-1,x=c*365+(c/4)+(c/400)-(c/100),k=0,
   b[] = {3,(n % 4 < 1 & n % 100 > 0) | n % 400 < 1 ? 1 : 0
                                     ,3,2,3,2,3,3,2,3,2,3},a = new int[ 12 ];

 if ( (n % 4 < 1 & n % 100 > 1) | n % 400 < 1 )
     b[ 1 ] = -1;
 for (int i : b)
    a[ k++ ] = (x += i + 28) % 7 == 1 ? 1 : 0;

return a;
     }

This version is provide by @cliffroot(168 bytes)

 static int[] f(int n) {
 int b = 13561787 | ( (n%4 < 1 & n%100 > 0) | n%400 < 1 ? 1 << 20 : 0 ),
           x = --n*365 + n/4 + n/400 - n/100,a[]=new int[12],k=0;
    while (k < 12)
    a[k++] = (x += (b >> 24 - k*2&3 ) + 28) % 7 == 1 ? 1 : 0;
  return a;   }
    }

output sample

1 1 0 0 0 0 0 0 0 1 0 0(for input 3385)
\$\endgroup\$
7
  • 1
    \$\begingroup\$ After I wrote my answer I knew calculating everything yourself would be shorter.. :) Btw, you can golf n%4==0 to n%4<1; n%400==0 to n%400<1 and int c=...;int[]b=...,a=... to int c=...,b[]=...,a[]=.... \$\endgroup\$ Oct 27, 2016 at 9:48
  • 1
    \$\begingroup\$ b and a can be defined in the int part like this: int ... ,b[]=...,a[]=... \$\endgroup\$ Oct 27, 2016 at 9:50
  • 1
    \$\begingroup\$ int[]f(int n){int x=--n*365+n/4+n/400-n++/100,k=0,b[]={1,(n%4<1&n%100>0)|n%400<1?-1:-2,1,0,1,0,1,1,0,1,0,1},a[]=new int[12];for(int i:b)a[k++]=(x+=i+30)%7==1?1:0;return a;} few bytes saved \$\endgroup\$
    – cliffroot
    Oct 27, 2016 at 13:18
  • 1
    \$\begingroup\$ can also change b to b[]={3,(n%4<1&n%100>0)|n%400<1?1:0,3,2,3,2,3,3,2,3,2,3} and i+30 to i+28 for 2 more bytes \$\endgroup\$
    – cliffroot
    Oct 27, 2016 at 13:24
  • 1
    \$\begingroup\$ and another 3 bytes int[]f(int n){int b=13561787|((n%4<1&n%100>0)|n%400<1?1<<20:0),x=--n*365+n/4+n/400-n/100,a[]=new int[12],k=0;while(k<12)a[k++]=(x+=(b>>24-k*2&3)+28)%7==1?1:0;return a;} \$\endgroup\$
    – cliffroot
    Oct 27, 2016 at 14:43
3
\$\begingroup\$

MATL, 21 bytes

12:"G@QhO6(YO9XO77=?@

Months are displayed as numbers.

Try it online! Or verify all test cases.

Explanation

This uses date conversion builtin functions. For the given year it tests which months' last day is Monday.

Instead of explicitly specifying the last day of month k (which may be 28, 29, 30 or 31), we specify the 0-th day of month k+1, which is equivalent and does not depend on month or year.

12:      % Push [1 2 ... 12] (months)
"        % For each month k
  G      %   Push input
  @Q     %   Push k+1
  h      %   Concatenate
  O6(    %   Postpend four zeros. For example, for input 2016 and month k=1 
         %   (first iteration) this gives [2016 2 0 0 0 0] (year, month, day,
         %   hour, min, sec). The 0-th day of month k+1 is the same as the
         %   last day of month k.
  YO     %   Convert the above 6-element date vector to date number
  9XO    %   Convert date number to date string with output format 9, which 
         %   is weekday as a capital letter
  77=    %   Is it an 'M'?
  ?      %   If so
    @    %     Push current month (will be implicitly displayed)
\$\endgroup\$
3
\$\begingroup\$

Bash + GNU utilities, 56 bytes

seq -f1month-1day$1-%g-1 12|date -f- +%B%u|sed -n s/1//p

Appears to require date version 8.25. The 8.23 version in Ideone doesn't cut it.

\$\endgroup\$
3
\$\begingroup\$

Excel, 537 bytes

Because – you know – Excel!

Takes input year in A1. Returns hexadecimal list of months; 1=January, C= December. Since each month is a single digit, no separator is needed.

=IF(2=WEEKDAY(EOMONTH(DATE(A1,1,1),0)),1,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,2,1),0)),2,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,3,1),0)),3,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,4,1),0)),4,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,5,1),0)),5,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,6,1),0)),6,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,7,1),0)),7,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,8,1),0)),8,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,9,1),0)),9,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,10,1),0)),"A","")&IF(2=WEEKDAY(EOMONTH(DATE(A1,11,1),0)),"B","")&IF(2=WEEKDAY(EOMONTH(DATE(A1,12,1),0)),"C","")

Example: A1 contains 2016. B1 contains the above formula, and displays as 2A, meaning February and October.

\$\endgroup\$
3
\$\begingroup\$

PHP, 109 180 159 bytes

for($z=$argv[1];$m++<12;)if(date(N,strtotime(sprintf("%04d-$m-",$z).cal_days_in_month(0,$m,$z)))<2)echo"$m,";
  • Outputs the provided year, not all of them (... always read the question)
  • Ignored notices (thanks Titus)
  • Change while to for as it's now a single year (again, thanks Titus)

Old 2

$z=0;while($z++<9999){$o=[];$m=0;while($m++<12)if(date("N",strtotime(sprintf("%04d-$m-","$z").cal_days_in_month(0,$m,$z)))<2)$o[]=$m;echo count($o)>0?"$z:".implode(",",$o)."
":"";}

Supports all years from dot to 10000, also got rid of an undefined var warning I wasn't aware of on one PC. Yes it's longer than the old version, but it's more robust.

Old 1

while($z++<9999){$o=[];$m=0;while($m++<12)if(date("N",strtotime("$z-$m-".cal_days_in_month(0,$m,$z)))<2)$o[]=$m;echo count($o)>0?"$z:".implode(",",$o)."
":"";}

If running on Windows or a 32bit system there will be the dreaded 2038 bug, but on a 64bit linux system it's fine.

I did attempt to use date("t"... which is meant to represent the last date of the given month, but the results didn't match those previously mentioned in this thread.

\$\endgroup\$
2
  • 2
    \$\begingroup\$ -2: "$z" needs no quotes -7: ignore the notices (they not printed with default settings: do not init $z, no quotes for N) -1: for instead of while -43: take input as requested instead of looping through the years -3: join instead of implode -16: direct output: for($z=$argv[1];$m++<12;)if(date(N,strtotime(sprintf("%04d-$m-",$z).cal_days_in_month(0,$m,$z)))<2)echo"$m,"; +9 if you insist on having no trailing comma: echo$o=$o?",$m":$m; \$\endgroup\$
    – Titus
    Oct 27, 2016 at 9:10
  • \$\begingroup\$ Ahh misread the question! Thought it was for all years.. oops :B Thanks for the other suggestions as well, will get on them \$\endgroup\$
    – CT14.IT
    Oct 27, 2016 at 9:22
3
\$\begingroup\$

PHP, 92 Bytes

for($d=new DateTime("$argv[1]-1-1");$i++<12;)$d->modify("1month")->format(w)!=2?:print"$i,";

check 12 times 1 month after first day of a year is a tuesday. If it is then is the day before the last day in the month is a monday.

\$\endgroup\$
2
  • \$\begingroup\$ You could use echo instead of print and save 1 \$\endgroup\$
    – Octopus
    Oct 28, 2016 at 15:34
  • 2
    \$\begingroup\$ @Octopus not inside the ternary Operator \$\endgroup\$ Oct 28, 2016 at 15:37
3
\$\begingroup\$

C, 214 bytes

main(int a,char *b[]){for(int x,y,d,m=12;m;m--){y=atoi(b[1]);x=m-1;d=x==1?(y%4==0?(y%100==0?(y%400==0?29:28):29):28):(x==3||x==5||x==10?30:31);if((d+=m<3?y--:y-2,23*m/9+d+4+y/4-y/100+y/400)%7==1)printf("%d\n",m);}}

Compile

gcc -std=c99 -o foo foo.c

Ungolfed

With credits to the relevant gurus.

Michael Keith and Tom Craver for C Program to find day of week given date.

Collin Biedenkapp for Q&A: How do I figure out what the last day of the month is?

/* credit to Collin Biedenkapp */
short _get_max_day(short x, int z) {
    if(x == 0 || x == 2 || x == 4 || x == 6 || x == 7 || x == 9 || x == 11)
        return 31;
    else if(x == 3 || x == 5 || x == 8 || x == 10)
        return 30;
    else {
        if(z % 4 == 0) {
            if(z % 100 == 0) {
                if(z % 400 == 0)
                    return 29;
                return 28;
            }
            return 29;
        }
        return 28;
    }
}

main(int argc,char *argv[]) {
 for(int y,d,m=12;m;m--) {
  y=atoi(argv[1]);
  d=_get_max_day(m-1,y);
  /* credit to Michael Keith and Tom Craver */
  if ((d+=m<3?y--:y-2,23*m/9+d+4+y/4-y/100+y/400)%7 == 1)
    printf("%d\n",m);
 }
}
\$\endgroup\$
5
  • 1
    \$\begingroup\$ What if you flip your if the other direction, to have your else return 31, and therefore you can eliminate the big == chain? \$\endgroup\$ Oct 27, 2016 at 18:33
  • 1
    \$\begingroup\$ would be better if(x==1) {z part}else if(x==3|| x == 5 || x == 8 || x == 10)return 30 else return 31 \$\endgroup\$
    – user58988
    Oct 27, 2016 at 22:14
  • 1
    \$\begingroup\$ what about: return x==1?(z%4==0?(z%100==0?(z%400==0?29:28):29):28):(x==3||x==5||x==8||x==10?30:31) \$\endgroup\$
    – user58988
    Oct 27, 2016 at 22:26
  • \$\begingroup\$ TimmyD + RosLuP : thanks for the return() points, 100 bytes now saved. \$\endgroup\$
    – steve
    Oct 28, 2016 at 7:45
  • 1
    \$\begingroup\$ it is possible continue to reduce at last until this: u(y,m){return m-1?30+((2773>>m)&1):28+(y%4==0&&y%100||y%400==0);} where y is the year and m the month \$\endgroup\$
    – user58988
    Oct 28, 2016 at 21:45
3
\$\begingroup\$

PHP, 96 95 76 71 69 64 61 bytes

Note: year numbers must be padded to 4 chars, like 0070.

for(;13+$i-=1;)date(N,mktime(0,0,0,1-$i,0,$argn))-1||print$i;

Run like this:

echo 3385 | php -nR 'for(;13+$i-=1;)date(N,mktime(0,0,0,1-$i,0,$argn))-1||print$i;';echo
> -1-2-10

Explanation

Iterates from -1 to -12. Create date using mktime, day 0 (the last day of the previous month) and month 2..13. Format the date as day number, and if the result is 1, print the current number. The negative sign - is used as the delimiter.

The Millenium Bug Strikes Again!

Note that with this version, the range 0..100 is interpreted as 1970..2069. This is no problem for the range 0..69, as weeks have a pattern that repeats every 400 years (146097 days, exactly 20871 weeks), but for the range 70..99, 1900 is added to the year number, which is not a multiple of 400. To fix that problem JUST for 30 year numbers in a range of 10k, the simplest way is to add 400 to the year number to prevent the 2-digit interpretation (+4 bytes):

for(;13+$i-=1;)date(N,mktime(0,0,0,1-$i,0,$argn+400))-1||print$i;

Tweaks

  • Saved a byte by using !~-$i to compare $i with 1 (-1 binary negated is 0, logically negated is true; every other number is false), so parentheses aren't needed
  • Saved 19 bytes by using last day ofYYYY-m notation to create the date
  • Saved 5 bytes by using date and strtotime instead of date_create
  • Saved 2 bytes by counting from negative numbers, using the negative sign as output delimiter (negative month numbers don't exist) and also as delim in the YYYY-m part of the date
  • Saved 5 bytes by using mktime instead of strtotime. Reverted to using day 0 (mktime also supports month 13, so 0-13==31-12)
  • Saved 3 bytes by using -R to make $argn available
\$\endgroup\$
4
  • \$\begingroup\$ mktime removes the necessity to pad the year, doesn´t it? \$\endgroup\$
    – Titus
    Oct 28, 2016 at 13:09
  • \$\begingroup\$ @Titus, sharp. Well I just figured out that mktime is counter-intuitive, because the arguments are taken as INTs. That means you can't pad the year... so everything in range 0..100 is interpreted as 1970..2070. That is no problem for the range 0..70 because 400 years have an exact number of weeks (so calendars repeat the pattern every 400 years), but 70..99 adds 1900 (not a multiple of 400!). Therefore new ver. has a bug. \$\endgroup\$
    – aross
    Oct 28, 2016 at 13:14
  • \$\begingroup\$ Only solution I see for that right now is$argv[1]+400 ... unless Julian and Gregorian weekdays differ. \$\endgroup\$
    – Titus
    Oct 28, 2016 at 13:22
  • \$\begingroup\$ @Titus, yep. Rules say use Gregorian cal \$\endgroup\$
    – aross
    Oct 28, 2016 at 13:27
3
\$\begingroup\$

Excel, 428 97 96 bytes

Input in A1. Output un-separated Hexadecimal values (January = 0, December = B)

=IF(2=WEEKDAY(DATE(A1+2000,1,31)),0,"")&CHOOSE(WEEKDAY(DATE(A1+2000,3,0)),4,19,6,"3B",8,25,"7A")

Added 10 bytes ("+2000") to allow handling of pre-1990 dates.

Saved 11 bytes thanks to @Engineer Toast.


First attempt (428 bytes), borrowing heavily from @Adám's solution.

=IF(2=WEEKDAY(DATE(A1,1,31)),1,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,2,1),0)),2,"")&IF(2=WEEKDAY(DATE(A1,3,31)),3,"")&IF(2=WEEKDAY(DATE(A1,4,30)),4,"")&IF(2=WEEKDAY(DATE(A1,5,31)),5,"")&IF(2=WEEKDAY(DATE(A1,6,30)),6,"")&IF(2=WEEKDAY(DATE(A1,7,31)),7,"")&IF(2=WEEKDAY(DATE(A1,8,31)),8,"")&IF(2=WEEKDAY(DATE(A1,9,30)),9,"")&IF(2=WEEKDAY(DATE(A1,10,31)),"A","")&IF(2=WEEKDAY(DATE(A1,11,30)),"B","")&IF(2=WEEKDAY(DATE(A1,12,31)),"C","")
\$\endgroup\$
2
  • \$\begingroup\$ How does this work on years earlier than 1900? The test case 297 -> May returns 6 with this formula. Shouldn't it be 4? 1776 gives 7A instead of just 8 for September. \$\endgroup\$ May 23, 2017 at 12:19
  • \$\begingroup\$ If you get it to work, though, you can probably use Date(A1,3,0) instead of EOMONTH(DATE(A1,2,1),0) \$\endgroup\$ May 23, 2017 at 12:27
3
\$\begingroup\$

Python 2, 122 bytes

Ugh. Math with dates isn't as simple as I'd like.

from datetime import*
lambda y:[m+1for m in range(12)if(date(y,12,31)if m>10else(date(y,m+2,1)-timedelta(1))).weekday()<1]

Try it online

Same length:

from datetime import*
lambda y:[m-1for m in range(2,14)if(date(y,12,31)if m>12else(date(y,m,1)-timedelta(1))).weekday()<1]
\$\endgroup\$
3
  • \$\begingroup\$ I wasn't even going to try Python with this one. Nice effort. \$\endgroup\$
    – ElPedro
    Oct 26, 2016 at 20:44
  • \$\begingroup\$ You have to include the import statement in your bytecount. \$\endgroup\$ Nov 5, 2020 at 20:54
  • \$\begingroup\$ @pppery Way to notice something in an old post. Fixed. \$\endgroup\$
    – mbomb007
    Nov 5, 2020 at 21:29
2
\$\begingroup\$

Dyalog APL with dfns's cal, Version 15.0: 22; Version 16.0: 19 bytes

The cal function comes with a default install, just enter )copy dfns.

Version 15.0: ∊⎕{⍵/⍨2=≢⍎⊢⌿cal⍺⍵}¨⍳12

enlist (flatten)

⎕{... numeric input as left argument to the following anonymous function, taking each of the right side values as right argument in turn

⍵/⍨ the argument if (gives an empty list if not)

2= two (namely Sunday and Monday) is equal to

the tally of

the numbers in

⊢⌿ the bottom-most row of

cal the calendar for

⍺⍵ year left-argument, month right-argument, the latter being

⍳12 1 to 12

Version 16.0: ⍸2=⎕{≢⍎⊢⌿cal⍺⍵}¨⍳12

the indices where

2= two equals (namely Sunday and Monday)

⎕{... numeric input as left argument to the following anonymous function, taking each of the right side values as right argument in turn

the tally of

the numbers in

⊢⌿ the bottom-most row of

cal the calendar for

⍺⍵ year left-argument, month right-argument, the latter being

⍳12 1 to 12

\$\endgroup\$
2
\$\begingroup\$

Bash+cal, 58 bytes

$ cat t.sh
for A in {1..12};do cal $A $1|grep -qx .....&&echo $A;done
$ bash t.sh 2016
2
10
$
\$\endgroup\$
1
  • \$\begingroup\$ +1 - works for BSD cal (e.g. OSX), but watch for trailing spaces on GNU cal. \$\endgroup\$ Oct 27, 2016 at 1:06
2
\$\begingroup\$

Python 2, 94 bytes

from datetime import*
lambda y:[m for m in range(1,13)if date(y+(m>11),m%12+1,1).weekday()==1]

repl.it

An unnamed function, takes an integer year, outputs a list of the month numbers [1-12].

I also tried to beat the byte count with arithmetic without success (110 bytes). :

lambda y:map(lambda x,v:(23*((x+2)%13or 1)/9+y-2*(0<x<11)+(x>10)+v/4-v/100+v/400)%7==4,range(12),[y-1]+[y]*11)

An unnamed function which returns a list of boolean values representing if the months [Jan-Dec] end in a Monday

\$\endgroup\$
2
\$\begingroup\$

Java 7, 200 249 bytes

import java.util.*;String c(int y){String r="";GregorianCalendar c=new GregorianCalendar();c.setGregorianChange(new Date(1L<<63));c.set(1,y);c.set(2,0);for(int i=0;i++<12;c.add(2,1)){c.set(5,c.getActualMaximum(5));if(c.get(7)==2)r+=i+" ";}return r;}

In Java, GregorianCalendar is a mix between a Gregorian and Julian calendar. Because of this, year 1 gave incorrect results. Changing Calendar c=Calendar.getInstance(); to GregorianCalendar c=new GregorianCalendar();c.setGregorianChange(new Date(1L<<63)); fixes this by forcing a use of the Gregorian calendar only. Thanks to @JonSkeet on stackoverflow.com for explaining this to me.

Ungolfed & test code:

Try it here.

import java.util.*;
class M{
  static String c(int year){
    String r = "";
    GregorianCalendar calendar = new GregorianCalendar();
    calendar.setGregorianChange(new Date(Long.MIN_VALUE));
    calendar.set(Calendar.YEAR, year);
    calendar.set(Calendar.MONTH, 0);
    for(int i = 0; i++ < 12; calendar.add(Calendar.MONTH, 1)){
      calendar.set(Calendar.DATE, calendar.getActualMaximum(Calendar.DATE));
      if(calendar.get(Calendar.DAY_OF_WEEK) == 2){
        r += i+" ";
      }
    }
    return r;
  }

  public static void main(String[] a){
    System.out.println(c(1));
    System.out.println(c(297));
    System.out.println(c(1776));
    System.out.println(c(2000));
    System.out.println(c(2016));
    System.out.println(c(3385));
  }
}

Output:

4 12
5 
9 
1 7 
2 10 
1 2 10 
\$\endgroup\$
2
\$\begingroup\$

C#6 C#, 171 167 135 bytes

using System;
void d(int n){for(int i=0;++i<13;)if((int)new DateTime(n,i,DateTime.DaysInMonth(n,i)).DayOfWeek==1)Console.Write(i+" ");}

-32 bytes thanks to Shebang

Print months as numbers; with space delimited; with trailing space. Now this answer also works for earlier versions of C#.


Old, 167 bytes

using System;using System.Linq;
c(int n)=>string.Join(",",Enumerable.Range(1,12).Where(i=>new DateTime(n,i,DateTime.DaysInMonth(n,i)).DayOfWeek==(DayOfWeek)1));

-4 bytes thanks to TimmyD

Output months are numbers in return string, comma delimited

Ungolfed

string c(int n)=>
    string.Join(",",                                        // Join them with commas
        Enumerable.Range(1,12)                              // For 1-12 inclusive
        .Where(                                             // Select only
            i=>new DateTime(n,i,DateTime.DaysInMonth(n,i)   // Get last day of that year-month
            ).DayOfWeek                                     // Get its day of week
            ==(DayOfWeek)1                              // Is Monday
        )
    )
;
\$\endgroup\$
4
  • \$\begingroup\$ @TimmyD Yes but need explicit cast. Answer updated \$\endgroup\$
    – Link Ng
    Oct 27, 2016 at 13:59
  • \$\begingroup\$ LINQ is fun but this is 126 bytes: void q(int y){for(int m=1;m<13;m++){if((int)new DateTime(y,m,DateTime.DaysInMonth(y,m)).DayOfWeek==1){Console.WriteLine(m);}}} ;) Also, it would be shorter to cast the DayOfWeek to int than it would be to cast the int to DayOfWeek \$\endgroup\$
    – Kade
    Oct 27, 2016 at 14:57
  • \$\begingroup\$ @Shebang Thanks. I really shouldn't golf in one-line linq --- Only Jon Skeet can do that. See if I have time for update tomorrow. Tired now. \$\endgroup\$
    – Link Ng
    Oct 27, 2016 at 15:15
  • \$\begingroup\$ You can convert this to be an Action<int> to save some bytes \$\endgroup\$ Nov 16, 2016 at 13:37
2
\$\begingroup\$

Ruby, 54 + 6 = 60 bytes

λ cat monday.rb
p (1..12).select{|m|Date.new($*[0].to_i,m,-1).monday?}
λ ruby -rdate monday.rb 2016
[2, 10]

6 bytes for -rdate on the command line to get the Date class from the standard library.

Explanation: pretty straightforward thanks to the Ruby stdlib's great Date class. Not only does it have methods like monday?, tuesday?, etc, the constructor will take negative numbers for any field past year to mean 'count this field backwards from the end of the period represented by the previous field'. $* is shorthand for ARGV, so $*[0] is a quick way to get the first command line argument.

\$\endgroup\$
2
\$\begingroup\$

R, 106 99 95 83 78 77 74 bytes

g=function(x)which(format(seq(as.Date(paste0(x,-2,-1)),,'m',12)-1,"%u")<2)

The sequence of last days of each month is given by seq(as.Date(paste0(x,-2,-1)),,'m',12)-1:

  • paste0 coerces -2 and -1 to characters. If the x was 2016 for instance, paste0(x,-2,-1) gives "2016-2-1" which is then converted to the 1st of February 2016 by as.Date.

  • seq applied to a POSIXct or a Date object is seq(from, to , by, length.out): here to is not given, by is given as 'm' which is matched to 'month' thanks to partial matching, and length.out is of course 12.

  • The resulting sequence is the first day of the 12 months starting with February of the year in question. -1 gives us then the last day of the 12 months starting with January of the year in question.

Test cases:

> g(1)
[1]  4 12
> g(25)
[1] 3 6
> g(297)
[1] 5
> g(2000)
[1] 1 7
> g(2016)
[1]  2 10
> g(3385)
[1]  1  2 10
> g(9999)
[1] 5

Old version at 95 bytes, outputting the month names instead of just their numbers:

g=function(x)format(S<-seq(as.Date(sprintf("%04i-02-01",x)),,'m',12)-1,"%B")[format(S,"%u")==1]
\$\endgroup\$
2
  • \$\begingroup\$ This answer is just brilliant. I had no idea seq had a method for Date -objects and this solves the issue of as.Date not handling years above 10000 in my deleted answer. \$\endgroup\$
    – Billywob
    Oct 27, 2016 at 9:44
  • \$\begingroup\$ @Billywob yes seq.Date and seq.POSIXt are quite impressive: they can even process commands such as seq(time1, time2, by="10 min") or seq(date1, date2, by="quarter"). Very useful when plotting a time-series. \$\endgroup\$
    – plannapus
    Oct 27, 2016 at 10:25
2
\$\begingroup\$

Japt, 24 bytes

Do1 £Ov"Ð400+U"+X e ¥2©X

Test it online! Outputs an array of numbers, with false in place of months that don't end in a Monday.

There was a bug in the interpreter that didn't allow me to use Ð in the function body £. After the bug fix and another feature addition, this is 18 bytes in the current commit:

Do1@Ð400+UX e ¥2©X
\$\endgroup\$
1
\$\begingroup\$

Java, 143 129 bytes

This uses the new time API of Java 8.

y->{String s="";for(int m=0;++m<13;)if(java.time.YearMonth.of(y,m).atEndOfMonth().getDayOfWeek().ordinal()==0)s+=m+" ";return s;}

Output

Note that each line has an extra space at the end.

4 12 
5 
9 
1 7 
2 10 
1 2 10 

Ungolfed and testing

import java.time.*;
import java.util.function.*;

public class Main {
    public static void main (String[] args) {
        IntFunction<String> func = year -> {
          String result = "";
          for (int month=1; month <= 12; month++) {
            if (YearMonth.of(year, month).atEndOfMonth().getDayOfWeek().ordinal() == 0) {
              result += month + " ";
            }
          }
          return result;
        };
        System.out.println(func.apply(1));
        System.out.println(func.apply(297));
        System.out.println(func.apply(1776));
        System.out.println(func.apply(2000));
        System.out.println(func.apply(2016));
        System.out.println(func.apply(3385));
    }
}

Shaves

  1. 143 to 129 bytes: use DayOfWeek::ordinal to compare with a numerical constant instead of the enum constant.
    Thanks @TimmyD for the general idea if not the exact solution! ;-)
\$\endgroup\$
3
  • \$\begingroup\$ @TimmyD sadly, it's an enum. It does have a getValue() method, though, which would save a few bytes. \$\endgroup\$
    – Celos
    Oct 27, 2016 at 13:03
  • \$\begingroup\$ @Celos ordinal() saves 1 more byte compared to getValue(), even though it is suggested to never use it. \$\endgroup\$ Oct 27, 2016 at 13:08
  • \$\begingroup\$ yes, good thinking. I posted my comment without first refreshing, so I didn't see your reply and edit. \$\endgroup\$
    – Celos
    Oct 27, 2016 at 14:11
1
\$\begingroup\$

GNU awk, 80 bytes

{for(;m<13;a=mktime($0" "++m" 1 9 0 0")){if(strftime("%w",a-8e4)~1){print m-1}}}

Example

$ gawk '{for(;m<13;a=mktime($0" "++m" 1 9 0 0")){if(strftime("%w",a-8e4)~1){print m-1}}}' <<<2016
2
10
$
\$\endgroup\$
1
\$\begingroup\$

PHP, 109 bytes

$y=$argv[1];for($i;++$i<13;)echo(date('N',strtotime($y."-$i-".date('t',strtotime("$y-$i-1"))))==1?"$i ":'');

The code produces a notice due to for($i; but the question mentions nothing about avoiding errors.


Outputs months numbers separated by a space.

   1 --> 1 12 
 297 --> 5 
1776 --> 9 
2000 --> 1 7 
2016 --> 2 10 
3385 --> 1 2 10 

Works in PHP 5.2.16 and onward at http://sandbox.onlinephpfunctions.com/

\$\endgroup\$
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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