8
\$\begingroup\$

Upon receiving month and year in YYYYMM format, generate output of the corresponding calendar month for that year.

For example the input 201312 should generate the following output:

Mo Tu We Th Fr Sa Su
                   1
 2  3  4  5  6  7  8
 9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31

Only trick is, NO native calendar generating functions... so Linux clones, no "cal" function... Muahahahahah!

PS: The calendar must start out with Monday as the left-most day, this is to ensure that the output is like the "cal" function, but does not output like "cal", which has Sunday as its left-most day...

Smallest code size wins.

\$\endgroup\$
  • 1
    \$\begingroup\$ You want it to look like a calendar, might want to change your text to say that more clearly. Also, what are the winning conditions? \$\endgroup\$ – Justin Dec 9 '13 at 4:21
  • \$\begingroup\$ @Quincunx, you're like my conscience, only digital... \$\endgroup\$ – WallyWest Dec 9 '13 at 4:22
  • 1
    \$\begingroup\$ Except I'm not digital... \$\endgroup\$ – Justin Dec 9 '13 at 4:22
  • 1
    \$\begingroup\$ "Smallest size wins." size of what? If it is code size, then please change the tag to code-golf \$\endgroup\$ – Justin Dec 9 '13 at 4:27
  • 2
    \$\begingroup\$ I presume you want the Gregorian calendar, but for what range of years? \$\endgroup\$ – Peter Taylor Dec 9 '13 at 12:31
6
\$\begingroup\$

Python 2.7 - 152

Unfortunately it fails for September 1752. Granted, it imports all of the calender functions, but only uses 1, and that just returns the start day of the week and the number of days.

from calendar import*
w,l=monthrange(*divmod(input(),100))
print" Mo Tu We Th Fr Sa Su\n"+"   "*w+''.join(["%3d"%s+"\n"*((s+w)%7<1)for s in range(1,l+1)])

Relatively standard code, but this is my favourite bit:

"\n"*((s+w)%7<1)

It prints the new line using string multiplication, if the number of the current day and start day of the week is Sunday (e.g. 7) as the boolean is cast to an integer.

This saves a character on the more intuitive x%7==0 by using x%7<1 instead.

Test output:

> 198210
Mo Tu We Th Fr Sa Su
             1  2  3
 4  5  6  7  8  9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
\$\endgroup\$
  • \$\begingroup\$ let me guess: you have just translated my approach to another language and it came up shorter. I'm okay with that, but disclosure would be nice. \$\endgroup\$ – John Dvorak Dec 9 '13 at 14:37
  • \$\begingroup\$ @JanDvorak Oh no. Not at all. I couldn't even understand yours. To be honest, given the verbose imports I needed, I was shocked it was going to come close to beating yours. Just out of curiousity what is 52.times doing? Its not multiplication? \$\endgroup\$ – user8777 Dec 9 '13 at 20:33
  • 1
    \$\begingroup\$ It's a looping construct. n.times{...} is identical to (0...n).each{...} or 0.upto(n-1){...}. Multiplication would be 52 * ... \$\endgroup\$ – John Dvorak Dec 9 '13 at 20:42
  • \$\begingroup\$ @JanDvorak I played with Python a few years ago in a job I was working in... I found the indent syntax a little bit of a pain... So used to curly brackets I guess... LOVE the "\n"*((s+w)%7<1) trick... I've never checked to see if this would work in JavaScript... ;) \$\endgroup\$ – WallyWest Dec 10 '13 at 7:15
  • \$\begingroup\$ The Wiki reference you mentioned was interesting... "It reformed the calendar of England and British Dominions so that a new year began on 1 January rather than 25 March (Lady Day) and would run according to the Gregorian calendar, as used in most of western Europe." I'm surprised the English were a little behind then...? \$\endgroup\$ – WallyWest Dec 12 '13 at 23:54
8
\$\begingroup\$

Ruby, 170 168 characters

g=gets.to_i
require'date'
d=Date.new g/100,g%100
puts'Mo Tu We Th Fr Sa Su'
l=['']*(d.jd%7)+[*1..(d>>1).jd-d.jd]
56.times{|i|$><<"#{l[i].to_s.rjust 2} #{?\n if i%7>5}"}

Bugfix: didn't require the neccessary library (+16) used julian date modulo 7 instead of current week day directly (-3)
used /100 and %100 to parse date instead of regex (-13). Taken from LegoStormtroopr's answer.
removed the parentheses around the argument to rjust and Date.new(-2)

