29
\$\begingroup\$

This simple challenge is very similar to this one: How many days in a month? The only difference is you yield the number of days in a month given the index of the month instead of its name.

The reason I ask this near-duplicate is curiosity about mathematical patterns in the sequence of numbers. For example, a simple observation is that even-indexed months have 31 until August and then it flips — but golf that observation and/or make better ones that yield better strokes...

INPUT: Integer indicating the month; 1 through 12. (Optionally, you can accept 0-indexed month numbers from 0 to 11.)

OUTPUT: Number of days in that month. February can return 28 or 29.

Complete I/O table:

INPUT   :   OUTPUT
  1          31
  2          28 or 29 
  3          31
  4          30
  5          31
  6          30
  7          31
  8          31
  9          30
 10          31
 11          30
 12          31
\$\endgroup\$
0

36 Answers 36

27
\$\begingroup\$

APL (Dyalog Unicode), 13 12 bytesSBCS

Anonymous tacit prefix function. 0-indexed. February is 29.

31-1∘=+2|7∘|

Try it online!

31- thirty-one minus…

1∘= the equal-to-one'ness…

  + plus…

   2| the two-mod of…

    7∘| the seven-mod'ness

The reason I ask this near-duplicate is curiosity about mathematical patterns in the sequence of numbers. For example, a simple observation is that even-indexed months have 31 until August and then it flips — but golf that observation and/or make better ones that yield better strokes...

This solution implements the following mathematical pattern:

$$f(x)=31-[x=1]-\big((x\mod 7)\mod 2\big)$$

or

$$f(x)=31-x-\left[x=1\right]+7\left\lfloor\frac{x}7\right\rfloor+2\left\lfloor x-7\left\lfloor\frac{x}7\right\rfloor\over2\right\rfloor$$

\$\endgroup\$
3
  • \$\begingroup\$ What is the $[1=x]$ notation? \$\endgroup\$ Commented Nov 15, 2019 at 23:59
  • \$\begingroup\$ @infinitezero It means "1 if x=1, 0 otherwise". \$\endgroup\$
    – Vincent
    Commented Nov 16, 2019 at 14:59
  • \$\begingroup\$ @infinitezero Iverson bracket (bottom of page: So far the notations…) \$\endgroup\$
    – Adám
    Commented Nov 16, 2019 at 19:32
13
\$\begingroup\$

Poetic, 706 bytes

counting a day,one month<t-o>twelve
i got frustrated doing a list
i do say,o,i edited a list,a month&a day count
in twelve(in December)to one(January)i listed a day"s count,then the numeral months
and once i am ready,o,i think i got a number to say
a number,o,i know a count
o,i say i am thirty if one"s short
i am ready,o,i know a count is not a thirty if we switch it
a long,a short,a etc.i switch
i do think i want a count of Febr-u"ry=two n eight:a case of a month"s age as shorter than the others"s
a day"s a day,i reckon
i know,i am clever
o,a date"s count at min=a thirty-day,or affix a one,i think
i do start&i produce threes if ever i am thirty
P.S.note:i index by one,i receive any-format numbers

Try it online!

