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\$

8 Answers 8

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\$
6
  • 1
    \$\begingroup\$ ...:28+!(y%(y%100?4:400)) shaves 3 more \$\endgroup\$
    – mob
    Sep 13, 2012 at 22:19
  • \$\begingroup\$ Thanks @mob, I'm taking it a bit further, will update soon. \$\endgroup\$
    – ugoren
    Sep 14, 2012 at 7:30
  • \$\begingroup\$ If you're going to use y%16, why not y%8? \$\endgroup\$
    – mob
    Sep 14, 2012 at 16:00
  • \$\begingroup\$ In fact, (y%50?4:8) or (y%25?4:8) work as well. \$\endgroup\$
    – mob
    Sep 14, 2012 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, 2012 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\$
4
  • 1
    \$\begingroup\$ Here's another trick: use the expression !(y%100||(y/=100),y%4) \$\endgroup\$
    – mob
    Sep 13, 2012 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, 2012 at 15:54
  • \$\begingroup\$ Figured out a better one: !(y%(y%100?4:400)) \$\endgroup\$
    – mob
    Sep 13, 2012 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, 2012 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
  • 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, 2012 at 12:06
  • 1
    \$\begingroup\$ You are right! I will fix it. thanks. \$\endgroup\$
    – olivecoder
    Sep 12, 2012 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\$
2
  • 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, 2012 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\$ Sep 17, 2012 at 21:26

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