7
\$\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\$
7
  • 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\$ 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\$ 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\$
7
  • \$\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\$ 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\$ 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\$ 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\$ 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\$
1
  • \$\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\$
1
  • \$\begingroup\$ Great use of Mathematica! \$\endgroup\$ 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\$
2
\$\begingroup\$

Vyxal, 87 bytes

k§2vẎṄ,4ȯI:£3<?4ẎIεD4/⌊‟₁/⌊N‟:400/⌊»∧+ż↵`»8τv‹¥Ẏt2Ṡ7%7ε¤w$ẋf»∇ė{»4τ¥Ẏt28+ɾJ7ẇƛƛS2↳;Ṅ;⁋,

Try it Online!

-7 thanks to lyxal.

=== Part 1: Header ===
k§      # Monday to Sunday
  2vẎ   # Get first two letters of each
     Ṅ, # Join by spaces
=== Part 2: What day does it start? ===
4ȯI                                          # Last two (month) as integer
   :£                                        # Store a copy to register
     3<?4ẎIε                                 # Decrement the year if the month is Jan or Feb 
            D                                # Calculate:
             4/⌊‟                            # floor(y/4)
                 ₁/⌊N‟                       # -floor(y/100)
                      :                      # y
                       400/⌊                 # And floor(y/400)
                            »...»8τv‹        # Compressed list of the days (mod 7) at the start of each month
                                     ¥Ẏt     # Get the correct item
                                        2    # Add 2 (1 because first day of month, 1 because it ends on Sunday)
                                         Ṡ7% # Take the sum of the whole thing, mod 7.
=== Part 3: Get the whole month ===
7ε                     # Difference from 7
  ¤w$ẋf                # Copies of the empty string
       »...»4τ         # Compressed list of days in each month, -28
              ¥Ẏt      # Get the correct item
                 28+   # Add 28
                    ɾ  # Make a range out of that
                     J # Add on the empty strings
=== Part 4: Format nicely ===
7ẇ           # Divide into chunks of 7
  ƛ      ;   # Foreach...
   ƛ   ;     # For each item...
    S        # Stringify
     2↳      # Align
        Ṅ    # Join by spaces
          ⁋, # Output joined by newlines
\$\endgroup\$
1
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\$
1
\$\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\$
1
  • \$\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.