How many days in a month?

25

4

Given a textual representation (case-insensitive full name or 3 character abbreviation) of a month return the number of days in the month.

For example, december, DEC, and dec should all return 31.

February can have either 28 or 29 days.

Assume the input is a month in one of the correct forms.

qw3n

Posted 2017-10-28T17:35:33.533

Reputation: 733

19You should probably list out all the variations of the month names that we should be able to accept. – Giuseppe – 2017-10-28T17:40:44.443

what do you mean by case insensitive? do you mean we have to accept any case and give the right answer? or do you mean we can specify whether the input must be given in upper or lower case (presumably consistently)? – Level River St – 2017-10-28T17:46:13.133

1For anybody who can use it, the ASCII ordinal sums of the first 3 characters lowered are unique. – totallyhuman – 2017-10-28T18:20:25.423

19That was far, far too soon to accept a solution. – Shaggy – 2017-10-28T19:28:08.153

5i think this would be nicer if input was just the month in a fixed format, as the format now basically requires converting to a fixed case and only looking at the first 3 letters. – xnor – 2017-10-28T21:04:13.510

4As it stands it looks like you want answers to handle all of the listed forms - "For example, december, DEC, and dec should all return 31" - Is that the intention? – Jonathan Allan – 2017-10-28T23:27:28.607

Answers

4

Pyke, 9 bytes

l4C9@~%R@

Try it here!

