The Last Monday

27

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>

AdmBorkBork

Posted 2016-10-26T18:32:28.180

Reputation: 41 581

1Related 1 and Related 2. – AdmBorkBork – 2016-10-26T18:33:17.090

1Related but not duplicates or? – ElPedro – 2016-10-26T20:13:24.043

@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. – AdmBorkBork – 2016-10-26T20:17:18.117

Sorry @TimmD. My misunderstanding of your comment. – ElPedro – 2016-10-26T20:56:09.197

1@ElPedro No problem! I would rather have a question and have it be clear, than to not have a question and have something unclear. – AdmBorkBork – 2016-10-26T20:57:21.623

Can we print the months as YearMonth, for instance 2016-02 2016-10? – Olivier Grégoire – 2016-10-27T09:31:18.897

@OlivierGrégoire Sure, that's fine, so long as it's consistent. – AdmBorkBork – 2016-10-27T12:25:23.997

Can we return an array with falsy values in place of non-Monday months (e.g. [0,2,0,0,0,0,0,0,0,10,0,0])? There's a JS ES6 answer that currently does this. – ETHproductions – 2016-10-28T15:16:08.447

@ETHproductions Yeah, that's fine, since it's still unambiguous to the reader. The output formatting isn't the interesting part of this challenge. – AdmBorkBork – 2016-10-28T15:21:08.547

Answers

2

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

Adám

Posted 2016-10-26T18:32:28.180

Reputation: 37 779

18

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.

ETHproductions

Posted 2016-10-26T18:32:28.180

Reputation: 47 880

Owww... My brain, did you account for leap years in alla that? – Magic Octopus Urn – 2016-10-26T19:54:45.873

2@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 – mbomb007 – 2016-10-26T20:06:42.163

Hopefully y+(y>>2)+(z=y/25>>2)+(z>>2) still saves you a byte. – Neil – 2016-10-26T20:16:10.520

@Neil Thanks, but I found a better way :-) – ETHproductions – 2016-10-26T20:47:34.617

Nice; I saved 6 bytes on my Batch port using (y*5/4-(y/100)*3/4). – Neil – 2016-10-26T21:16:05.457

Make that 8 bytes - (y*5/4-y/100*3/4). – Neil – 2016-10-26T23:17:58.650

@Neil I was just going to ask if you could remove those parens ;-) – ETHproductions – 2016-10-27T00:28:43.350

This is just magnificent! :) – Shaggy – 2017-05-23T12:11:25.497

11

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.

Neil

Posted 2016-10-26T18:32:28.180

Reputation: 95 035

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] – ETHproductions – 2016-10-27T00:33:19.043

@ETHproductions I can save a further byte by reversing the order! – Neil – 2016-10-27T07:56:42.700

Reverse order is fine. Formatting the output isn't the interesting part of this challenge. – AdmBorkBork – 2016-10-27T12:36:52.933

What's our policy on Array Comprehensions now that they've been removed from the spec? – MayorMonty – 2016-10-27T12:43:14.497

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] – ETHproductions – 2016-10-27T14:17:09.587

@MayorMonty I believe the policy is that since they still work in Firefox 30+, they are still a valid feature. – ETHproductions – 2016-10-27T14:39:32.910

BTW, I count 64 bytes in your current solution. (My suggestion is 63) – ETHproductions – 2016-10-27T14:40:25.257

@ETHproductions Ah, all my byte counts are off by 1 for some reason. I'll fix that later. – Neil – 2016-10-27T16:35:41.410

Switch it around to save the parens: for(_ of(m="")+1e11) – ETHproductions – 2016-10-27T17:03:48.290

@ETHproductions Bah, why didn't you just say so in the first place... – Neil – 2016-10-27T17:07:47.387

@Neil I hadn't thought of using 1e11+(m="") ;) – ETHproductions – 2016-10-27T18:25:39.773

8

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.

Titus

Posted 2016-10-26T18:32:28.180

Reputation: 13 814

You need really the table shema mysql? https://mariadb.com/kb/en/mariadb/mysqlhelp_topic-table/

– Jörg Hülsermann – 2016-10-27T20:20:27.570

@JörgHülsermann I don´t get your point. – Titus – 2016-10-28T11:01:52.550

Should FROM help_topic without mysql. work? I have try it not – Jörg Hülsermann – 2016-10-28T11:10:20.527

@JörgHülsermann only if you prepend USE mysql; The correct database must be selected somehow. – Titus – 2016-10-28T12:38:32.870

5

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

Neil

Posted 2016-10-26T18:32:28.180

Reputation: 95 035

5

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

Ton Hospel