As noted in the final line of the program, this program takes months as 1-based indices, and can take both simple numbers and numbers with a leading 0. (How's that for code comments?)

In pseudocode, my approach was basically like this:

N = input(); // Poetic doesn't support native numerical input, only input as ASCII codes; I basically have to write myself a number input routine every time
DIGIT = 49 // ASCII value for "1"; I would set it to 3, but that would be slightly longer
if (N>7) N++; // this accounts for the July->August parity shift
if (N!=2) { // if not February...
    DIGIT += 2; // now it's "3"
    print(DIGIT); // output: "3"
    DIGIT -= 3; // and now it's "0"...
    if (N%2==1) THREE++; // ...unless N is odd
    print(DIGIT); // output: "30" if short month, "31" if long month
} else { // if February...
    DIGIT += 1; // now it's "2"
    print(DIGIT); // output: "2"
    DIGIT += 6; // now it's "8"
    print(DIGIT); // output: "28"
}
\$\endgroup\$
3
  • \$\begingroup\$ Is there a reason why you used " instead of '? \$\endgroup\$
    – user85052
    Commented Nov 15, 2019 at 10:46
  • \$\begingroup\$ @A_ Apostrophes are "closed off" in Poetic; for example, can't is a 4-letter word. As far as code golf goes, apostrophes are entirely useless. (I'd have used the Unicode right-quotation-mark, but that's more than one byte.) \$\endgroup\$ Commented Nov 15, 2019 at 11:27
  • \$\begingroup\$ @A_ Basically, apostrophes are deleted, non-letter characters (defined as a character that returns false for the is_alpha() function in Python, or equivalently that doesn't match the newfangled \p{L} regex) are replaced with whitespace, and then the whole program is split on whitespace and its word-lengths are counted and turned into program instructions. \$\endgroup\$ Commented Nov 15, 2019 at 11:35
12
\$\begingroup\$

Pyke, 4 bytes

~%R@

I have no idea how does this work (actually, after reading the source, I think I do, but Pyke seems extremely weird to me) as I simply used the second half of the Pyke answer by @Blue in the related question OP linked to. Try it online!

\$\endgroup\$
3
  • 4
    \$\begingroup\$ For anyone else wondering what this does and don't know Pyke (like me): here are the Pyke docs and this code will: ~% push the builtin list ['Padding', 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; R rotate the values on the stack (at least 2) - so with only a single value on the stack it takes the input implicitly and acts like a swap (Q -get input- instead of R would be more a more intuitive alternative); @ index this input into the list; (and output the result implicitly with trailing newline). PS: 0-based input with ~MQ@ is also possible. \$\endgroup\$ Commented Nov 15, 2019 at 12:36
  • \$\begingroup\$ Thank you for notifying me Pyke has docs! :) \$\endgroup\$ Commented Nov 15, 2019 at 12:39
  • \$\begingroup\$ Took me a bit to find as well, haha. ;) On the github page it links to "me saying how great the language is", where it at the bottom links to "This documentation can be found in pure html form here." Not sure why this html docs aren't in the github README or Wiki page tbh.. \$\endgroup\$ Commented Nov 15, 2019 at 12:42
11
\$\begingroup\$

C (gcc), 27 bytes

0-indexed.

Instead of indexing into a string, I get the day offset (from 28) for the month from a packed bit array. Luckily all the offsets fit in a two-bit representation, so the bit array fits in an integer: I just shift and mask the offset and add 28.

f(m){m=0xEEFBB3>>m*2&3|28;}

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ Are you sure this is shorter than indexing into a string though? \$\endgroup\$ Commented Nov 15, 2019 at 11:56
  • 2
    \$\begingroup\$ @someone No, it's not. It's more fun though. It probably would be if there were more than 12 months in a year, however! :-) \$\endgroup\$
    – ErikF
    Commented Nov 15, 2019 at 15:37
10
\$\begingroup\$

JavaScript (ES6), 16 bytes

All solutions expect a 0-indexed input and output 29 days for February.

Using a decimal modulo.

n=>n%1.7+!~-n^31

Try it online!


Using a single integer modulo.

n=>30-!~-n|n%7^1

Try it online!


Same approach as Adám with 2 integer modulos.

n=>31-n%7%2-!~-n

Try it online!

\$\endgroup\$
8
\$\begingroup\$

Gaia, 3 bytes

∂k=

Yep, there's a built-in.

Try it online!

∂k   List containing days in each month
  =  Index into it (implicit input)
\$\endgroup\$
6
\$\begingroup\$

x86 Machine Code, 14 bytes

B8 B3 FB EE 00
01 C9
D3 E8
24 03
04 1C
C3

This is a straight port of ErikF's C answer. The above bytes define a function that accepts a zero-indexed month (in the ECX register), and outputs the number of days (in the AL register, the lower-order bytes of the EAX register). The result is calculated by adding 28 to a fix-up parameter obtained from a sequenced vector of 2-bit values.

B8 B3 FB EE 00   mov    eax, 0x00EEFBB3    ; load bit vector into EAX
01 C9            add    ecx, ecx           ; \ index into the bit vector
D3 E8            shr    eax, cl            ; |   by shifting it right
24 03            and    al,  3             ; /   and keeping only the lowest 2 bits
04 1C            add    al,  28            ; add 28
C3               ret