l4        -   input.title()
    @     -  v.index(^)
  C9      -   ['PADDING', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
        @ - v[^]
     ~%R  -  ['Padding', 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]

Or 15 bytes if all input formats are required

l43<C9 3L<@~%R@

Try it here!

l43<            -   input.title()[:3]
          @     -  v.index(^)
    C9 3L<      -   ['PAD', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
              @ - v[^]
           ~%R  -  ['Padding', 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]

Blue

Posted 2017-10-28T17:35:33.533

Reputation: 26 661

6This returns 31 for FEB. – Laikoni – 2017-10-29T07:26:54.617

2

I believe @Laikoni's point is valid (it also returns 31 for Apr, Jun, Sep, and Nov) but also think that it requires a little clarification in the OP (see my question).

– Jonathan Allan – 2017-10-29T11:20:11.730

@JonathanAllan Well, the OP has accepted this answer, so I guess it's valid? – Erik the Outgolfer – 2017-10-29T17:12:33.633

4@EriktheOutgolfer I would not jump to that conclusion personally. – Jonathan Allan – 2017-10-29T17:41:08.757

I was under the impression that it only needed to work for one form of inputs – Blue – 2017-10-29T22:28:33.807

Pyke looks really cool. Is there any documentation on it? – Eli Richardson – 2017-10-31T17:51:50.493

@EliR It's a simple stack based language. Some info on each of the instructions can be found here: https://pyke.catbus.co.uk/ and some more links here: https://github.com/muddyfish/PYKE/blob/master/README.md if you have any queries feel free to ping me in the Nineteenth Byte chat room here: https://chat.stackexchange.com/rooms/240/the-nineteenth-byte

– Blue – 2017-10-31T19:27:03.840

33

JavaScript (ES6),  48 47 44 43  42 bytes

m=>31^'311'[parseInt(m[1]+m[2],34)*3%49%8]

Demo

let f =

m=>31^'311'[parseInt(m[1]+m[2],34)*3%49%8]

;(
  'JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC,' +
  'JANUARY,FEBRUARY,MARCH,APRIL,MAY,JUNE,JULY,AUGUST,SEPTEMBER,OCTOBER,NOVEMBER,DECEMBER'
).split`,`
.forEach(m => console.log(m, '->', f(m)))

How?

These operations lead to a lookup table of 8 entries, which would not be very interesting if the values were randomly distributed. But any result greater than 2 is mapped to 31 days. Therefore, only the first 3 entries need to be stored explicitly.

Month | [1:2] | Base 34 -> dec. | * 3  | % 49 | % 8 | Days
------+-------+-----------------+------+------+-----+-----
  JAN |    AN |             363 | 1089 |   11 |   3 |  31
  FEB |    EB |             487 | 1461 |   40 |   0 |  28
  MAR |    AR |             367 | 1101 |   23 |   7 |  31
  APR |    PR |             877 | 2631 |   34 |   2 |  30
  MAY |    AY |              10 |   30 |   30 |   6 |  31
  JUN |    UN |            1043 | 3129 |   42 |   2 |  30
  JUL |    UL |            1041 | 3123 |   36 |   4 |  31
  AUG |    UG |            1036 | 3108 |   21 |   5 |  31
  SEP |    EP |             501 | 1503 |   33 |   1 |  30
  OCT |    CT |             437 | 1311 |   37 |   5 |  31
  NOV |    OV |             847 | 2541 |   42 |   2 |  30
  DEC |    EC |             488 | 1464 |   43 |   3 |  31

Arnauld

Posted 2017-10-28T17:35:33.533

Reputation: 111 334

14honestly how on earth do you keep making these amazing weird submissions with crazy maths stuff D: do you have a program to find these or are you just too good for the rest of us – HyperNeutrino – 2017-10-28T17:56:22.897

1@HyperNeutrino The first thing I try is always to find a base conversion, followed by an optional multiplication followed by one or several modulo operations. This one was found quickly that way. But I misread the challenge and first thought that this .substr(0,3) was not required. So, on second thought, this may not be the best approach. – Arnauld – 2017-10-28T18:04:10.627

substr? slice! – Neil – 2017-10-28T18:04:47.043

My trivial approach is only <s>2</s> 3 bytes longer so it might not be optimal anymore because of that, but still very impressive :) – HyperNeutrino – 2017-10-28T18:05:18.620

Sorry @Arnauld, i beat you using Javascript Dates (link)

– Herman L – 2017-10-29T14:33:19.157

@HermanLauenstein For the record, date built-ins were originally disallowed, so I didn't even try. :)

– Arnauld – 2017-10-29T16:23:40.693

1Someone's edit removed that part, but one of the reasons I originally disallowed it is I was wanting to see answers like this one. I love the use base 34 to sidestep the issue of capitalization and different formats. – qw3n – 2017-10-29T18:45:37.767

15

Javascript (ES6), 36 33 bytes

-3 bytes thanks to @JustinMariner and @Neil

m=>31-new Date(m+31).getDate()%31

Sorry @Arnauld, abusing JavaScript weirdness is shorter than your fancy base conversions.

How it works

For some reason, JavaScript allows entering dates outside of the specified month. The code counts how many days outside the month the date is to determine how many days there are in the month. Examples:
"FEB31"Thu Mar 02 200031 - 2 % 3129
"October31"Tue Oct 31 200031 - 31 % 3131

Test cases

f=m=>31-new Date(m+31).getDate()%31
;(
 "JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC,"+
 "January,February,Mars,April,May,June,July,August,September,October,November,December"
).split`,`.forEach(s=>console.log(s,"->",f(s)))

Herman L

Posted 2017-10-28T17:35:33.533

Reputation: 3 611

MS Excel also does this.. January 0 is always December Last Day, so =DAY("00/01/2017") will result in 31 – DavChana – 2017-10-29T17:18:58.203

It looks like Javascript only allows date strings where the day is up to 31. If you try to enter "feb 32", it translates to 2032-02-01, and if you try to force it with "0-feb-32" (or a similar string), it just says "Invalid Date". Oddly enough, if you set the day to 0 ("feb 0"), it translates to 2000-02-01 rather than 2000-01-31. – TehPers – 2017-10-29T20:14:25.993

You might be able to save a byte by dropping the space before 31. It seems to work in Chrome as new Date("feb31") for example. – Justin Mariner – 2017-10-30T07:56:17.100

In fact you could probably use +31 saving three bytes overall. None of this works in Firefox though. – Neil – 2017-10-30T11:15:26.680

11

Python 2, 46 45 38 bytes

-1 byte thanks to @totallyhuman

lambda m:29-int(m[1:3],35)%238%36%-5/2

Try it online!

ovs

Posted 2017-10-28T17:35:33.533

Reputation: 21 408

45 bytes. – totallyhuman – 2017-10-28T18:21:34.523

7

Bash, 21 bytes

cal $1|xargs|tail -c3

Try it online!

Takes input as command-line argument and outputs with a trailing newline. The day count for February depends on that of the current year

Requires the util-linux 2.29 version of cal, which is the one available on TIO. Also is locale-dependent, so LC_TIME must be changed on non-English systems (thanks @Dennis for clarification).

Idea of piping through xargs to trim cal's output is from this SO answer.

Justin Mariner

Posted 2017-10-28T17:35:33.533

Reputation: 4 746

2This isn’t just bash. Generally it’s sh, but it’s probably almost every shell implementation that supports path lookups and pipes, on a system with cal, tail and xargs. – kojiro – 2017-10-30T01:26:52.997

5

Proton, 50 bytes

k=>31-((e=k.lower()[1to3])in"eprunov")-3*(e=="eb")

Try it online!

-14 bytes thanks to Jonathan Frech

Thirty days hath September, April, June, and November. All the rest had peanut butter. All except my grandmother; she had a little red trike, but I stole it. muahahahahaha

(I've been waiting to tell that joke (source: my math professor) for ages on this site :D :D :D)

HyperNeutrino

Posted 2017-10-28T17:35:33.533

Reputation: 26 575

@Riker oh whoops that wasn't there when I started writing this :/ – HyperNeutrino – 2017-10-28T17:52:49.290

1There is a new rule that you have to check for not a valid month and return 0. I hope it gets deleted – Level River St – 2017-10-28T17:52:54.927

1Nevermind changing I'm deleting that part – qw3n – 2017-10-28T17:53:18.933

I think you can use a single string 'sepaprjunnov' instead of a list of strings. – Jonathan Frech – 2017-10-28T17:55:55.327

@JonathanFrech maybe; I'll try that, thanks – HyperNeutrino – 2017-10-28T17:56:47.483

@JonathanFrech yup, that saved 12 bytes, thanks! – HyperNeutrino – 2017-10-28T17:58:38.177

50 bytes. – Jonathan Frech – 2017-10-28T17:59:25.307

The joke alone was worth an upvote. :) – Robert Benson – 2017-10-28T18:10:25.353

4

C# (.NET Core), 52+13=65 38+24=62 bytes

m=>D.DaysInMonth(1,D.Parse(1+m).Month)

Try it online!

+24 for using D=System.DateTime;

Acknowledgements

-3 bytes thanks to Grzegorz Puławski.

Ayb4btu

Posted 2017-10-28T17:35:33.533

Reputation: 541

Does this work without using System;? Or can you excluse that from the byte count? – Matty – 2017-10-30T13:13:44.337

@Matty That's a good point; now added. – Ayb4btu – 2017-10-30T19:07:02.663

3

Python 3, 60 bytes

x=input().lower()[1:3];print(31-(x in"eprunov")-3*(x=="eb"))

Try it online!

Porting my Proton solution

-10 bytes thanks to totallyhuman

HyperNeutrino

Posted 2017-10-28T17:35:33.533

Reputation: 26 575

Better than mine heh – Thomas Ward – 2017-10-28T18:11:40.287

1um – totallyhuman – 2017-10-28T18:12:36.773

:P builtins are sometimes too long :P – HyperNeutrino – 2017-10-28T18:12:38.613

@totallyhuman oh rly wow. +1 thanks :P – HyperNeutrino – 2017-10-28T18:12:52.687

2umm – totallyhuman – 2017-10-28T18:23:11.587

@totallyhuman lol nice – HyperNeutrino – 2017-10-28T18:26:56.427

3

Shell/GNU Date, 39, 26 bytes

date -d1$1+1month-1day +%d

Where $1 is the name of the month.

Try it online!

edit: Thanks Dennis for saving many bytes!

DarkHeart

Posted 2017-10-28T17:35:33.533

Reputation: 171

2

AWK, 45 44 bytes

L=tolower($1){$0=L~/v|p|un/?30:L~/f/?28:31}1

Try it online!

Robert Benson

Posted 2017-10-28T17:35:33.533

Reputation: 1 339

2

Python 3 - 93 86 84 82 bytes

Variants of answer (showing the progression of time, and bytes for each, with TIO links):

Original Answer (93 bytes)

-7 bytes thanks to Jonathan Frech. (86 bytes)

-2 more bytes thanks to my own further testing of the monthrange results, with the second value always being the higher value. (84 bytes) 1

-2 more by using import calendar as c and referencing it with c.monthrange. (82 bytes, current revision)


lambda x:c.monthrange(1,time.strptime(x[:3],'%b')[1])[1];import time,calendar as c

Obviously not as nice as HyperNeutrino's answer which doesn't use built-ins, but this still works.


Footnotes

1: Test cases via TIO.run showing the proof for how I'm handling those monthrange values, for a varying number of month test cases.

Thomas Ward

Posted 2017-10-28T17:35:33.533

Reputation: 193

86 bytes. – Jonathan Frech – 2017-10-28T18:27:30.843

@JonathanFrech Thanks. Further revised downwards by my having tested more of how monthrange works, and also by using import ...,calendar as c so as not having to type 'calendar' twice. – Thomas Ward – 2017-10-28T19:38:42.080

2

Haskell, 65 63 62 bytes

f.map((`mod`32).fromEnum)
f(_:b:c:_)|c<3=28|c>13,b>3=30
f _=31

Try it online!

Pattern matching approach. The first line is to handle the case-insensitivity. Then we return 28 if the third letter is smaller than C (number 3), 30 if the second letter is larger than C and the third one larger than M, or 31 otherwise.

Edit: -1 byte thanks to Leo


Alternative (65 64 bytes)

f s|let i#n=n<mod(fromEnum$s!!i)32=sum$29:[2|2#2]++[-1|2#13,1#3]

Try it online!

Laikoni

Posted 2017-10-28T17:35:33.533

Reputation: 23 676

1Clever one! You can save a byte by checking for c<3 instead of a==6 (February is the first month if you order them by their third letter, followed by December) – Leo – 2017-10-30T05:29:16.723

2

Perl 5, 47 + 1 (-p) = 48 bytes

$_=substr$_,1,2;$_=31-("eprunov"=~/$_/i)-3*/b/i

Try it online!

Xcali

Posted 2017-10-28T17:35:33.533

Reputation: 7 671

-6 bytes : ($_)=/.(..)/; instead of $_=substr$_,1,2; and () around "eprunov"=~/$_/i can be removed. – Nahuel Fouilleul – 2017-11-03T08:33:37.217

2

Mediawiki Template, 19 bytes

{{#time:t|{{{1}}}}}

tsh

Posted 2017-10-28T17:35:33.533

Reputation: 13 072

2

APL (Dyalog), 32 bytes*

Tacit prefix function. Assumes ⎕IO (Index Origin) 0, which is default on many systems.

31 28 30⊃⍨∘⊃'.p|un|no|f'⎕S 1⍠1

Try it online!

⍠1 case insensitively

1 return the length of the

⎕S PCRE Search for

'.p|un|no|f' any-char,"p" or "un" or "no" or "f"

⊃⍨∘⊃ and use the first element of that (0 if none) to pick from

31 28 30 this list

Thus:

  • Apr, Sep, Jun, and Nov will select the number at index 2, namely 30

  • Feb will select the number at index 1, namely 28

  • anything else will select the number at index 0, namely 31


* Using Classic and counting as ⎕OPT.

Dyalog APL

Posted 2017-10-28T17:35:33.533

Reputation: 21

1

MATL, 22 bytes

14L22Y2c3:Z)Z{kj3:)km)

Try it online!

Explanation

14L    % Push numeric array of month lengths: [31 28 ... 31]
22Y2   % Push cell array of strings with month names: {'January', ..., 'December'}
c      % Convert to 2D char array, right-padding with spaces
3:Z)   % Keep first 3 columns
Z{     % Split into cell array of strings, one each row
k      % Convert to lower case
j      % Input string
3:)    % Keep first 3 characcters
k      % Convert to lower case
m      % Ismember: gives a logical index with one match
)      % Use that as index into array of month lengths. Implicit display