\$\endgroup\$
  • \$\begingroup\$ Cool. Not tested exhaustively, but seems that you can change "#{l[i].to_s.rjust 2} #{?\n if i%7>5}" with "%2s %s"%[l[i],i%7>5?$/:""]. \$\endgroup\$ – manatwork Dec 10 '13 at 8:22
5
\$\begingroup\$

Mathematica 203

g@d_:=Module[{w={"Mo","Tu","We","Th","Fr","Sa","Su"},c},
c@n_:=" "~ Table ~{n};
Grid@Partition[Join[w,c[Position[w,StringTake[ToString@DayName@d,2]][[1,1]]-1],
Range@DayCount[d,d~DatePlus~{1,"Month"}],c@6],7]]

Testing

g[{2013, 12}]
g[{2014, 1}]
g[{2014, 2}]

calendars

\$\endgroup\$
  • \$\begingroup\$ Great use of Mathematica! \$\endgroup\$ – WallyWest Dec 10 '13 at 7:12
2
\$\begingroup\$

SmileBASIC, 204 bytes

INPUT Y$Y$[3]=Y$[3]+"/
DTREAD Y$+"/01"OUT Y,M,,W
W=W-1+!W*7?"Mo Tu We Th Fr Sa Su
FOR I=1TO 30+(1AND M-(M>7))-(M==2)*2+(Y MOD 4<1&&(Y MOD 100||Y MOD 400<1))LOCATE W*3,?STR$(I,2);
W=W+1
IF W>6 THEN W=0?
NEXT

Wow, that leap year detector is VERY long...

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

JavaScript (239)

h=prompt();y=h.slice(i=0,4);m=h[4]+h[5]-1;d=new Date(y,m);a='MoTuWeThFrSaSu'.match(/../g);for(p=0;p<(d.getDay()||7)-1;p++)a.push('  ');while(d.setDate(++i)&&d.getMonth()==m)a.push(9<i?i:' '+i);while(c=a.splice(0,7).join(' '))console.log(c)

Output:

(for 198210)                (for 201312)

Mo Tu We Th Fr Sa Su        Mo Tu We Th Fr Sa Su
             1  2  3                           1
 4  5  6  7  8  9 10         2  3  4  5  6  7  8
11 12 13 14 15 16 17         9 10 11 12 13 14 15
18 19 20 21 22 23 24        16 17 18 19 20 21 22
25 26 27 28 29 30 31        23 24 25 26 27 28 29
                            30 31
\$\endgroup\$
0
\$\begingroup\$

PHP, 153 147 bytes

Mo Di We Th Fr Sa Su
<?=str_pad("",3*$w=date(w,$t=strtotime(chunk_split($argv[1],4,"-")."7")));while($d++<date(t,$t))printf("%2d "."
"[++$w%7],$d);

breakdown

echo"Mo Di We Th Fr Sa Su\n";   // header
echo str_pad("",3*                      // 4. print leading spaces
    $w=date(w,                          // 3. get weekday
    $t=strtotime(                       // 2. convert to unix timestamp
        chunk_split($argv[1],4,"-")."7" // 1. import, split to year-month-, append day 7
)));
while($d++<date(t,$t))                  // 5. loop $d through days of month:
    printf("%2d "."\n"[++$w%7],$d);         // print date, plus a linebreak for sundays
\$\endgroup\$
0
\$\begingroup\$

C (gcc), 242 bytes

Not the most elegant solution, I suspect.

Input in the form of an integer with the four high digits forming the year, and the low two digits the month.

X=100,W;f(d){int m=d%X,y=d/X,i=0,M=" >8><><>><><>"[m]/2+(m==2&(!(y%4)&&(y%X|!(y%400))));for(m+=m<3?y--,10:-2,W=(((1+(26*m-2)/10-2*y/X+5*(y%X)/4+y/X/4)%7)+6)%7,printf("Mo Tu We Th Fr Sa Su\n%*s",3*W,"");i<M;)printf("%2d%c",++i,W++%7^6?32:10);}

Try it online!

\$\endgroup\$
  • \$\begingroup\$ Suggest (13*m+4)/5+y%X*5/4-7*y/X/4 instead of 1+(26*m-2)/10-2*y/X+5*(y%X)/4+y/X/4 \$\endgroup\$ – ceilingcat Jul 15 '18 at 3:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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