Try it online!

Note that we can do the AND and ADD on byte-sized operands, which results in 2-byte instructions, rather than the 3-byte instructions required to operate on double-words.

The big bloat here is that initial 32-bit MOV instruction required to load the bit vector, but this implementation is still significantly smaller than a solution implementing the mathematical algorithm cited by Adam: (31 - ((month % 7) % 2) - (month == 1)).

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

05AB1E, 9 bytes

7%É31αsΘ-

Same formula as @Adám's APL (Dyalog Unicode) answer, which I've also partially used in this earlier answer of mine.

Try it online.

Explanation:

7%         # Take the (implicit) input-integer modulo-7
  É        # Check whether it is odd (short for modulo-2)
   31α     # Take the absolute difference with 31
      s    # Swap to take the (implicit) input-integer again
       Θ   # 05AB1E truthify; 1 if n==1; 0 otherwise
        -  # And subtract this from the earlier number
           # (after which the result is output implicitly)
\$\endgroup\$
5
\$\begingroup\$

Python 3, 24 bytes

lambda n:31-n%7%2-(n==1)

Try it online!

Adaptation of Adám's APL answer


Original answer:

Python 3, 29 bytes

lambda n:31^n%2^n//7^2*(n==1)

Try it online!

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

Turing Machine Code, 197 bytes

0 0 _ * j
0 1 _ r F
0 2 _ * j
0 3 2 * F
0 4 _ * j
0 5 2 * F
0 6 _ * j
0 7 _ * j
0 8 2 * F
0 9 _ * j
h * * * halt
j _ 3 r ǰ
ǰ _ 1 * h
F _ 2 r Ƒ
Ƒ _ 8 * h
F 0 2 * F
F 1 _ r j
N _ 0 * h
F 2 3 r N

Try it online!

\$\endgroup\$
4
\$\begingroup\$

Python 3, 58 45 bytes

lambda x:'312831303130313130313031'[x*2:][:2]

Try it online!

  • A weak solution to get it started with an "unanalyzed" solution space

  • Saved a few bytes by functionizing thanks to Jo King

\$\endgroup\$
2
  • 2
    \$\begingroup\$ This can quickly be improved to 37 bytes with unprintables, or 28 bytes as a function \$\endgroup\$
    – Jo King
    Commented Nov 15, 2019 at 0:39
  • 1
    \$\begingroup\$ @JoKing Good call. The unprintables I think is inventive enough that you can post it as a separate answer if you want, but I've functionized. \$\endgroup\$ Commented Nov 15, 2019 at 1:24
4
\$\begingroup\$

PHP, 31 bytes

<?=date(t,mktime(0,0,0,$argn));

Try it online!

Just using builtins really. Input month via STDIN, 1-indexed.

\$\endgroup\$
4
\$\begingroup\$

C# (Visual C# Interactive Compiler), 20 bytes

x=>""[x]

Try it online!

\$\endgroup\$
3
  • \$\begingroup\$ I think a string of unprintables is shorter. \$\endgroup\$ Commented Nov 15, 2019 at 4:20
  • 8
    \$\begingroup\$ What is this sorcery \$\endgroup\$
    – Innat3
    Commented Nov 15, 2019 at 10:11
  • \$\begingroup\$ @Innat3: indexing a string where the "characters" are small integers, below ASCII 32 = space. \$\endgroup\$ Commented Nov 18, 2019 at 2:21
4
\$\begingroup\$

Python 2, 42 39 35 bytes

lambda i:(30+(i%2==(i<8)),28)[i==2]

Try it online!

Not the shortest Python solution but an alternative approach (1 indexed).

Shorter but not very interesting:

Python 2, 34 bytes

lambda i:int("303232332323"[i])+28

Try it online!

\$\endgroup\$
4
\$\begingroup\$

Retina, 29 28 bytes

^o$
x
o{7}|oo

^
31*
__x|_o

Explanation:

^o$      match input equal to "o"
x        replace it with x
o{7}|oo  match 7 or 2 "o"s, whichever the regex engine prefers
         replace them with nothing (this happens to compute a%7%2)