Luis Mendo

Posted 2017-10-28T17:35:33.533

Reputation: 87 464

1

Retina, 32 31 28 bytes

i`f
28
i`p|v|un
30
\D

^$
31

Try it online! Edit: Saved 1 byte thanks to @RobertBenson. Saved 3 bytes thanks to @ovs.

Neil

Posted 2017-10-28T17:35:33.533

Reputation: 95 035

I believe you could save a byte by using 'f' instead of 'eb' – Robert Benson – 2017-10-28T18:19:59.017

28 bytes – ovs – 2017-10-30T17:41:35.657

1

Wolfram Language (Mathematica), 46 30 bytes

#~NextDate~"Month"~DayCount~#&

Try it online!

Will give either 28 or 29 for February depending on whether the current year is a leap year.

How it works

All date commands in Mathematica will interpret input such April, APR, ApRiL, and so on as the first day of the corresponding month in the current year. (As a bonus, input such as "February 2016" or {2016,2} also works as expected.)

#~NextDate~"Month" gives the first day of the month after that, and DayCount gives the number of days between its two arguments. The number of days between April 1st and May 1st is 30, the number of days in April.

Misha Lavrov

Posted 2017-10-28T17:35:33.533

Reputation: 4 846

1

Java 8, 47 bytes

m->31-new java.util.Date(m+"31 1").getDate()%31