Posted 2016-10-26T18:32:28.180

Reputation: 14 114

4

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


$

steve

Posted 2016-10-26T18:32:28.180

Reputation: 2 276

1Strictly speaking, this is perl + cal, not just perl :-p. For example, my Windows machine has perl, but this won't work there. – philomory – 2016-10-26T21:26:41.200

Fair point, updated this and my bash attempt. – steve – 2016-10-26T21:31:59.223

4

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

miles

Posted 2016-10-26T18:32:28.180

Reputation: 15 654

wait, does calendar actually output ascii art? – Destructible Lemon – 2016-10-26T23:14:21.020

@DestructibleWatermelon To be exact, the output format of calendar is an array of 12 boxes where each box contains a 2d array of characters – miles – 2016-10-26T23:18:00.637

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. – Adám – 2016-10-27T09:47:30.513

@Adám Thanks, it uses a better method but it's not a verb in J. I think it will still help though – miles – 2016-10-27T09:53:27.970

My intention was only to inspire. I know it isn't a verb. – Adám – 2016-10-27T09:58:19.883

@Adám Inspire you did :) I saved 14 bytes with that shorter logic – miles – 2016-10-27T10:02:32.263

Can you not replace ##\ with I.? – Adám – 2016-10-27T10:24:37.373

4

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.

LegionMammal978

Posted 2016-10-26T18:32:28.180

Reputation: 15 731

4

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)

Numberknot

Posted 2016-10-26T18:32:28.180

Reputation: 885

1After 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[]=.... – Kevin Cruijssen – 2016-10-27T09:48:13.223

1b and a can be defined in the int part like this: int ... ,b[]=...,a[]=... – Olivier Grégoire – 2016-10-27T09:50:17.390

@OlivierGrégoire You're 2 minutes too late. ;) @Numberknot and you can also change n%100!=0 to n%100>0. – Kevin Cruijssen – 2016-10-27T09:55:38.457

Done @KevinCruijssen. – Numberknot – 2016-10-27T09:59:29.653

1int[]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 – cliffroot – 2016-10-27T13:18:40.580

1can 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 – cliffroot – 2016-10-27T13:24:28.940

1and 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;} – cliffroot – 2016-10-27T14:43:30.437

3

Python 2, 100 bytes

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

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:

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]

mbomb007

Posted 2016-10-26T18:32:28.180

Reputation: 21 944

I wasn't even going to try Python with this one. Nice effort. – ElPedro – 2016-10-26T20:44:41.877

3

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.

CT14.IT

Posted 2016-10-26T18:32:28.180

Reputation: 231

2-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; – Titus – 2016-10-27T09:10:35.000

Ahh misread the question! Thought it was for all years.. oops :B Thanks for the other suggestions as well, will get on them – CT14.IT – 2016-10-27T09:22:43.330

3

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)

Luis Mendo

Posted 2016-10-26T18:32:28.180

Reputation: 87 464

3

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.

Digital Trauma

Posted 2016-10-26T18:32:28.180

Reputation: 64 644

3

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.

Adám

Posted 2016-10-26T18:32:28.180

Reputation: 37 779

3

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","")

Wernisch

Posted 2016-10-26T18:32:28.180

Reputation: 2 534

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. – Engineer Toast – 2017-05-23T12:19:48.480

If you get it to work, though, you can probably use Date(A1,3,0) instead of EOMONTH(DATE(A1,2,1),0) – Engineer Toast – 2017-05-23T12:27:08.953

3

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

aross

Posted 2016-10-26T18:32:28.180

Reputation: 1 583

mktime removes the necessity to pad the year, doesn´t it? – Titus – 2016-10-28T13:09:40.000

@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.

– aross – 2016-10-28T13:14:19.897

Only solution I see for that right now is$argv[1]+400 ... unless Julian and Gregorian weekdays differ. – Titus – 2016-10-28T13:22:41.897

@Titus, yep. Rules say use Gregorian cal – aross – 2016-10-28T13:27:07.267

3

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);
 }
}

steve

Posted 2016-10-26T18:32:28.180

Reputation: 2 276

1What if you flip your if the other direction, to have your else return 31, and therefore you can eliminate the big == chain? – AdmBorkBork – 2016-10-27T18:33:05.713

1would be better if(x==1) {z part}else if(x==3|| x == 5 || x == 8 || x == 10)return 30 else return 31 – RosLuP – 2016-10-27T22:14:59.903

1what 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) – RosLuP – 2016-10-27T22:26:26.957

TimmyD + RosLuP : thanks for the return() points, 100 bytes now saved. – steve – 2016-10-28T07:45:59.110