^        match the beginning of string
31*      and replace it with 31 times the default character (_)
__x|_o   match __x or _o literally
         and erase them (that is, "x" means "erase two _" and "o" means "erase one _")

Try it online!

\$\endgroup\$
7
  • \$\begingroup\$ You can remove the } to save a byte (relevant part of the docs EDIT: or maybe not, seems like an undocumented feature). \$\endgroup\$ Commented Nov 15, 2019 at 13:40
  • \$\begingroup\$ @Kevin Thanks, though I'm pretty sure that section refers to groupings when substituting, not the patterns themselves, so this is probably a different feature. \$\endgroup\$ Commented Nov 15, 2019 at 13:42
  • \$\begingroup\$ Hmm good point.. I just noticed it works without the closing bracket, and was looking for the relevant docs. Maybe it's undocumented/hidden. :) \$\endgroup\$ Commented Nov 15, 2019 at 13:43
  • \$\begingroup\$ For some reason it also doesn't seem to work with normal human circular () parentheses. Maybe that's a .NET regex "feature"? \$\endgroup\$ Commented Nov 15, 2019 at 13:44
  • \$\begingroup\$ No, it doesn't seem to work in .NET C#. Ah well.. PS: You forgot to update your byte-count in the title. \$\endgroup\$ Commented Nov 15, 2019 at 13:50
3
\$\begingroup\$

Red, 46 bytes

func[m][b:(a: to now[1 m 1])+ 31 b/4: 1 b - a]

Try it online!

A verbose solution that literally calculates the number of days in the given month (28 for february - year 1 AD)

Explanation:

Red[]
f: func[m][
    a: to now [1 m 1]   ; make a date dd-mm-yyyy (1st of the "month" year 1 AD)
    b: a + 31           ; add 31 days to it
    b/4: 1              ; and go back to the 1st day of the new month
    b - a               ; subtract the initial date from the new one 
]
\$\endgroup\$
3
\$\begingroup\$

Haskell, 37 bytes

Not in any way clever, but there you go. Pretty much checks all the non-31-day months and if it isn't any of them it falls back on 31.

f 2=28;f m|elem m[4,6,9,11]=30;f _=31

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ 27 bytes, with 0-indexing \$\endgroup\$ Commented Nov 15, 2019 at 23:34
  • 1
    \$\begingroup\$ @UnrelatedString, go ahead and post as your own answer if you want. I think it's less a revision of my answer than a completely new one. \$\endgroup\$ Commented Nov 18, 2019 at 13:41
3
\$\begingroup\$

Excel, 29 bytes

=DAY(EOMONTH(DATE(0,B1,1),0))

Where B1 is the month number (1-based).

\$\endgroup\$
1
  • \$\begingroup\$ Porting @Adam's formula is shorter at 27 bytes: =31-(A1=1)-MOD(MOD(A1,7),2) \$\endgroup\$
    – Wernisch
    Commented Nov 20, 2019 at 13:22
3
\$\begingroup\$

As suggested by @Xcali it can be even shorter:

Perl 5, 35 bytes

$_=substr"3128".3130313031x2,$_*2,2

Try it online!

As suggested by @manatwork this can be shortened substantial:

Perl 5, 39 bytes

("3128".3130313031x2)=~/(..){$_}/;$_=$1

Try it online!

Perl (And because I like regex, a first humble attempt):

Perl 5, 60 bytes

print $1 if "312831303130313130313031" =~ /(..){$ARGV[0]}/g;

Try it online!

Invoke via perl -e and user supplied input, e.g. 2 for the month, at command line argument with index 0.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ 1) None of the spaces are needed. 2) Is shorter without if: just do the pattern matching then print in separate statements. 3) Is shorter to get the month number as input. 4) If taking input, is shorter to automate it using -p switch. 5) No need for the g modifier. Try it online! \$\endgroup\$
    – manatwork
    Commented Nov 15, 2019 at 11:26
  • \$\begingroup\$ That's a substantial truncation. \$\endgroup\$
    – stephanmg
    Commented Nov 15, 2019 at 11:28
  • 1
    \$\begingroup\$ A bit shorter if you repeat the common part of the string: ("3128".3130313031x2). \$\endgroup\$
    – manatwork
    Commented Nov 15, 2019 at 11:33
  • 1
    \$\begingroup\$ Even shorter if you use substr and 0-index: Try it online! \$\endgroup\$
    – Xcali
    Commented Nov 15, 2019 at 17:11
  • \$\begingroup\$ Thanks @Xcali I incorporated the changes. \$\endgroup\$
    – stephanmg
    Commented Nov 15, 2019 at 17:14