Try it online!

Ended up using the same idea as Herman Lauenstein's JS answer, where setting the date to the 31st pushed into the next month. Java does require a year, so that has been set to 1.

Justin Mariner

Posted 2017-10-28T17:35:33.533

Reputation: 4 746

1

PHP, 38 33+1 32+1 bytes

Saved 5 bytes thanks to Titus

<?=date(t,strtotime("$argn 1"));

Run as pipe with -nF

Try it online!

Jo.

Posted 2017-10-28T17:35:33.533

Reputation: 974

1Hey, I don't think you need .' 1', it seems to work on TIO without it! – Dom Hastings – 2017-11-02T16:51:36.767

128+1 bytes: <?=date(t,strtotime($argn)); (run as pipe with -nF) – Titus – 2017-11-02T21:21:21.610

3@DomHastings - so, before I posted, I had tested to see if it would work without the .' 1', but it wasn't working. After seeing your comment, I tried to figure out what I had done wrong. Because I was running it on the 31st of the month, it was taking the 31st (current) day for any month I put in, which would put it beyond the current month. Feb 31st turns into March 3rd, so the code returns 31 (the number of days in March). Because of this, every month was returning 31. So, it works without the .' 1' on any day <= 28th of the month. – Jo. – 2017-11-03T03:47:47.190