1it 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 – RosLuP – 2016-10-28T21:45:57.113

3

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.

Jörg Hülsermann

Posted 2016-10-26T18:32:28.180

Reputation: 13 026

You could use echo instead of print and save 1 – Octopus – 2016-10-28T15:34:05.600

1@Octopus not inside the ternary Operator – Jörg Hülsermann – 2016-10-28T15:37:26.857

3

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...

Fors

Posted 2016-10-26T18:32:28.180

Reputation: 3 020

The printf("%d, ", m) would print something as 1, or 2, 3, so there is always one ',' more... I prefer use only spaces – RosLuP – 2016-10-30T15:51:26.740

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. – Fors – 2016-10-30T17:00:45.680

2

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
$

steve

Posted 2016-10-26T18:32:28.180

Reputation: 2 276

+1 - works for BSD cal (e.g. OSX), but watch for trailing spaces on GNU cal. – Digital Trauma – 2016-10-27T01:06:31.373

2

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.

philomory

Posted 2016-10-26T18:32:28.180

Reputation: 153

2

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

Jonathan Allan

Posted 2016-10-26T18:32:28.180

Reputation: 67 804

2

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 

Kevin Cruijssen

Posted 2016-10-26T18:32:28.180

Reputation: 67 575

2

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]

plannapus

Posted 2016-10-26T18:32:28.180

Reputation: 8 610

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. – Billywob – 2016-10-27T09:44:12.390

@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. – plannapus – 2016-10-27T10:25:44.870

2

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
        )
    )
;

Link Ng

Posted 2016-10-26T18:32:28.180

Reputation: 593

@TimmyD Yes but need explicit cast. Answer updated – Link Ng – 2016-10-27T13:59:33.097

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 – Kade – 2016-10-27T14:57:44.960

@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. – Link Ng – 2016-10-27T15:15:00.870

You can convert this to be an Action<int> to save some bytes – TheLethalCoder – 2016-11-16T13:37:26.957

2

PHP, 84 bytes

for($m=1;$m++<14;){if(strftime('%w',strtotime($argv[1]."-$m-1"))==2)echo($m-1)." ";}

My first Code Golf. This is the shortest PHP so far on this question.

EDIT: doesn't seem to work for year 1. I'll have to figure out why, but right now I have to go.

Octopus

Posted 2016-10-26T18:32:28.180

Reputation: 819

1I'd say "Welcome to PPCG!" but you've been registered here for longer than I have! :D Nice first golf. – AdmBorkBork – 2016-10-27T20:38:07.850

Your error is that you create 1-13-1 and 1-14-1 for the year 1 <13 is enough. If you solve this you can remove the unnessary brackets in the moment and think about using the ternary operator – Jörg Hülsermann – 2016-10-27T20:49:46.140

This should fixed your problems for(;$m++<12;)strftime("%w",strtotime($argv[1]+($m/12^0)."-".($m%12+1)."-1"))!=2?:print"$m "; – Jörg Hülsermann – 2016-10-27T21:07:37.833

2

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

ETHproductions

Posted 2016-10-26T18:32:28.180

Reputation: 47 880

1

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! ;-)

Olivier Grégoire

Posted 2016-10-26T18:32:28.180

Reputation: 10 647

@TimmyD sadly, it's an enum. It does have a getValue() method, though, which would save a few bytes. – Celos – 2016-10-27T13:03:03.623

@Celos ordinal() saves 1 more byte compared to getValue(), even though it is suggested to never use it. – Olivier Grégoire – 2016-10-27T13:08:20.657

yes, good thinking. I posted my comment without first refreshing, so I didn't see your reply and edit. – Celos – 2016-10-27T14:11:58.760

1

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
$

steve

Posted 2016-10-26T18:32:28.180

Reputation: 2 276

1

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/

MonkeyZeus

Posted 2016-10-26T18:32:28.180

Reputation: 461

STDERR is ignored by default, so this is fine.

– AdmBorkBork – 2016-10-27T18:51:08.097

1

JavaScript, 65 bytes

v=>[...""+1e11].map((x,i)=>new Date(v+400,++i).getDay()==2?i:"")

Stealing the ""+1e11 trick from the other JavaScript answer.

Returns ["", 2, "", "", "", "", "", "", "", 10, "", ""] for 2016, indicating that Feb and Oct end on a Monday.

Edited: Years 0-99 are parsed as 1900-1999 in JS. Adding 400 causes them to be parsed as 400-499, which are equivalent calendar years.

Grax32

Posted 2016-10-26T18:32:28.180

Reputation: 1 282

