Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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
share|improve this question
1  
Related 1 and Related 2. – TimmyD 13 hours ago
    
Related but not duplicates or? – ElPedro 11 hours ago
    
@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. – TimmyD 11 hours ago
    
Sorry @TimmD. My misunderstanding of your comment. – ElPedro 10 hours ago
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. – TimmyD 10 hours ago

15 Answers 15

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]
share|improve this answer
    
Owww... My brain, did you account for leap years in alla that? – carusocomputing 11 hours ago
1  
@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 11 hours ago
    
Hopefully y+(y>>2)+(z=y/25>>2)+(z>>2) still saves you a byte. – Neil 11 hours ago
    
@Neil Thanks, but I found a better way :-) – ETHproductions 11 hours ago
    
Nice; I saved 6 bytes on my Batch port using (y*5/4-(y/100)*3/4). – Neil 10 hours ago

JavaScript (Firefox 30+), 68 bytes

y=>[for(m of Array(12).keys())if(new Date(y+400,++m).getDay()==2)m]
share|improve this answer
    
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 7 hours ago

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
share|improve this answer

Perl+cal, 47 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


$
share|improve this answer
1  
Strictly speaking, this is perl + cal, not just perl :-p. For example, my Windows machine has perl, but this won't work there. – philomory 10 hours ago
    
Fair point, updated this and my bash attempt. – steve 10 hours ago

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]
share|improve this answer
    
I wasn't even going to try Python with this one. Nice effort. – ElPedro 11 hours ago

J, 48 bytes

((2|2%~' '#@-.~_2,@{.4 5 7 8{"1])&>##\)@calendar

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 = 1, Feb = 2, ..., Dec = 12.

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 =: ((2|2%~' '#@-.~_2,@{.4 5 7 8{"1])&>##\)@calendar
   f 1
4 12
   f 297
5
   f 1776
9
   f 2000
1 7
   f 2016
2 10
   f 3385
1 2 10
share|improve this answer
    
wait, does calendar actually output ascii art? – Destructible Watermelon 8 hours ago
    
@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 8 hours ago

Mathematica, 62 bytes

Position[a=#;DayName@DayRange[{#},{#+1},"EndOfMonth"],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.

share|improve this answer

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
$
share|improve this answer
    
+1 - works for BSD cal (e.g. OSX), but watch for trailing spaces on GNU cal. – Digital Trauma 6 hours ago

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.

share|improve this answer

PHP, 159 bytes

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.

share|improve this answer

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
share|improve this answer

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)
share|improve this answer

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

share|improve this answer

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.

share|improve this answer

MySQL, 183 bytes

can probably be done shorter

SET @y=2016;CREATE TEMPORARY TABLE y (m INT);INSERT INTO y VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12);SELECT m FROM y WHERE 2=DAYOFWEEK(LAST_DAY(concat(@y,"-",m,"-01")))

Select a database. Replace 2016 with the desired year. Run.

share

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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