Ahhh, I forget about how PHP fills in the blanks! Thanks for explaining! – Dom Hastings – 2017-11-03T05:34:48.040

@Titus Thank you. I'm such a golf newbie! I don't know why I didn't realize the 't' -> t. Also, I had to do a bunch of searching to figure out how to "run as pipe with -nF" but I got it figured out (I think). :) – Jo. – 2017-11-03T06:33:38.413

$argn.' 1' -> "$argn 1" saves one more byte – Titus – 2017-11-03T10:32:53.827

1

q/kdb+, 36 bytes

Solution:

28 30 31@2^1&(*)"ebeprunov"ss(_)1_3#

Examples:

q)28 30 31@2^1&(*)"ebeprunov"ss(_)1_3#"January"
31
q)28 30 31@2^1&(*)"ebeprunov"ss(_)1_3#"FEB"
28
q)28 30 31@2^1&(*)"ebeprunov"ss(_)1_3#"jun"
30

Explanation:

There are a million ways to skin a cat. I think is slightly different to the others. Take the 2nd and 3rd letters of the input, lowercase them, then look them up in the string "ebeprunov". If they are at location 0, then this is February, if they are at a location >0 they are a 30-dayer, if they are not in the string, they are a 31-dayer.

28 30 31@2^1&first"ebeprunov"ss lower 1_3# / ungolfed solution
                                        3# / take first 3 items from list, January => Jan
                                      1_   / drop the first item from the list, Jan => an
                                lower      / lower-case, an => an
                  "ebeprunov"ss            / string-search in "ebeprunov", an => ,0N (enlisted null)
             first                         / take the first, ,0N => 0N
           1&                              / take max (&) with 1, 0N => 0N
         2^                                / fill nulls with 2, 0N => 2
        @                                  / index into