This gives incorrect output for 1 (9; should be4,12). You can fix this by adding 400 to the year like the other answer (not sure why this works, but it does) – ETHproductions – 2016-10-28T15:48:40.533

I will fix it. JavaScript considers years 0 to 99 to be 1900 to 1999. – Grax32 – 2016-10-28T22:13:50.353

1

C, 175 217 bytes

#define R return
#define L(i) for(;i-->0;) 
u(y,m){R m-1?30+((2773>>m)&1):28+(y%4==0&&y%100||y%400==0);}s(y,m,g){g+=4;L(m)g+=u(y,m),g%=7;L(y)g+=1+u(y,1),g%=7;R g;}w(y,m,r){m=12;L(m)s(y,m,u(y,m))||(r|=1<<(m+1));R r;}

Code for to find the last day for febrary taken from K&R2; try http://ideone.com/XtuhGj the function for debug is w

z(y,m,r){m=12;L(m)s(y,m,13)-4||(r|=1<<(m+1));R r;}

/*    
// ritorna il numero dei giorni di anno=y mese=m con mese in 0..11
// m==1 significa febbraio   y%4?0:y%100?1:!(y%400) non funziona
u(y,m){R m-1?30+((2773>>m)&1):28+(y%4==0&&y%100||y%400==0);}

// argomenti anno:y[0..0xFFFFFFF]  mese:m[0..11]  giorno:g[1..u(y,m)]
// ritorna il numero del giorno[0..6]
s(y,m,g)
{g+=4; // correzione per il giorno di partenza anno mese giorno = 0,1,1
 L(m)g+=  u(y,m),g%=7; // m:0..m-1  somma mod 7 i giorni del mese dell'anno y
 L(y)g+=1+u(y,1),g%=7; // y:0..y-1  somma mod 7 gli anni da 0..y-1
                       // g+=1+u(y,1) poiche' (365-28)%7=1 e 1 e' febbraio
 R g;
}

// argomenti anno:y[0..0xFFFFFFF], m=0 r=0 
// calcola tutti gli ultimi giorni del mese dell'anno y che cadono di lunedi'
// e mette tali mesi come bit, dal bit 1 al bit 12 [il bit 0 sempre 0] in r
w(y,m,r){m=12;L(m)s(y,m,u(y,m))||(r|=1<<(m+1));R r;}

// argomenti anno:y[0..0xFFFFFFF], m=0 r=0 
//ritorna in r il numero dei mesi che ha giorno 13 di venerdi[==4]
// e mette tali mesi come bit, dal bit 1 al bit 12 [il bit 0 sempre 0] in r
z(y,m,r){m=12;L(m)s(y,m,13)-4||(r|=1<<(m+1));R r;}
*/

#define P printf
#define W while 
#define M main 
#define F for
#define U unsigned
#define N int
#define B break
#define I if
#define J(a,b)  if(a)goto b
#define G goto
#define P printf
#define D double
#define C unsigned char
#define A getchar()
#define O putchar
#define Y malloc
#define Z free
#define S sizeof
#define T struct
#define E else
#define Q static
#define X continue
M()
{N y,m,g,r,arr[]={1,297,1776,2000,2016,3385}, arr1[]={2016,1,1997,1337,123456789};
 C*mese[]={"gen","feb","mar","apr","mag","giu","lug","ago","set","ott","nov","dic"};
 C*giorno[]={"Lun","Mar","Mer","Gio","Ven","Sab","Dom"};
 P("Inserisci Anno mese giorno>");r=scanf("%d %d %d", &y, &m, &g);
 P("Inseriti> %d %d %d r=%d\n", y, m, g, r);
 I(r!=3||m>12||m<=0||g>u(y,m-1))R 0;
 r=s(y,m-1,g);// 12-> 11 -> 0..10
 P("Risultato=%d giorno=%s\n", r, giorno[r]);
 r=w(y,0,0);P(" r=%d ", r);P("\n");
 F(m=0;m<6;++m)
        {P("N anno=%d -->",arr[m]); 
         r=w(arr[m],0,0); // ritorna in r i mesi tramite i suoi bit...
         F(y=1;y<13;++y) I(r&(1<<y))P("%s ",mese[y-1]);
         P("\n");
        }
 F(m=0;m<4;++m)
        {P("N anno=%d -->",arr1[m]); 
         r=z(arr1[m],0,0); // ritorna in r i mesi tramite i suoi bit...
         F(y=1;y<13;++y) I(r&(1<<y))P("%s ",mese[y-1]);
         P("\n");
        }

}

RosLuP

Posted 2016-10-26T18:32:28.180

Reputation: 3 036