7
\$\begingroup\$

I would like to see the shortest expression to calculate the days (or the last day) of a month in any language.

Considering y as the number of year and m as month.

Basic rules

  • without date / time functions.
  • considering leap years.
  • there is not other rule.
\$\endgroup\$

closed as unclear what you're asking by Rɪᴋᴇʀ, Mego, NoOneIsHere, Steadybox, caird coinheringaahing Oct 28 '17 at 23:40

Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

5
\$\begingroup\$

C, 40 33 31 characters

Reduced length in three ways:
1. Replaced m%2^m>7 with m^m>7. The first is 0/1 in 30/31 day months, the second is even/odd. But the high bits don't matter, because their all set in 30 anyway (months with 30/31 days look like a really good idea now).
2. Used mob's idea (y%(y%100?4:400) as a leap year test)
3. Used <1 instead of ! saves parenthesis.
4. y%(y%100?4:400) -> y%(y%25?4:16) - works the same.

m-2?30|m^m>7:28|y%(y%25?4:16)<1
\$\endgroup\$
  • 1
    \$\begingroup\$ ...:28+!(y%(y%100?4:400)) shaves 3 more \$\endgroup\$ – mob Sep 13 '12 at 22:19
  • \$\begingroup\$ Thanks @mob, I'm taking it a bit further, will update soon. \$\endgroup\$ – ugoren Sep 14 '12 at 7:30
  • \$\begingroup\$ If you're going to use y%16, why not y%8? \$\endgroup\$ – mob Sep 14 '12 at 16:00
  • \$\begingroup\$ In fact, (y%50?4:8) or (y%25?4:8) work as well. \$\endgroup\$ – mob Sep 14 '12 at 16:11
  • \$\begingroup\$ Thanks @mob, %16 works. %8 fails on 2200. I thought about &15, which isn't good, and somehow missed the equivalent %16 \$\endgroup\$ – ugoren Sep 14 '12 at 17:58
5
\$\begingroup\$

C, 47 45 characters

30+(m>7^m&1)-(m^2?0:2-!(y%100||(y/=100),y%4))

Taken from an answer to an earlier question where I borrowed a couple of tricks from another user. Returns the length of month m in year y for the Gregorian calendar. ugoren's answer to the same question is shorter and may give a shorter answer to this question.

With thanks to mob for his leap year calculation.

\$\endgroup\$
  • 1
    \$\begingroup\$ Here's another trick: use the expression !(y%100||(y/=100),y%4) \$\endgroup\$ – mob Sep 13 '12 at 15:28
  • \$\begingroup\$ @mob Wow. It's taken me a good fifteen minutes to figure out how that works (I even checked it on ideone to make sure it did). Clever. \$\endgroup\$ – Gareth Sep 13 '12 at 15:54
  • \$\begingroup\$ Figured out a better one: !(y%(y%100?4:400)) \$\endgroup\$ – mob Sep 13 '12 at 16:18
  • \$\begingroup\$ @mob I think I'll leave mine as it is now - there's no way I'll catch up with ugoren's answer. \$\endgroup\$ – Gareth Sep 14 '12 at 8:22
3
\$\begingroup\$

I've already answered it before in stackoverflow:

(62648012>>m*2&3)+28+(m==2&&y%4==0)

https://stackoverflow.com/questions/2675720/calculate-days-of-month/11675530#11675530

[EDIT] Matt advertised me about leap yars below and he's asked about language. About the language: the expression works on c/c++ and maybe others.

So, the simplest form will work until 2100... but to prevents the 2100 bug :) I've copied the Matt solution to leap year:

(62648012>>m*2&3)+28+(m==2&&(y%4==0&&(y%100!=0||y%400==0)))
\$\endgroup\$
  • 2
    \$\begingroup\$ I'm not familiar with the language you are using so I may be incorrect, but I don't think you account for integer multiples of 100 (not leap years unless they are also integer multiples of 400) en.wikipedia.org/wiki/Leap_year#Gregorian_calendar for example: 2100 is not a leap year \$\endgroup\$ – Matt Sep 12 '12 at 12:06
  • 1
    \$\begingroup\$ You are right! I will fix it. thanks. \$\endgroup\$ – olivecoder Sep 12 '12 at 14:06
3
\$\begingroup\$

Python 64 61 59

(62648012>>m*2&3)+28+(m==2and y%4==0*(y%100>0 or y%400==0))

Based on olivecoder's solution, but accounting for multiples of 100.

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

VBA, 84

28+Val(Mid("303232332323",M,1))-(M=2 And Y Mod 4=0 And (Y Mod 100>0 Or Y Mod 400=0))
\$\endgroup\$
2
\$\begingroup\$

Python 50 54 57

29+{2:y%(y%25and 4or 16)and-1}.get(m,(1&m^m>>3)+1)

with inspiration from mob, and the interesting fact, that a dict saves 1 byte in contrast to m==2and(..)or(...)

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

Mathematica 97 91 83 82 78 76

A bit long, but gets the job done.

d = y ~ Divisible ~ # & ; 30 + { 1 , Boole [ d @ 400 ∨ ( d @ 4 ∧ ¬ d @ 100 ) ] - 2 , 1 , 0 , 1 , 0 , 1 , 1 , 0 , 1 , 0 , 1 } [ [ m ] ]
\$\endgroup\$
1
\$\begingroup\$

VB.net (89 81c)

shame about the date function restriction as VB.net at only (21c)

Date.DaysInMonth(y,m)

may have won one for a change. DAMN YOU!

So current best is 89c

{0,31,28,31,30,31,30,31,31,30,31,30,31}(m)+(If( m=2 AndAlso (y Mod 4)=0 AndAlso (y Mod 400)>0,1,0)

{0,31,28,31,30,31,30,31,31,30,31,30,31}(m)+(If( m=2 And (y Mod 4)=0 And (y Mod 400)>0,1,0)
\$\endgroup\$
  • 1
    \$\begingroup\$ if we ignore the restriction on YDM, then I can beat that with Excel at only 19 characters with =DAY(DATE(y,m+1,0)) :) \$\endgroup\$ – SeanC Sep 17 '12 at 19:49
  • \$\begingroup\$ Importing the Namespace System.Date would mean you can remove the first 5 chars, so that brings it down to 16c \$\endgroup\$ – Adam Speight Sep 17 '12 at 21:26

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