28 30 31                                   / list 28,30,31

streetster

Posted 2017-10-28T17:35:33.533

Reputation: 3 635

1

Excel VBA, 47 43 Bytes

Anonymous VBE immediate window function that takes input, as month name, abbreviation, or number, from range [A1] and outputs the length of that month in the year 2001 to the VBE immediate window function.

?31-Day(DateValue("1 "&[A1]&" 1")+30)Mod 31

Old Version

d=DateValue(["1 "&A1&" 1"]):?DateAdd("m",1,d)-d

Taylor Scott

Posted 2017-10-28T17:35:33.533

Reputation: 6 709

0

QBIC, 49 35 bytes

?31-(instr(@aprjunsepnov feb`,;)%3)

Significantly shorter with some trickery.

Explanation

?                          PRINT
31-(                       31 minus
  instr(                   the position of
                      ,;   our input string
    @aprjunsepnov feb`  )  in the string cntaining all non-31 months                                
    %3)                    modulo 3 (this yields a 1 for each month except feb=2)

steenbergh

Posted 2017-10-28T17:35:33.533

Reputation: 7 772

0

Java (OpenJDK 8), 126 bytes

s->{for(java.time.Month m:java.time.Month.values())if(m.name().startsWith(s.toUpperCase()))System.out.print(m.length(false));}

Try it online!

Roberto Graham

Posted 2017-10-28T17:35:33.533

Reputation: 1 305

1I think you can shorten false to a boolean expression like 1<0 to save a couple bytes. – Justin Mariner – 2017-10-31T00:53:15.653

0

Perl 5, 24 bytes

23 bytes code + 1 for -p.

$_=31-/p|un|no/i-/f/i*3

Try it online!

Dom Hastings

Posted 2017-10-28T17:35:33.533

Reputation: 16 415

0

Ruby, 45 bytes

->m{((Date.parse(m)>>1)-1).day}
require'date'

Try it online!

Ruby's Date.parse accepts a month name on its own. What would normally be a right-shift (>>) actually adds to the month of the Date object. Subtraction affects the day of the month, which will wrap backwards to the last day of the previous month.

Justin Mariner

Posted 2017-10-28T17:35:33.533

Reputation: 4 746

0

Kotlin, 92 bytes

val d={m:String->arrayOf(0,31,30,30,31,30,31,28,31,0,30)[(m[1].toInt()+m[2].toInt())%32%11]}

Try it online!

JohnWells

Posted 2017-10-28T17:35:33.533

Reputation: 611