3
\$\begingroup\$

z80 Machine Code, 13 bytes

47 1F 1F 1F A8 E6 01 05 10 01 3D C6 30

Takes input (starting at 1) in the A register and stores output in the same register. This was manually assembled from the ez80 manual and is not yet tested, therefore it might contain some mistakes.

Explanation:

47        ld b, a         ; Copy the value to the B register
1F 1F 1F  rra   (3 times) ; \ Set A to ((A >> 3) ^ B) & 1, which is
A8        xor a, b        ; | equal to 1 on all months with 31 days
E6 01     and a, 1        ; / 
05        dec b           ; \ Decrement the B register twice and skip the next instruction if 
10 01     djnz $+3        ; / the resulting value is not zero (if the month is not february)
3D        dec a           ; Decrement A (if february)
C6 30     add a, 30       ; Add 30 to A
\$\endgroup\$
3
\$\begingroup\$

C++ (g++), 60 54 47 40 bytes

1-indexed. f(2)==29.

int f(int n){return(n^n/8)%2-(n==2)+30;}

Solution from k-map, which simplified to A=w+x+z and B=zw'+z'w. A was negated and became a subtraction.

int f(int n){      //N is a 4-digit binary number wxyz.
return (n^n/8) %2  //Add 1 if (w XOR z)
     - (n==2)      //Subtract 1 if !(w OR x OR z), which simplifies to (w'x'z'),
                   //which is only satisfied when N is 0000 or 0010.
                   //Since n is never 0, this condition is only satisfied when n==2.
     + 30;         //Add 30, the base month length.
}

At first I tried adding 1 or 2 instead of 1 or 1, but my solution was 87 bytes (if I remember correctly). I tried that with 0-indexing and 1-indexing, but they ended up being the exact same length.

47 bytes: int f(int n){return(n/8|n/4|n)%2+(n^n/8)%2+29;}

54 bytes: int f(int n){return((n>>3|n>>2|n)&1)+((n^n>>3)&1)+29;}

60 bytes: int f(int n){return(n>>3&1|n>>2&1|n&1)+((n&1)^(n>>3&1))+29;}

Edit: Thanks to Herman L. for the improvement to 54 bytes, I'm glad someone found my approach interesting even though it's clearly not the shortest!

Edit 2: Thank you to ceilingcat for the improvement to 47 bytes. This uses division instead of bit shifting, which saves one byte in each of three places. It also replaces &1 with %2 in two places. Both of these functionally return the last byte of the integer, but the modulo operator has precedence over addition. This means that two pairs of parentheses can be removed, saving four bytes. In total, by mixing arithmetic and bitwise operators, ceilingcat managed to improve the answer by seven bytes!

Edit 3: Another improvement by ceilingcat brings it down six bytes by doing bitwise comparison with 13, -!(n&13). Since this is only true in one case, simplified to an equality check.

\$\endgroup\$
5
  • \$\begingroup\$ Welcome to CG&CC! \$\endgroup\$
    – Endenite
    Commented Nov 17, 2019 at 8:08
  • 1
    \$\begingroup\$ A few bytes can be saved by reordering the operators: int f(int n){return((n>>3|n>>2|n)&1)+((n^n>>3)&1)+29;} \$\endgroup\$
    – Endenite
    Commented Nov 17, 2019 at 8:13
  • \$\begingroup\$ @HermanL Thank you, it looks so obvious now that you point that out! I guess I need more practice with bitwise operators. \$\endgroup\$
    – radeklew
    Commented Nov 17, 2019 at 19:45
  • \$\begingroup\$ @ceilingcat Great idea! I wouldn't have thought to use /, since I was focussed on bitwise operators. \$\endgroup\$
    – radeklew
    Commented Nov 30, 2019 at 4:58
  • \$\begingroup\$ @ceilingcat Nice! Got it down to 40 and updated the answer. Good idea with the subtraction. \$\endgroup\$
    – radeklew
    Commented Dec 2, 2019 at 3:06
3
\$\begingroup\$

Javascript, 23 bytes

n=>15662007>>~-n*2&3|28

This is utilizing a binary map 15662007 which is

111011101111101110110111
11.10.11.10.11.11.10.11.10.11.01.11
 3. 2. 3. 2. 3. 3. 2. 3. 2. 3. 1. 3

You just add each item to 28 and see that it provides a proper mapping to each month.

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

Ruby, 18 bytes

->n{31-n%7%2-2[n]}

Try it online!

0-based, basically the same formula as Adam, adapted to ruby.

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

Jelly, 10 bytes

%7Ḃ31__1⁼$

Try it online!

Pretty much just a translation of Adám and Kevin Cruijssen's APL and 05ab1e answers, respectively. There's probably some way I could cut out the $.

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

T-SQL 61 bytes

declare @ int set @=2print DAY(EOMONTH(DATEFROMPARTS(1,@,1)))

40 bytes if we put the input directly to the query:

print DAY(EOMONTH(DATEFROMPARTS(1,2,1)))
\$\endgroup\$
2
\$\begingroup\$

J, 19 bytes

(31-0 2 0,#:330){~]

For fun, here's a J translation of Adam's APL answer (also 12 bytes):

31-1&=+2|7&|

Jonah's comment saves another 4 bytes, due to:

  1. better use of J's hook: ({...) instead of (...{~])
  2. better choice of starting binary values, adjusting the arithmetic as necessary (30+1 _1,... rather than 31-0 2 0,...):
| expr    | result               |
|---------|----------------------|
| 0,#:330 | 0 1 0 1 0 0 1 0 1 0  |
| #:693   | 1 0 1 0 1 1 0 1 0 1  |

Try it online!

\$\endgroup\$
4
  • 1
    \$\begingroup\$ I came up with a similar 15 byte approach ({30+1 _1,#:@693), but it can still be beaten by translating Adam's solution directly into J. \$\endgroup\$
    – Jonah
    Commented Nov 15, 2019 at 21:11
  • \$\begingroup\$ Nice. I tried to translate Adam's to J but failed to make it shorter, probably because I don't quite grok APL yet. \$\endgroup\$ Commented Nov 17, 2019 at 17:50
  • 1
    \$\begingroup\$ Aha, got it: 31-1&=+2|7&| Thanks! \$\endgroup\$ Commented Nov 17, 2019 at 17:56
  • \$\begingroup\$ That's the one. Nice! \$\endgroup\$
    – Jonah
    Commented Nov 17, 2019 at 17:57
2
\$\begingroup\$

Keg, -rr, 17 16 14 13 bytes

$:&1=-&7%2%-

Try it online!

Simply a port of Adams APL answer.

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

Pyth, 10 8 bytes

0-indexed, February is 29.

C@."񣈆"

Try it online! TIO doesn't seem to like the UTF-8 conjoined character, but it works in the official interpreter. Consider TIO a glorified pastebin for this.

Previous version, 10 bytes:

C@."Îï»

Try it online!

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

Wren, 27 bytes

-3 bytes thx to Jo King for putting all into a tertiary statement.

Fn.new{|x|1==x?28:31-x%7%2}

Try it online!

Wren, 35 bytes

-4 bytes thx 2 Jo King for noticing that .bytes[x] would work.

Fn.new{|x|" ".bytes[x]}

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ For the first, you can move it all into the ternary statment for 27 bytes \$\endgroup\$
    – Jo King
    Commented Nov 15, 2019 at 9:13
1
\$\begingroup\$

C (gcc), 22 bytes

f(n){n=31-n%7%2-!~-n;}

Try it online!

Stealing from @Arnaulds / @Adám


29 26 bytes

f(x){x=""[x];}

Port of @Embodiment of Ignorance answer

\$\endgroup\$

Your Answer

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

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