Calendar: Difference between revisions

185,061 bytes added ,  2 months ago
no edit summary
No edit summary
 
(120 intermediate revisions by 37 users not shown)
Line 1:
[[Category:Scala examples needing attention]]
{{task|Date and time}}
Create a routine that will generate a text calendar for any year.
Line 6 ⟶ 7:
* A line printer with a width of 132 characters.
* An [[wp:IBM_3270#Displays|IBM 3278 model 4 terminal]] (80×43 display with accented characters). Target formatting the months of the year to fit nicely across the 80 character width screen. Restrict number of lines in test output to 43.
 
 
(Ideally, the program will generate well-formatted calendars for any page width from 20 characters up.)
Line 18 ⟶ 20:
For economy of size, do not actually include Snoopy generation in either the code or the output, instead just output a place-holder.
 
For other calendar-related tasks, see [[Five weekends]].
 
;Related task:
:*   [[Five weekends]]
<br><br>
=={{header|360 Assembly}}==
{{trans|Free Basic}}
This program uses no external functions but two ASSIST macros (XDECO, XPRNT) to keep the code as short as possible.
<langsyntaxhighlight lang="360asm">* calendar 08/06/2016
CALENDAR CSECT
USING CALENDAR,R13 base register
Line 202 ⟶ 206:
DA DS 12CL144
YREG
END CALENDAR</langsyntaxhighlight>
{{out}}
<pre>
Line 239 ⟶ 243:
31
</pre>
 
=={{header|Ada}}==
 
Line 246 ⟶ 249:
the [[Calendar_-_for_"real"_programmers#Ada]] task.
 
<langsyntaxhighlight Adalang="ada">with Ada.Calendar.Formatting;
 
package Printable_Calendar is
Line 293 ⟶ 296:
end record;
 
end Printable_Calendar;</langsyntaxhighlight>
 
We continue with the implementation (printable_calendar.ads):
 
<langsyntaxhighlight Adalang="ada">with Ada.Text_IO;
 
package body Printable_Calendar is
Line 472 ⟶ 475:
end Init_132;
 
end Printable_Calendar;</langsyntaxhighlight>
 
Now, the main program is really simple:
 
<langsyntaxhighlight Adalang="ada">with Printable_Calendar;
 
procedure Cal is
Line 486 ⟶ 489:
C.New_Line;
C.Print(1969, "Nineteen-Sixty-Nine");
end Cal;</langsyntaxhighlight>
 
Here is the output:
Line 531 ⟶ 534:
 
To get a 132-character-wide output, you just have to replace "Init_80" by "Init_132" in the main program.
 
=={{header|ALGOL 68}}==
{{works with|ALGOL 68|Revision 1 - no extensions to language used}}
{{works with|ALGOL 68G|Any - tested with release [http://sourceforge.net/projects/algol68/files/algol68g/algol68g-1.18.0/algol68g-1.18.0-9h.tiny.el5.centos.fc11.i386.rpm/download 1.18.0-9h.tiny].}}
{{wont work with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release [http://sourceforge.net/projects/algol68/files/algol68toc/algol68toc-1.8.8d/algol68toc-1.8-8d.fc9.i386.rpm/download 1.8-8d] - due to extensive use of '''format'''[ted] ''transput''.}}
<langsyntaxhighlight lang="algol68">#!/usr/local/bin/a68g --script #
 
PROC print calendar = (INT year, page width)VOID: (
Line 643 ⟶ 645:
line printer width = 80; # as at 1969! #
print calendar(mankind stepped on the moon, line printer width)
)</langsyntaxhighlight>
Output:
<pre>
Line 681 ⟶ 683:
26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30
</pre>
=={{header|ALGOL W}}==
{{trans|Simula}} which is a {{trans|C}}
This is pretty much the same as the Simula version.
<br>
The main differences are that the "for" loop counter in Algol W is a separate variable that only exists during execution of the loop
whereas in Simula the loop counter must be declared outside the loop and has its value changed as the loop executes
- hence some of the "for" loops have been replaced by "while" loops.
<br>In Algol W, the condition of a "while" loop can be a block and the boolean "and" operator short circuits, which allow us to avoid the goto statements.
<br>Also, the Algol W string type is fixed length, unlike the Simula text type.
<syntaxhighlight lang="algolw">BEGIN
INTEGER WIDTH, YEAR;
INTEGER COLS, LEAD, GAP;
STRING(2) ARRAY WDAYS (0::6);
RECORD MONTH ( STRING(9) MNAME; INTEGER DAYS, START_WDAY, AT_POS );
REFERENCE(MONTH) ARRAY MONTHS(0::11);
WIDTH := 80; YEAR := 1969;
 
BEGIN
WDAYS(0) := "Su"; WDAYS(1) := "Mo"; WDAYS(2) := "Tu";
WDAYS(3) := "We"; WDAYS(4) := "Th"; WDAYS(5) := "Fr"; WDAYS(6) := "Sa";
MONTHS( 0) := MONTH(" January", 31, 0, 0 );
MONTHS( 1) := MONTH(" February", 28, 0, 0 );
MONTHS( 2) := MONTH(" March", 31, 0, 0 );
MONTHS( 3) := MONTH(" April", 30, 0, 0 );
MONTHS( 4) := MONTH(" May", 31, 0, 0 );
MONTHS( 5) := MONTH(" June", 30, 0, 0 );
MONTHS( 6) := MONTH(" July", 31, 0, 0 );
MONTHS( 7) := MONTH(" August", 31, 0, 0 );
MONTHS( 8) := MONTH("September", 30, 0, 0 );
MONTHS( 9) := MONTH(" October", 31, 0, 0 );
MONTHS(10) := MONTH(" November", 30, 0, 0 );
MONTHS(11) := MONTH(" December", 31, 0, 0 )
END;
BEGIN
PROCEDURE SPACE(INTEGER VALUE N);
BEGIN
WHILE N > 0 DO BEGIN
WRITEON(" "); N := N-1;
END
END SPACE;
PROCEDURE INIT_MONTHS;
BEGIN
INTEGER I;
IF YEAR REM 4 = 0 AND YEAR REM 100 NOT = 0 OR YEAR REM 400 = 0 THEN
DAYS(MONTHS(1)) := 29;
YEAR := YEAR-1;
START_WDAY(MONTHS(0))
:= (YEAR * 365 + YEAR DIV 4 - YEAR DIV 100 + YEAR DIV 400 + 1) REM 7;
FOR I := 1 STEP 1 UNTIL 12-1 DO
START_WDAY(MONTHS(I)) :=
(START_WDAY(MONTHS(I-1)) + DAYS(MONTHS(I-1))) REM 7;
COLS := (WIDTH + 2) DIV 22;
WHILE 12 REM COLS NOT = 0 DO
COLS := COLS-1;
GAP := IF COLS - 1 NOT = 0 THEN (WIDTH - 20 * COLS) DIV (COLS - 1) ELSE 0;
IF GAP > 4 THEN
GAP := 4;
LEAD := (WIDTH - (20 + GAP) * COLS + GAP + 1) DIV 2;
YEAR := YEAR+1
END INIT_MONTHS;
PROCEDURE PRINT_ROW(INTEGER VALUE ROW);
BEGIN
INTEGER C, I, FROM, UP_TO;
INTEGER PROCEDURE PREINCREMENT(INTEGER VALUE RESULT I);
BEGIN I := I+1; I
END PREINCREMENT;
INTEGER PROCEDURE POSTINCREMENT(INTEGER VALUE RESULT I);
BEGIN INTEGER PREV_VALUE;
PREV_VALUE := I; I := I+1; PREV_VALUE
END POSTINCREMENT;
FROM := ROW * COLS;
UP_TO := FROM + COLS;
SPACE(LEAD);
FOR C := FROM STEP 1 UNTIL UP_TO-1 DO BEGIN
I := 9 % LENGTH OF MNAME(MONTHS(C)) % ;
SPACE((20 - I) DIV 2);
WRITEON(MNAME(MONTHS(C)));
SPACE(20 - I - (20 - I) DIV 2 + (IF C = UP_TO - 1 THEN 0 ELSE GAP));
END;
WRITE();
SPACE(LEAD);
FOR C := FROM STEP 1 UNTIL UP_TO-1 DO BEGIN
FOR I := 0 STEP 1 UNTIL 7-1 DO BEGIN
WRITEON(WDAYS(I)); IF I NOT = 6 THEN WRITEON(" ")
END;
IF C < UP_TO - 1 THEN
SPACE(GAP)
ELSE
WRITE();
END;
WHILE BEGIN
C := FROM;
WHILE C < UP_TO AND AT_POS(MONTHS(C)) >= DAYS(MONTHS(C)) DO
C := C + 1;
 
C NOT = UP_TO
END DO BEGIN
SPACE(LEAD);
C := FROM;
WHILE C < UP_TO DO BEGIN
I := 0;
WHILE I < START_WDAY(MONTHS(C)) DO BEGIN
I := I + 1;
SPACE(3)
END;
WHILE POSTINCREMENT(I) < 7 AND AT_POS(MONTHS(C)) < DAYS(MONTHS(C)) DO BEGIN
WRITEON(I_W := 2, S_W := 0, PREINCREMENT(AT_POS(MONTHS(C))));
IF I < 7 OR C < UP_TO - 1 THEN
SPACE(1)
END;
WHILE POSTINCREMENT(I) <= 7 AND C < UP_TO-1 DO
SPACE(3);
IF C < UP_TO - 1 THEN
SPACE(GAP - 1);
START_WDAY(MONTHS(C)) := 0;
C := C + 1
END;
WRITE();
END;
WRITE()
END PRINT_ROW;
PROCEDURE PRINT_YEAR;
BEGIN
INTEGER ROW, STRLEN, Y;
STRLEN := 1;
Y := YEAR;
WHILE Y > 9 DO BEGIN Y := Y DIV 10; STRLEN := STRLEN + 1 END;
SPACE((WIDTH - STRLEN) DIV 2);
WRITEON(I_W := 1, YEAR);
WRITE(); WRITE();
WHILE ROW * COLS < 12 DO BEGIN
PRINT_ROW(ROW);
ROW := ROW+1
END
END PRINT_YEAR;
 
INIT_MONTHS;
PRINT_YEAR
END
END.</syntaxhighlight>
{{out}}
<pre>
 
1969
 
January February March
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1
5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8
12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15
19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22
26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29
30 31
 
April May June
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 3 1 2 3 4 5 6 7
6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14
13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21
20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28
27 28 29 30 25 26 27 28 29 30 31 29 30
 
July August September
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 1 2 3 4 5 6
6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13
13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20
20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27
27 28 29 30 31 24 25 26 27 28 29 30 28 29 30
31
 
October November December
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1 2 3 4 5 6
5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13
12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20
19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27
26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30
 
 
</pre>
 
=={{header|Amazing Hopper}}==
<p>Hopper tiene una función que genera calendarios en español, y con un formato diferente al pedido.</p>
<p>El calendario generado en un array 2D como el que se muestra a continuación:</p>
<p>Línea de código:</p>
<pre>
Let ( calendario := Calendar(1,año,12) )
[ 1:8, 1:7 ] Cget 'calendario', Print this table
</pre>
<pre>
ENE, , , , , ,1969
Dom,Lun,Mar,Mie,Jue,Vie,Sab
, , , 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,
, , , , , ,
</pre>
<p>Son generados tantos calendarios como se pida, y de diferentes formas (lineales o radiales). El código a continuación debe reformatear el calendario antes de imprimirlo.</p>
<syntaxhighlight lang="txt">
#include <jambo.h>
 
Main
Set stack 15
año=0
Get arg numeric '2', Move to 'año'
Set '4,1,1,1' Init 'fila, columna, contador columna, contador mes)
meses={}
Let list ( meses := "Enero","Febrero","Marzo","Abril","Mayo",\
"Junio","Julio","Agosto","Septiembre","Octubre",\
"Noviembre","Diciembre" )
calendario=0
Let ( calendario := Calendar(1,año,12) )
Cls
Link gosub 'Cambia lenguaje de los meses, Imprime año'
Tok sep ("")
Gosub while ( i=1, Less(i,97), Dibuja calendario )
End
 
Subrutines
 
Define 'Dibuja calendario'
Locate (fila, columna) Just center (23, [ contador mes++ ] Cget 'meses')
Print it
++fila
Loc row (fila--) [ {i}Plus(1):{i}Plus(7), 1:7 ] Cget 'calendario'
Print this table
++contador columna
columna += 25
When( Equals (contador columna, 4) ) {
Set '1', Copy to 'contador columna',
Move to 'columna'
fila+=9
}
i+=8
Return
 
Define 'Imprime año'
Locate (2,35), Print (año)
Return
 
Define 'Cambia lenguaje de los meses'
Let ( calendario := Tran (" Do","Dom",calendario) )
Let ( calendario := Tran (" Lu","Lun",calendario) )
Let ( calendario := Tran (" Ma","Mar",calendario) )
Let ( calendario := Tran (" Mi","Mie",calendario) )
Let ( calendario := Tran (" Ju","Jue",calendario) )
Let ( calendario := Tran (" Vi","Vie",calendario) )
Let ( calendario := Tran (" Sa","Sab",calendario) )
Return
</syntaxhighlight>
{{out}}
<pre>
$ hopper jm/calendar.jambo 1969
 
1969
 
Enero Febrero Marzo
Do Lu Ma Mi Ju Vi Sa Do Lu Ma Mi Ju Vi Sa Do Lu Ma Mi Ju Vi Sa
1 2 3 4 1 1
5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8
12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15
19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22
26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29
30 31
 
Abril Mayo Junio
Do Lu Ma Mi Ju Vi Sa Do Lu Ma Mi Ju Vi Sa Do Lu Ma Mi Ju Vi Sa
1 2 3 4 5 1 2 3 1 2 3 4 5 6 7
6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14
13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21
20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28
27 28 29 30 25 26 27 28 29 30 31 29 30
 
Julio Agosto Septiembre
Do Lu Ma Mi Ju Vi Sa Do Lu Ma Mi Ju Vi Sa Do Lu Ma Mi Ju Vi Sa
1 2 3 4 5 1 2 1 2 3 4 5 6
6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13
13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20
20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27
27 28 29 30 31 24 25 26 27 28 29 30 28 29 30
31
 
Octubre Noviembre Diciembre
Do Lu Ma Mi Ju Vi Sa Do Lu Ma Mi Ju Vi Sa Do Lu Ma Mi Ju Vi Sa
1 2 3 4 1 1 2 3 4 5 6
5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13
12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20
19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27
26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30
</pre>
 
=={{header|AutoHotkey}}==
<langsyntaxhighlight AutoHotkeylang="autohotkey">Calendar(Yr){
LastDay := [], Day := []
Titles =
Line 721 ⟶ 1,033:
Res:=RegExReplace(Res,"`am)(^|\s)\K0", " ")
return res
}</langsyntaxhighlight>
Examples:<langsyntaxhighlight AutoHotkeylang="autohotkey">Gui, font,s8, COURIER
Gui, add, edit, vYr w40 r1 Limit4 Number, 1969
Gui, add, edit, vEdit2 w580 r38
Line 736 ⟶ 1,048:
GuiClose:
ExitApp
return</langsyntaxhighlight>
Outputs:<pre> 1969
 
Line 774 ⟶ 1,086:
26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30 </pre>
 
=={{header|AutoIt}}==
<syntaxhighlight lang="autoit">
<lang AutoIt>
#include <Date.au3>
 
Line 879 ⟶ 1,190:
ConsoleWrite($sLeft & $_sLine & $_sLF & @LF)
EndFunc ;==>_PrintLine
</syntaxhighlight>
</lang>
Output
<pre>
Line 922 ⟶ 1,233:
</pre>
--[[User:BugFix|BugFix]] ([[User talk:BugFix|talk]]) 00:40, 15 November 2013 (UTC)
 
=={{header|AWK}}==
<syntaxhighlight lang="awk">
<lang AWK>
 
Works with Gnu awk version 3.1.5 and with BusyBox v1.20.0.git awk
Line 1,025 ⟶ 1,335:
 
</syntaxhighlight>
</lang>
Output:
<pre>
Line 1,064 ⟶ 1,374:
 
</pre>
=={{header|BASIC}}==
 
==={{header|BaCon}}===
Choosing 132 character output.
<langsyntaxhighlight lang="freebasic">DECLARE month$[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }
DECLARE month[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
year$ = "1969"
Line 1,099 ⟶ 1,409:
PRINT day;
NEXT
NEXT</langsyntaxhighlight>
 
{{out}}
Line 1,123 ⟶ 1,433:
 
=={{header|Batch File}}==
<langsyntaxhighlight lang="dos">::Calender Task from Rosetta Code Wiki
::Batch File Implementation
 
Line 1,215 ⟶ 1,525:
echo.
pause
endlocal</langsyntaxhighlight>
{{Out}}
<pre>
Line 1,260 ⟶ 1,570:
 
Press any key to continue . . .</pre>
 
=={{header|BBC BASIC}}==
{{works with|BBC BASIC for Windows}}
The day and month names are in the language for which the PC is configured.
<langsyntaxhighlight lang="bbcbasic"> INSTALL @lib$+"DATELIB"
VDU 23,22,640;570;8,15,16,128
Line 1,299 ⟶ 1,608:
PRINT
NEXT
</syntaxhighlight>
</lang>
Output:
<pre> 1969
Line 1,337 ⟶ 1,646:
26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30</pre>
 
=={{header|Befunge}}==
This is quite closely based on the [[Calendar#C|C]] sample, although the centering calculation has been adjusted to fix an off-by-one error, and the months have been made a constant height, regardless of how much space they require, to try and produce a more balanced layout.
Line 1,343 ⟶ 1,651:
The year is read from stdin, and the width is specified by the first value on the stack (set to 80 - <tt>"P"</tt> - in the current implementation).
 
<langsyntaxhighlight lang="befunge">"P"00p&>:::4%!\"d"%*\45*:*%!+!!65*+31p:1-:::"I"5**\4/+\"d"/-\45*:*/+1+7%:0v
J!F?M!A M!J J!A!S O!N D!SaFrThWeTuMoSuvp01:_1#!-#%:#\>#+6<v-2g1+1g01p1p01:<
January February March April >:45**00g\-\1-:v:<<6>+7%:10g2+:38*\`|
Line 1,353 ⟶ 1,661:
> > $$55+,6>>40p:10g30g>:#,1#*-#8\#4_$>\:2*:1+1g2-50p1g640g-7*1+\-7v v@,<6
2:+g01$_55+,^ > > > > #^>#g>#0>#2_v v*2!!\%+55:\/+55:**`0\!`g05:::\< >2-^^
->:> >#^>#<>#<^#!:-1g04$$ < < < < < >4+8*+\:!!2*4+8*+,,48*,1+\1-:>#^_$$1+\1</langsyntaxhighlight>
 
=={{header|C}}==
With arbitrary display width (>= 20 though) and auto spacing.
<langsyntaxhighlight Clang="c">#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Line 1,481 ⟶ 1,788:
bail: fprintf(stderr, "bad args\nUsage: %s year [-w width (>= 20)]\n", v[0]);
exit(1);
}</langsyntaxhighlight>
 
{{libheader|Gadget}}
{{trans|Amazing Hopper}}
<syntaxhighlight lang="c">
 
#include <gadget/gadget.h>
LIB_GADGET_START
 
void draw_calendar( RDS(char*,calendario), int year );
void print_calendar( RDS(char*,calendario) );
 
Main
Assert( Arg_count ==2, fail_arg );
Get_arg_int( year, 1 );
 
ACTUAL_LANG_DATE = EN; /* text in english */
New array calendario as string;
/* get full year:
112 = code for months after initial month.
1 = initial month
year = well... */
calendario = Calendar(calendario, 112, 1, year);
draw_calendar( SDS(calendario), year );
Free str array calendario;
Exception( fail_arg ){
Msg_yellow("Modo de uso:\n ./calendar <nYear>");
}
 
End
 
void draw_calendar( RDS( char*, calendario), int year )
{
int fila=4, columna=1, cnt_columna=1, cnt_mes=0, i=0;
Cls;
At 2,35; Print "%d", year;
 
while ( cnt_mes < 12 )
{
String month_name;
Stack {
Store ( month_name, Pad_c( Capital( Get_monthname(cnt_mes++) ),' ',23) );
} Stack_off;
At fila, columna; Print "%s", month_name;
 
Atrow ++fila;
Range for calendario [ i+1: 1: i+8, 0:1: Cols(calendario) ];
print_calendar( SDS(calendario) );
--fila;
++cnt_columna;
columna += 25;
When( cnt_columna == 4 ) {
cnt_columna = columna = 1;
fila+=9;
}
i+=8;
Free secure month_name;
}
Prnl;
}
 
 
void print_calendar( RDS(char*,calendario) )
{
int i,j;
int row = SCREEN_ROW;
 
Iterup( row, calendario, i)
{
Iterup( col, calendario, j)
{
Print "%*s", 3, $calendario[i,j];
}
Atrow ++row;
}
}
 
</syntaxhighlight>
{{out}}
<pre>
1969
 
January February March
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1
5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8
12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15
19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22
26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29
30 31
 
April May June
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 3 1 2 3 4 5 6 7
6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14
13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21
20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28
27 28 29 30 25 26 27 28 29 30 31 29 30
 
July August September
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 1 2 3 4 5 6
6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13
13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20
20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27
27 28 29 30 31 24 25 26 27 28 29 30 28 29 30
31
 
October November December
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1 2 3 4 5 6
5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13
12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20
19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27
26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30
 
</pre>
 
=={{header|C sharp|C#}}==
An attempt to abuse the DateTime class for all static information. In the event that the number of days and months changes, so long as the DateTime class is updated accordingly, this should still print properly. It also abuses iterators to allow for a concise month printing method, but with the ability to still print x months per line.
 
<syntaxhighlight lang="csharp">
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace CalendarStuff
{
class Program
{
static void Main(string[] args)
{
Console.WindowHeight = 46;
Console.Write(buildMonths(new DateTime(1969, 1, 1)));
Console.Read();
}
private static string buildMonths(DateTime date)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine(center("[Snoop]", 24 * 3));
sb.AppendLine();
sb.AppendLine(center(date.Year.ToString(), 24 * 3));
 
List<DateTime> dts = new List<DateTime>();
while (true)
{
dts.Add(date);
if (date.Year != ((date = date.AddMonths(1)).Year))
{
break;
}
}
var jd = dts.Select(a => buildMonth(a).GetEnumerator()).ToArray();
int sCur=0;
while (sCur<dts.Count)
{
sb.AppendLine();
int curMonth=0;
var j = jd.Where(a => curMonth++ >= sCur && curMonth - 1 < sCur + 3).ToArray(); //grab the next 3
sCur += j.Length;
bool breakOut = false;
while (!breakOut)
{
int inj = 1;
foreach (var cd in j)
{
if (cd.MoveNext())
{
sb.Append((cd.Current.Length == 21 ? cd.Current : cd.Current.PadRight(21, ' ')) + " ");
}
else
{
sb.Append("".PadRight(21, ' ') + " ");
breakOut = true;
}
if (inj++ % 3 == 0) sb.AppendLine();
}
}
 
}
return sb.ToString();
}
 
 
private static IEnumerable<string> buildMonth(DateTime date)
{
yield return center(date.ToString("MMMM"),7*3);
var j = DateTime.DaysInMonth(date.Year, date.Month);
yield return Enum.GetNames(typeof(DayOfWeek)).Aggregate("", (current, result) => current + (result.Substring(0, 2).ToUpper() + " "));
string cur = "";
int total = 0;
 
foreach (var day in Enumerable.Range(-((int)date.DayOfWeek),j + (int)date.DayOfWeek))
{
cur += (day < 0 ? " " : ((day < 9 ? " " : "") + (day + 1))) +" ";
if (total++ > 0 && (total ) % 7 == 0)
{
yield return cur;
cur = "";
}
}
yield return cur;
}
private static string center(string s, int len)
{
return (s.PadLeft((len - s.Length) / 2 + s.Length, ' ').PadRight((len), ' '));
}
}
}
 
</syntaxhighlight>
=={{header|C++}}==
<langsyntaxhighlight lang="cpp">
#include <windows.h>
#include <iostream>
Line 1,641 ⟶ 2,172:
}
//--------------------------------------------------------------------------------------------------
</syntaxhighlight>
</lang>
Output:
<pre>
Line 1,686 ⟶ 2,217:
+----------------------+----------------------+----------------------+
</pre>
=={{header|Clojure}}==
{{trans|Common Lisp}}Java interop version.<br>
Does not use any external dependencies to demonstrate the java interop.<br>
Requires "join" from "clojure.string".<br>
Written by Kyuvi.<br>
 
<syntaxhighlight lang="clojure">(require '[clojure.string :only [join] :refer [join]])
=={{header|C sharp|C#}}==
An attempt to abuse the DateTime class for all static information. In the event that the number of days and months changes, so long as the DateTime class is updated accordingly, this should still print properly. It also abuses iterators to allow for a concise month printing method, but with the ability to still print x months per line.
 
(def day-row "Su Mo Tu We Th Fr Sa")
<lang csharp>
 
(def col-width (count day-row))
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
(defn month-to-word
namespace CalendarStuff
"Translate a month from 0 to 11 into its word representation."
{
[month]
((vec (.getMonths (new java.text.DateFormatSymbols))) month))
class Program
{
static void Main(string[] args)
{
Console.WindowHeight = 46;
Console.Write(buildMonths(new DateTime(1969, 1, 1)));
Console.Read();
}
private static string buildMonths(DateTime date)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine(center("[Snoop]", 24 * 3));
sb.AppendLine();
sb.AppendLine(center(date.Year.ToString(), 24 * 3));
 
(defn month [date]
List<DateTime> dts = new List<DateTime>();
(.get date (java.util.Calendar/MONTH)))
while (true)
{
dts.Add(date);
if (date.Year != ((date = date.AddMonths(1)).Year))
{
break;
}
}
var jd = dts.Select(a => buildMonth(a).GetEnumerator()).ToArray();
int sCur=0;
while (sCur<dts.Count)
{
sb.AppendLine();
int curMonth=0;
var j = jd.Where(a => curMonth++ >= sCur && curMonth - 1 < sCur + 3).ToArray(); //grab the next 3
sCur += j.Length;
bool breakOut = false;
while (!breakOut)
{
int inj = 1;
foreach (var cd in j)
{
if (cd.MoveNext())
{
sb.Append((cd.Current.Length == 21 ? cd.Current : cd.Current.PadRight(21, ' ')) + " ");
}
else
{
sb.Append("".PadRight(21, ' ') + " ");
breakOut = true;
}
if (inj++ % 3 == 0) sb.AppendLine();
}
}
 
(defn total-days-in-month [date]
}
(.getActualMaximum date (java.util.Calendar/DAY_OF_MONTH)))
return sb.ToString();
}
 
(defn first-weekday [date]
(.get date (java.util.Calendar/DAY_OF_WEEK)))
(defn normal-date-string
"Returns a formatted list of strings of the days of the month."
[date]
(map #(join " " %)
(partition 7
(concat
(repeat (dec (first-weekday date)) " ")
(map #(format "%2s" %)
(range 1 (inc (total-days-in-month date))))
(repeat (- 42 (total-days-in-month date)
(dec (first-weekday date)) ) " ")))))
(defn oct-1582-string
"Returns a formatted list of strings of the days of the month of October 1582."
[date]
(map #(join " " %)
(partition 7
(concat
(repeat (dec (first-weekday date)) " ")
(map #(format "%2s" %)
(concat (range 1 5)
(range 15 (inc (total-days-in-month date)))))
(repeat (- 42
(count (concat (range 1 5)
(range 15
(inc (total-days-in-month date)))))
(dec (first-weekday date)) ) " ")))))
 
private static IEnumerable<string> buildMonth(DateTime date)
{
yield return center(date.ToString("MMMM"),7*3);
var j = DateTime.DaysInMonth(date.Year, date.Month);
yield return Enum.GetNames(typeof(DayOfWeek)).Aggregate("", (current, result) => current + (result.Substring(0, 2).ToUpper() + " "));
string cur = "";
int total = 0;
 
(defn center-string
foreach (var day in Enumerable.Range(-((int)date.DayOfWeek),j + (int)date.DayOfWeek))
"Returns a string that is WIDTH long with STRING centered in it."
{
[string width]
cur += (day < 0 ? " " : ((day < 9 ? " " : "") + (day + 1))) +" ";
(let [pad (- width (count string))
if (total++ > 0 && (total ) % 7 == 0)
lpad (quot pad 2) {
rpad (- pad (quot pad yield return cur;2))]
(if (<= pad 0)
cur = "";
}string
(str (apply str (repeat lpad " ")) }; remove vector
string yield return cur;
(apply str (repeat rpad " "))))))
}
 
private static string center(string s, int len)
 
{
(defn calc-columns
return (s.PadLeft((len - s.Length) / 2 + s.Length, ' ').PadRight((len), ' '));
"Calculates the number of columns given the width in CHARACTERS and the
}
MARGIN }SIZE."
[characters margin-size]
}
(loop [cols 0 excess characters ]
(if (>= excess col-width)
(recur (inc cols) (- excess (+ margin-size col-width)))
cols)))
 
(defn month-vector
"Returns a vector with the month name, day-row and days
formatted for printing."
[date]
(vec (concat
(vector (center-string (month-to-word (month date)) col-width))
(vector day-row)
(if (and (= 1582 (.get date (java.util.Calendar/YEAR)))
(= 9 (month date)))
(oct-1582-string date)
(normal-date-string date)))))
 
(defn year-vector [date]
"Returns a 2d vector of all the months in the year of DATE."
(loop [m [] c (month date)]
(if (= c 11 )
(conj m (month-vector date))
(recur (conj m (month-vector date))
(do (.add date (java.util.Calendar/MONTH ) 1)
(month date))))))
 
(defn print-months
"Prints the months to standard output with NCOLS and MARGIN."
[ v ncols margin]
(doseq [r (range (Math/ceil (/ 12 ncols)))]
(do (doseq [i (range 8)]
(do (doseq [c (range (* r ncols) (* (+ r 1) ncols))
:while (< c 12)]
(printf (str (apply str (repeat margin " ")) "%s")
(get-in v [c i])))
(println)))
(println))))
 
(defn print-cal
"(print-cal [year [width [margin]]])
Prints out the calendar for a given YEAR with WIDTH characters wide and
with MARGIN spaces between months."
([]
(print-cal 1969 80 2))
([year]
(print-cal year 80 2))
([year width]
(print-cal year width 2))
([year width margin]
(assert (>= width (count day-row)) "Width should be more than 20.")
(assert (> margin 0) "Margin needs to be more than 0.")
(let [date (new java.util.GregorianCalendar year 0 1)
column-count (calc-columns width margin)
total-size (+ (* column-count (count day-row))
(* (dec column-count) margin))]
(println (center-string "[Snoopy Picture]" total-size))
(println (center-string (str year) total-size))
(println)
(print-months (year-vector date) column-count margin))))</syntaxhighlight>
 
 
 
<pre>user=> (print-cal)
[Snoopy Picture]
1969
 
January February March
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1
5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8
12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15
19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22
26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29
30 31
 
April May June
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 3 1 2 3 4 5 6 7
6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14
13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21
20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28
27 28 29 30 25 26 27 28 29 30 31 29 30
 
July August September
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 1 2 3 4 5 6
6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13
13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20
20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27
27 28 29 30 31 24 25 26 27 28 29 30 28 29 30
31
 
October November December
</lang>
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1 2 3 4 5 6
5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13
12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20
19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27
26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30
 
nil</pre>
=={{header|COBOL}}==
the program calls subroutine DATE2DOW to convert any YYYY-MM-DD to Day of Week (1=Sunday). the group names WS-CFGN
and WS-CFGW may be moved to WS-CFG to use narrow or wide print line size respectively.
<syntaxhighlight lang="cobol">
<lang COBOL>
IDENTIFICATION DIVISION.
PROGRAM-ID. CALEND.
Line 2,015 ⟶ 2,623:
.
END PROGRAM DATE2DOW.
</syntaxhighlight>
</lang>
Output (based on 80 character wide display)
<pre>
Line 2,054 ⟶ 2,662:
30
</pre>
 
=={{header|Common Lisp}}==
Depends on quicklisp.
<langsyntaxhighlight lang="lisp">(ql:quickload '(date-calc))
 
(defparameter *day-row* "Su Mo Tu We Th Fr Sa")
Line 2,131 ⟶ 2,738:
(lambda (&rest heads)
(format t format-string heads))
row))))</langsyntaxhighlight>
{{out}}
<pre>CL-USER> (print-calendar 1969)
Line 2,170 ⟶ 2,777:
30
NIL</pre>
 
=={{header|D}}==
<langsyntaxhighlight lang="d">import std.stdio, std.datetime, std.string, std.conv;
 
void printCalendar(in uint year, in uint nCols)
Line 2,214 ⟶ 2,820:
void main() {
printCalendar(1969, 3);
}</langsyntaxhighlight>
 
<pre> [Snoopy Picture]
Line 2,254 ⟶ 2,860:
26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30</pre>
=={{header|Delphi}}==
{{libheader| System.SysUtils}}
{{libheader| System.DateUtils}}
{{Trans|D}}
<syntaxhighlight lang="delphi">
program Calendar;
 
{$APPTYPE CONSOLE}
 
uses
System.SysUtils,
System.DateUtils;
 
function Center(s: string; width: Integer): string;
var
side: Integer;
begin
if s.Length >= width then
exit(s);
side := (width - s.Length) div 2;
Result := s + string.Create(' ', side);
Result := string.Create(' ', width - Result.Length) + Result;
end;
 
procedure PrintCalendar(year, nCols: word; local: string = 'en-US');
var
fmt: TFormatSettings;
begin
if (nCols <= 0) or (nCols > 12) then
exit;
fmt := TFormatSettings.Create(local);
var rows := 12 div nCols + ord(12 mod nCols <> 0);
var date := EncodeDate(year, 1, 1);
var offs := DayOfTheWeek(date);
 
var months: TArray<string>;
setlength(months, 12);
for var i := 1 to 12 do
months[i - 1] := fmt.LongMonthNames[i];
 
var sWeek := '';
for var i := 1 to 7 do
sWeek := sWeek + ' ' + copy(fmt.ShortDayNames[i], 1, 2);
 
var mons: TArray<TArray<string>>;
SetLength(mons, 12, 8);
for var m := 0 to 11 do
begin
mons[m, 0] := Center(months[m], 21);
mons[m, 1] := sWeek;
var dim := DaysInMonth(date);
for var d := 1 to 43 do
begin
var day := (d > offs) and (d <= offs + dim);
var str := ' ';
if day then
str := format(' %2d', [d - offs]);
mons[m, 2 + (d - 1) div 7] := mons[m, 2 + (d - 1) div 7] + str;
end;
offs := (offs + dim) mod 7;
date := IncMonth(date, 1);
end;
writeln(Center('[Snoopy Picture]', nCols * 24 + 4));
Writeln(Center(year.ToString, nCols * 24 + 4));
writeln;
 
for var r := 0 to rows - 1 do
begin
var s: TArray<string>;
SetLength(s, 8);
for var c := 0 to nCols - 1 do
begin
if r * nCols + c > 11 then
Break;
for var i := 0 to High(mons[r * nCols + c]) do
begin
var line := mons[r * nCols + c, i];
s[i] := s[i] + ' ' + line;
end;
end;
 
for var ss in s do
begin
writeln(ss, ' ');
end;
writeln;
end;
 
end;
 
begin
printCalendar(1969, 4);
readln;
end.</syntaxhighlight>
{{out}}
<pre> [Snoopy Picture]
1969
 
January February March April
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1 1 2 3 4 5
5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8 6 7 8 9 10 11 12
12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15 13 14 15 16 17 18 19
19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22 20 21 22 23 24 25 26
26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29 27 28 29 30
30 31
 
May June July August
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 1 2 3 4 5 6 7 1 2 3 4 5 1 2
4 5 6 7 8 9 10 8 9 10 11 12 13 14 6 7 8 9 10 11 12 3 4 5 6 7 8 9
11 12 13 14 15 16 17 15 16 17 18 19 20 21 13 14 15 16 17 18 19 10 11 12 13 14 15 16
18 19 20 21 22 23 24 22 23 24 25 26 27 28 20 21 22 23 24 25 26 17 18 19 20 21 22 23
25 26 27 28 29 30 31 29 30 27 28 29 30 31 24 25 26 27 28 29 30
31
 
September October November December
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 6 1 2 3 4 1 1 2 3 4 5 6
7 8 9 10 11 12 13 5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13
14 15 16 17 18 19 20 12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20
21 22 23 24 25 26 27 19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27
28 29 30 26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30</pre>
=={{header|EasyLang}}==
{{trans|AWK}}
<syntaxhighlight>
year = 1969
#
wkdays$ = "Su Mo Tu We Th Fr Sa"
pagewide = 80
blank$ = ""
month$[] = [ " January " " February " " March " " April " " May " " June " " July " " August " " September" " October " " November " " December " ]
days[] = [ 31 28 31 30 31 30 31 31 30 31 30 31 ]
#
func$ center txt$ .
h$ = substr blank$ 1 ((pagewide - len txt$) / 2)
return h$ & txt$ & h$
.
func$ makewk fst lst day .
for i to day - 1
wstr$ &= " "
.
for i = fst to lst
i$ = i
if i <= 9
i$ = " " & i
.
wstr$ &= i$ & " "
.
return substr wstr$ & blank$ 1 20
.
proc dow y . ndow leap .
leap = 0
if y mod 4 = 0
leap = 1
.
if y mod 100 = 0
leap = 0
.
if y mod 400 = 0
leap = 1
.
ndow = y * 365 + y div 4 - y div 100 + y div 400 + 1
ndow = (ndow - leap) mod1 7
.
len lin$[] 8
proc prmonth nmonth newdow monsize . .
lin$[1] &= " " & month$[nmonth] & " "
lin$[2] &= wkdays$ & " "
lin$[3] &= makewk 1 (8 - newdow) newdow & " "
for i = 4 to 7
lin$[i] &= makewk (9 + h - newdow) lower monsize (15 + h - newdow) 1 & " "
h += 7
.
lin$[8] &= makewk (37 - newdow) monsize 1 & " "
if len lin$[3] + 22 > pagewide
for i to 8
print center lin$[i]
lin$[i] = ""
.
.
.
for i to pagewide
blank$ &= " "
.
dow year newdow leap
print center "[ picture of Snoopy goes here ]"
print center year
for i = 1 to 12
monsize = days[i]
if i = 2 and leap = 1
monsize = 29
.
prmonth i newdow monsize
newdow = (monsize + newdow) mod1 7
.
</syntaxhighlight>
 
=={{header|F Sharp|F#}}==
<syntaxhighlight lang="fsharp">let getCalendar year =
let day_of_week month year =
let t = [|0; 3; 2; 5; 0; 3; 5; 1; 4; 6; 2; 4|]
let y = if month < 3 then year - 1 else year
let m = month
let d = 1
(y + y / 4 - y / 100 + y / 400 + t.[m - 1] + d) % 7
//0 = Sunday, 1 = Monday, ...
 
let last_day_of_month month year =
match month with
| 2 -> if (0 = year % 4 && (0 = year % 400 || 0 <> year % 100)) then 29 else 28
| 4 | 6 | 9 | 11 -> 30
| _ -> 31
 
let get_month_calendar year month =
let min (x: int, y: int) = if x < y then x else y
let ld = last_day_of_month month year
let dw = 7 - (day_of_week month year)
[|[|1..dw|];
[|dw + 1..dw + 7|];
[|dw + 8..dw + 14|];
[|dw + 15..dw + 21|];
[|dw + 22..min(ld, dw + 28)|];
[|min(ld + 1, dw + 29)..ld|]|]
let sb_fold (f:System.Text.StringBuilder -> 'a -> System.Text.StringBuilder) (sb:System.Text.StringBuilder) (xs:'a array) =
for x in xs do (f sb x) |> ignore
sb
 
let sb_append (text:string) (sb:System.Text.StringBuilder) = sb.Append(text)
 
let sb_appendln sb = sb |> sb_append "\n" |> ignore
 
let sb_fold_in_range a b f sb = [|a..b|] |> sb_fold f sb |> ignore
 
let mask_builder mask = Printf.StringFormat<string -> string>(mask)
let center n (s:string) =
let l = (n - s.Length) / 2 + s.Length
let f n s = sprintf (mask_builder ("%" + (n.ToString()) + "s")) s
(f l s) + (f (n - l) "")
let left n (s:string) = sprintf (mask_builder ("%-" + (n.ToString()) + "s")) s
let right n (s:string) = sprintf (mask_builder ("%" + (n.ToString()) + "s")) s
 
let array2string xs =
let ys = xs |> Array.map (fun x -> sprintf "%2d " x)
let sb = ys |> sb_fold (fun sb y -> sb.Append(y)) (new System.Text.StringBuilder())
sb.ToString()
 
let xsss =
let m = get_month_calendar year
[|1..12|] |> Array.map (fun i -> m i)
 
let months = [|"January"; "February"; "March"; "April"; "May"; "June"; "July"; "August"; "September"; "October"; "November"; "December"|]
 
let sb = new System.Text.StringBuilder()
sb |> sb_append "\n" |> sb_append (center 74 (year.ToString())) |> sb_appendln
for i in 0..3..9 do
sb |> sb_appendln
sb |> sb_fold_in_range i (i + 2) (fun sb i -> sb |> sb_append (center 21 months.[i]) |> sb_append " ")
sb |> sb_appendln
sb |> sb_fold_in_range i (i + 2) (fun sb i -> sb |> sb_append "Su Mo Tu We Th Fr Sa " |> sb_append " ")
sb |> sb_appendln
sb |> sb_fold_in_range i (i + 2) (fun sb i -> sb |> sb_append (right 21 (array2string (xsss.[i].[0]))) |> sb_append " ")
sb |> sb_appendln
for j = 1 to 5 do
sb |> sb_fold_in_range i (i + 2) (fun sb i -> sb |> sb_append (left 21 (array2string (xsss.[i].[j]))) |> sb_append " ")
sb |> sb_appendln
sb.ToString()
 
let printCalendar year = getCalendar year</syntaxhighlight>
 
{{out}}
<pre>> printCalendar 1969;;
val it : string =
"
1969
 
January February March
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1
5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8
12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15
19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22
26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29
30 31
 
April May June
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 3 1 2 3 4 5 6 7
6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14
13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21
20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28
27 28 29 30 25 26 27 28 29 30 31 29 30
 
 
July August September
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 1 2 3 4 5 6
6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13
13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20
20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27
27 28 29 30 31 24 25 26 27 28 29 30 28 29 30
31
 
October November December
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1 2 3 4 5 6
5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13
12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20
19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27
26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30
"</pre>
 
=={{header|Factor}}==
<syntaxhighlight lang="factor">USING: arrays calendar.format grouping io.streams.string kernel
math.ranges prettyprint sequences sequences.interleaved ;
IN: rosetta-code.calendar
 
: calendar ( year -- )
12 [1,b] [ 2array [ month. ] with-string-writer ] with map
3 <groups> [ " " <interleaved> ] map 5 " " <repetition>
<interleaved> simple-table. ;
 
: calendar-demo ( -- ) 1969 calendar ;
 
MAIN: calendar-demo</syntaxhighlight>
{{out}}
<pre>
January 1969 February 1969 March 1969
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1
5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8
12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15
19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22
26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29
30 31
April 1969 May 1969 June 1969
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 3 1 2 3 4 5 6 7
6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14
13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21
20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28
27 28 29 30 25 26 27 28 29 30 31 29 30
July 1969 August 1969 September 1969
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 1 2 3 4 5 6
6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13
13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20
20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27
27 28 29 30 31 24 25 26 27 28 29 30 28 29 30
31
October 1969 November 1969 December 1969
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1 2 3 4 5 6
5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13
12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20
19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27
26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30
</pre>
=={{header|Forth}}==
<syntaxhighlight lang="forth">
: weekday ( d m y -- u )
over 3 < if swap 12 + swap 1- then
dup 4 / over 100 / - over 400 / + + swap 1+ 13 * 5 / + + 2 - 7 mod ;
: mdays ( m y -- msize mday )
over 12 = if 31 1 2swap weekday negate exit then
2>r 1 2r@ weekday 1 2r> swap 1+ swap weekday over -
7 + 7 mod 28 + swap negate ;
: .week ( msize mday -- msize mday' )
7 0 do dup 0< if 1+ 3 spaces else
2dup > if 1+ dup 2 .r space else 3 spaces then then loop ;
: .3months ( y m -- )
3 0 do ." Mo Tu We Th Fr Sa Su " loop cr
3 over + swap do i over mdays rot loop drop
6 0 do 2rot .week 2 spaces 2rot .week 2 spaces 2rot .week cr loop
2drop 2drop 2drop ;
 
: cal ( y -- )
30 spaces ." [Snoopy]" cr
32 spaces dup . cr
." January February March" cr
dup 1 .3months
." April May June" cr
dup 4 .3months
." July August September" cr
dup 7 .3months
." October November December" cr
10 .3months ;
 
1969 cal
</syntaxhighlight>
{{out}}
<pre>
[Snoopy]
1969
January February March
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 5 1 2 1 2
6 7 8 9 10 11 12 3 4 5 6 7 8 9 3 4 5 6 7 8 9
13 14 15 16 17 18 19 10 11 12 13 14 15 16 10 11 12 13 14 15 16
20 21 22 23 24 25 26 17 18 19 20 21 22 23 17 18 19 20 21 22 23
27 28 29 30 31 24 25 26 27 28 24 25 26 27 28 29 30
31
April May June
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 5 6 1 2 3 4 1
7 8 9 10 11 12 13 5 6 7 8 9 10 11 2 3 4 5 6 7 8
14 15 16 17 18 19 20 12 13 14 15 16 17 18 9 10 11 12 13 14 15
21 22 23 24 25 26 27 19 20 21 22 23 24 25 16 17 18 19 20 21 22
28 29 30 26 27 28 29 30 31 23 24 25 26 27 28 29
30
July August September
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 5 6 1 2 3 1 2 3 4 5 6 7
7 8 9 10 11 12 13 4 5 6 7 8 9 10 8 9 10 11 12 13 14
14 15 16 17 18 19 20 11 12 13 14 15 16 17 15 16 17 18 19 20 21
21 22 23 24 25 26 27 18 19 20 21 22 23 24 22 23 24 25 26 27 28
28 29 30 31 25 26 27 28 29 30 31 29 30
October November December
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 5 1 2 1 2 3 4 5 6 7
6 7 8 9 10 11 12 3 4 5 6 7 8 9 8 9 10 11 12 13 14
13 14 15 16 17 18 19 10 11 12 13 14 15 16 15 16 17 18 19 20 21
20 21 22 23 24 25 26 17 18 19 20 21 22 23 22 23 24 25 26 27 28
27 28 29 30 31 24 25 26 27 28 29 30 29 30 31
</pre>
=={{header|Fortran}}==
Already having a routine to produce a calendar simplified matters. However, it added to each row of days a row of annotations for those days (Xmas, etc. and also +2hh and -2hh for the days with two half-hour changes in length due to daylight saving: NZ also had daylight saving with changes of one half-hour) which meant that the field allowance was always four. With the annotations abandoned, this could be reduced to three, and, the first day column on a line does not need a leading space. Since the method employed variables for the layout, it could easily be twiddled to have three months per line (thus fitting into a line length of 80) or six (using most of a line length of 132) and so it became a matter of pulling together the needed routines from various places.
<syntaxhighlight lang="fortran">
<lang Fortran>
MODULE DATEGNASH !Assorted vexations. Time and calendar games, with local flavourings added.
 
Line 2,541 ⟶ 3,583:
END DO
END
</syntaxhighlight>
</lang>
Selected output, lacking alas the outbursts from Snoopy: three months /line
<pre>
Line 2,598 ⟶ 3,640:
</pre>
=={{header|FreeBASIC}}==
<langsyntaxhighlight lang="freebasic">' version 17-02-2016
' compile with: fbc -s console
 
Line 2,722 ⟶ 3,764:
'Print : Print "hit any key to end program
Sleep
End</langsyntaxhighlight>
{{out}}
<pre> 1969
Line 2,741 ⟶ 3,783:
21 22 23 24 25 26 27 18 19 20 21 22 23 24 22 23 24 25 26 27 28 20 21 22 23 24 25 26 17 18 19 20 21 22 23 22 23 24 25 26 27 28
28 29 30 31 25 26 27 28 29 30 31 29 30 27 28 29 30 31 24 25 26 27 28 29 30 29 30 31 </pre>
=={{header|FutureBasic}}==
Legacy version:
<syntaxhighlight lang="futurebasic">window 1, @"Calendar", (0, 0, 520, 520 )
 
Str255 a
=={{header|F Sharp}}==
<lang fsharp>let getCalendar year =
let day_of_week month year =
let t = [|0; 3; 2; 5; 0; 3; 5; 1; 4; 6; 2; 4|]
let y = if month < 3 then year - 1 else year
let m = month
let d = 1
(y + y / 4 - y / 100 + y / 400 + t.[m - 1] + d) % 7
//0 = Sunday, 1 = Monday, ...
 
open "UNIX", 1,"cal 1969"
let last_day_of_month month year =
do
match month with
line input #1, a
| 2 -> if (0 = year % 4 && (0 = year % 400 || 0 <> year % 100)) then 29 else 28
print a
| 4 | 6 | 9 | 11 -> 30
until eof(1)
| _ -> 31
close 1
 
HandleEvents</syntaxhighlight>
let get_month_calendar year month =
let min (x: int, y: int) = if x < y then x else y
let ld = last_day_of_month month year
let dw = 7 - (day_of_week month year)
[|[|1..dw|];
[|dw + 1..dw + 7|];
[|dw + 8..dw + 14|];
[|dw + 15..dw + 21|];
[|dw + 22..min(ld, dw + 28)|];
[|min(ld + 1, dw + 29)..ld|]|]
let sb_fold (f:System.Text.StringBuilder -> 'a -> System.Text.StringBuilder) (sb:System.Text.StringBuilder) (xs:'a array) =
for x in xs do (f sb x) |> ignore
sb
 
Modern version:
let sb_append (text:string) (sb:System.Text.StringBuilder) = sb.Append(text)
<syntaxhighlight lang="futurebasic">include "NSLog.incl"
 
local fn RunCommand( command as CFStringRef ) as CFStringRef
let sb_appendln sb = sb |> sb_append "\n" |> ignore
TaskRef tsk = fn TaskInit
TaskSetExecutableURL( tsk, fn URLFileURLWithPath( @"/bin/sh" ) )
TaskSetArguments( tsk, @[@"-c",command] )
PipeRef pip = fn PipeInit
TaskSetStandardOutput( tsk, pip )
FileHandleRef fh = fn PipeFileHandleForReading( pip )
fn TaskLaunch( tsk, NULL )
CFDataRef dta = fn FileHandleReadDataToEndOfFile( fh, NULL )
CFStringRef outputStr = fn StringWithData( dta, NSUTF8StringEncoding )
end fn = outputStr
 
NSLog( @"%@", fn RunCommand( @"cal 1969" ) )
let sb_fold_in_range a b f sb = [|a..b|] |> sb_fold f sb |> ignore
 
HandleEvents</syntaxhighlight>
let mask_builder mask = Printf.StringFormat<string -> string>(mask)
let center n (s:string) =
let l = (n - s.Length) / 2 + s.Length
let f n s = sprintf (mask_builder ("%" + (n.ToString()) + "s")) s
(f l s) + (f (n - l) "")
let left n (s:string) = sprintf (mask_builder ("%-" + (n.ToString()) + "s")) s
let right n (s:string) = sprintf (mask_builder ("%" + (n.ToString()) + "s")) s
 
Output of either version:
let array2string xs =
let ys = xs |> Array.map (fun x -> sprintf "%2d " x)
let sb = ys |> sb_fold (fun sb y -> sb.Append(y)) (new System.Text.StringBuilder())
sb.ToString()
 
let xsss =
let m = get_month_calendar year
[|1..12|] |> Array.map (fun i -> m i)
 
let months = [|"January"; "February"; "March"; "April"; "May"; "June"; "July"; "August"; "September"; "October"; "November"; "December"|]
 
let sb = new System.Text.StringBuilder()
sb |> sb_append "\n" |> sb_append (center 74 (year.ToString())) |> sb_appendln
for i in 0..3..9 do
sb |> sb_appendln
sb |> sb_fold_in_range i (i + 2) (fun sb i -> sb |> sb_append (center 21 months.[i]) |> sb_append " ")
sb |> sb_appendln
sb |> sb_fold_in_range i (i + 2) (fun sb i -> sb |> sb_append "Su Mo Tu We Th Fr Sa " |> sb_append " ")
sb |> sb_appendln
sb |> sb_fold_in_range i (i + 2) (fun sb i -> sb |> sb_append (right 21 (array2string (xsss.[i].[0]))) |> sb_append " ")
sb |> sb_appendln
for j = 1 to 5 do
sb |> sb_fold_in_range i (i + 2) (fun sb i -> sb |> sb_append (left 21 (array2string (xsss.[i].[j]))) |> sb_append " ")
sb |> sb_appendln
sb.ToString()
 
let printCalendar year = getCalendar year</lang>
 
{{out}}
<pre>> printCalendar 1969;;
val it : string =
"
1969
 
January February March
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1
5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8
12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15
19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22
26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29
30 31
 
April May June
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 3 1 2 3 4 5 6 7
6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14
13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21
20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28
27 28 29 30 25 26 27 28 29 30 31 29 30
 
 
July August September
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 1 2 3 4 5 6
6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13
13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20
20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27
27 28 29 30 31 24 25 26 27 28 29 30 28 29 30
31
 
October November December
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1 2 3 4 5 6
5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13
12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20
19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27
26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30
"</pre>
 
=={{header|FutureBasic}}==
<lang futurebasic>
include "ConsoleWindow"
 
dim as Str255 a
 
open "UNIX", 1,"cal 1969"
do
line input #1, a
print a
until eof(1)
close 1
</lang>
 
Output:
<pre>
1969
Line 2,909 ⟶ 3,854:
30
</pre>
 
=={{header|Gambas}}==
<langsyntaxhighlight lang="gambas">Public Sub Main()
 
Shell "cal 1969"
 
End</langsyntaxhighlight>
Output:
<pre>
Line 2,955 ⟶ 3,899:
30
</pre>
 
=={{header|Go}}==
<langsyntaxhighlight Golang="go">package main
 
import (
Line 3,027 ⟶ 3,970:
fmt.Println()
}
}</langsyntaxhighlight>
Output:
<pre> [SNOOPY]
Line 3,069 ⟶ 4,012:
30
</pre>
 
=={{header|Haskell}}==
<langsyntaxhighlight Haskelllang="haskell">import qualified Data.Text as T
import Data.Time
import Data.Time.Calendar
Line 3,160 ⟶ 4,102:
calcol' = calColFromCol columns
 
columns' = colFromCalCol calcol'</langsyntaxhighlight>
<pre>*Main> printCalendar 1969 80
[Maybe Snoopy]
Line 3,197 ⟶ 4,139:
26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30</pre>
 
=={{header|Huginn}}==
<langsyntaxhighlight lang="huginn">import DateTime as dt;
import Algorithms as algo;
import Text as text;
Line 3,259 ⟶ 4,200:
cols
);
}</langsyntaxhighlight>
 
Output: <pre> 1969
Line 3,295 ⟶ 4,236:
20 21 22 23 24 25 26 17 18 19 20 21 22 23 22 23 24 25 26 27 28
27 28 29 30 31 24 25 26 27 28 29 30 29 30 31</pre>
 
=={{header|Icon}} and {{header|Unicon}}==
The procedures ''printCalendar'' handles formatting of large components and uses co-expressions to keep the formatting of week elements in each column synchronized. The procedure ''CalendarFormatWeek'' is a generator that returns heading elements, alignment spacing, and individual days.
<langsyntaxhighlight Iconlang="icon">procedure main(A)
printCalendar(\A[1]|1969)
end
Line 3,342 ⟶ 4,282:
if m = 2 & IsLeapYear(year) then suspend (d +:= 1, 29) # LY adjustment
every d to (6*7) do suspend "" # trailer alignment
end</langsyntaxhighlight>
 
{{libheader|Icon Programming Library}}
Line 3,382 ⟶ 4,322:
26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30</pre>
 
=={{header|J}}==
'''Solution:'''
<langsyntaxhighlight lang="j">require 'dates format' NB. J6.x
require 'dates general/misc/format' NB. J7.x
calBody=: (1 1 }. _1 _1 }. ":)@(-@(<.@%&22)@[ ]\ calendar@])
calTitle=: (<: - 22&|)@[ center '[Insert Snoopy here]' , '' ,:~ ":@]
formatCalendar=: calTitle , calBody</langsyntaxhighlight>
'''Example use:'''
<langsyntaxhighlight lang="j"> 80 formatCalendar 1969
[Insert Snoopy here]
1969
Line 3,429 ⟶ 4,368:
19 20 21 22 23 24 25│ 16 17 18 19 20 21 22│ 21 22 23 24 25 26 27
26 27 28 29 30 31 │ 23 24 25 26 27 28 29│ 28 29 30 31
│ 30 │ </langsyntaxhighlight>
 
=={{header|Java}}==
{{trans|D}}
<langsyntaxhighlight lang="java">import java.text.*;
import java.util.*;
 
Line 3,489 ⟶ 4,427:
}
}
}</langsyntaxhighlight>
 
{{out}}
Line 3,531 ⟶ 4,469:
26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30 </pre>
=={{header|JuliaJavaScript}}==
<syntaxhighlight lang="javascript">/**
The program implements three calendar row formatting variants, but is set up for the IBM 3270 terminal here.
* Given a width, return a function that takes a string, and
<lang julia>using Dates
* pads it at both ends to the given width
* @param {number} width
* @returns {function(string): string}
*/
const printCenter = width =>
s => s.padStart(width / 2 + s.length / 2, ' ').padEnd(width);
 
/**
const pagesizes = Dict( "lpr" => [132, 66], "tn3270" => [80, 43])
* Given an locale string and options, return a function that takes a date
* object, and retrurns the date formatted to the locale and options.
* @param {string} locale
* @param {DateTimeFormatOptions} options
* @returns {function(Date): string}
*/
const localeName = (locale, options) => {
const formatter = new Intl.DateTimeFormat(locale, options);
return date => formatter.format(date);
};
 
/**
* Increment the date by number.
* @param {Date} date
* @param {number} inc
* @returns {Date}
*/
const addDay = (date, inc = 1) => {
const res = new Date(date.valueOf());
res.setDate(date.getDate() + inc);
return res;
}
 
/**
* Given a date, build a string of the week, and return it along with
* the mutated date object.
* @param {Date} date
* @returns {[boolean, Date, string]}
*/
const makeWeek = date => {
const month = date.getMonth();
let [wdi, md, m] = [date.getUTCDay(), date.getDate(), date.getMonth()];
const line = Array(7).fill(' ').map((e, i) => {
if (i === wdi && m === month) {
const result = (md + '').padStart(2, ' ');
date = addDay(date);
[wdi, md, m] = [date.getUTCDay(), date.getDate(), date.getMonth()];
return result;
} else {
return e;
}
}).join(' ');
return [month !== m, date, line];
}
 
/**
* Print a nicely formatted calender for the given year in the given locale.
* @param {number} year The required year of the calender
* @param {string} locale The locale string. Defaults to US English.
* @param {number} cols The number of columns for the months. Defaults to 3.
* @param {number} coll_space The space between the columns. Defaults to 5.
*/
const cal = (year, locale = 'en-US', cols = 3, coll_space = 5) => {
const MONTH_LINES = 9; // Number of lines that make up a month.
const MONTH_COL_WIDTH = 20; // Character width of a month
const COL_SPACE = ' '.padStart(coll_space);
const FULL_WIDTH = MONTH_COL_WIDTH * cols + coll_space * (cols - 1);
 
const collArr = Array(cols).fill('');
const monthName = localeName(locale, {month: 'long'});
const weekDayShort = localeName(locale, {weekday: 'short'});
const monthCenter = printCenter(MONTH_COL_WIDTH);
const pageCenter = printCenter(FULL_WIDTH);
 
// Get the weekday in the given locale.
const sun = new Date(Date.UTC(2017, 0, 1)); // A sunday
const weekdays = Array(7).fill('').map((e, i) =>
weekDayShort(addDay(sun, i)).padStart(2, ' ').substring(0, 2)).join(' ');
 
// The start date.
let date = new Date(Date.UTC(year, 0, 1, 0, 0, 0));
let nextMonth = true;
let line = '';
const fullYear = date.getUTCFullYear();
 
// The array into which each of the lines are populated.
const accumulate = [];
 
// Populate the month table heading and columns.
const preAmble = date => {
accumulate.push(monthCenter(' '))
accumulate.push(monthCenter(monthName(date)));
accumulate.push(weekdays);
};
 
// Accumulate the week lines for the year.
while (date.getUTCFullYear() === fullYear) {
if (nextMonth) {
if (accumulate.length % MONTH_LINES !== 0) {
accumulate.push(monthCenter(' '))
}
preAmble(date);
}
[nextMonth, date, line] = makeWeek(date);
accumulate.push(line);
}
 
// Print the calendar.
console.log(pageCenter(String.fromCodePoint(0x1F436)));
console.log(pageCenter(`--- ${fullYear} ---`));
accumulate.reduce((p, e, i) => {
if (!p.includes(i)) {
const indexes = collArr.map((e, ci) => i + ci * MONTH_LINES);
console.log(indexes.map(e => accumulate[e]).join(COL_SPACE));
p.push(...indexes);
}
return p;
}, []);
};
 
cal(1969, 'en-US', 3);
</syntaxhighlight>
{{out}}
<pre>
 
🐶
--- 1969 ---
January February March
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1
5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8
12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15
19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22
26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29
30 31
April May June
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 3 1 2 3 4 5 6 7
6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14
13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21
20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28
27 28 29 30 25 26 27 28 29 30 31 29 30
July August September
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 1 2 3 4 5 6
6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13
13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20
20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27
27 28 29 30 31 24 25 26 27 28 29 30 28 29 30
31
October November December
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1 2 3 4 5 6
5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13
12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20
19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27
26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30
</pre>
=={{header|jq}}==
'''Adapted from [[#Wren|Wren]]'''
{{works with|jq}}
'''Also works with gojq, the Go implementation of jq'''
 
'''Also works with fq, a Go implementation of a large subset of jq'''
 
'''Utility Functions'''
<syntaxhighlight lang=jq>
def nwise($n):
def n: if length <= $n then . else .[0:$n] , (.[$n:] | n) end;
n;
 
def lpad($len): tostring | ($len - length) as $l | (" " * $l)[:$l] + .;
 
def center(width):
tostring
| length as $l
| ((width - $l)/2 | floor) as $k
| (" " * $k) + . + (" " * (width - ($k+$l)));
</syntaxhighlight>
'''Calendrical Functions'''
<syntaxhighlight lang=jq>
def weekdaynames: ["Su", "Mo","Tu", "We", "Th", "Fr", "Sa"];
 
# q.v. weekday
# Output the integer index of weekdaynames, i.e. Sunday is 0
def dayofweek($year; $month; $day):
"\($year)-\($month)-\($day)" | strptime("%Y-%m-%d") | .[-2];
 
def isLeapYear(y):
y%4 == 0 and ((y%100 != 0) or (y%400 == 0));
 
# January is 1
def monthLength($y; $m):
def __diy: [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365];
def __diy2: [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366];
 
if isLeapYear($y)
then __diy2[$m] - __diy2[$m-1]
else __diy[$m] - __diy[$m-1]
end;
 
def calendar(year):
def snoopy: "🐶";
def months: [
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December" ];
(weekdaynames | join(" ")) as $days
# $chunk is a list of three months in group number $c
| def printRow($chunk; $c):
# The line of month names:
(" " + ($chunk | map(center(20)) | join(" "))),
# The line of weekday names
(" " + ([range(0;3)| $days] | join(" "))),
# The body of the calendar
( [ dayofweek(year; $c*3 + 1; 1),
dayofweek(year; $c*3 + 2; 1),
dayofweek(year; $c*3 + 3; 1)] as $first
| [ monthLength(year; $c*3 + 1),
monthLength(year; $c*3 + 2),
monthLength(year; $c*3 + 3) ] as $mlen
# Print up to 6 lines
| range(0;6) as $i
| reduce range(0;3) as $j ("";
(1 + (7 * $i) - $first[$j]) as $start
| (reduce range($start; $start+7) as $k (.;
if ($k >= 1 and $k <= $mlen[$j])
then . + ($k|lpad(3))
else . + " "
end ) + " " ) )
),
"";
 
(snoopy, "--- \(year) ---" | center(72)),
( [months|nwise(3)] as $chunks
| range(0;3) | printRow( $chunks[.]; .) );
 
calendar(1969)
</syntaxhighlight>
{{output}}
As for [[#Wren|Wren]].
 
=={{header|Julia}}==
<syntaxhighlight lang="julia">
using Dates
const pagesizes = Dict( "lpr" => [132, 66], "tn3270" => [80, 43])
pagefit(prn) = haskey(pagesizes, prn) ?
[div(pagesizes[prn][1], 22), div(pagesizes[prn][2], 12)] : [1, 1]
pagecols(prn) = haskey(pagesizes, prn) ? pagesizes[prn][1] : 20
 
function centerobject(x, cols)
content = string(x)
rpad(lpad(content, div(cols + length(content), 2)), cols)
end
 
function ljustlines(x, cols)
arr = Vector{String}()
Line 3,553 ⟶ 4,739:
join(arr, "\n")
end
 
function formatmonth(yr, mo)
dt = Date("$yr-$mo-01")
dayofweekfirst = dayofweek(dt)
numweeklines = 1
 
str = centerobject(monthname(dt), 20) * "\nMo Tu We Th Fr Sa Su\n"
str *= " " ^ (3 * (dayofweekfirst - 1)) * lpad(string(1), 2)
str *= lpad(string(1), 2)
for i = 2:daysinmonth(dt)
if (i + dayofweekfirst + 5) % 7 == 0
str *= "\n" * lpad(i, 2)
numweeklines += 1
str *= lpad(i, 2)
else
str *= lpad(string(i), 3)
end
end
str *= numweeklines < 6 ? "\n\n\n" : "\n\n"
if numweeklines < 6
str *= "\n"
end
ljustlines(str, 20)
end
 
function formatyear(displayyear, printertype)
calmonths = [formatmonth(displayyear, mo) for mo in 1:12]
columns = pagecols(printertype)
monthsperline = pagefit(printertype)[1]
joinspaces = max( (monthsperline > 1) ?
div(columns - monthsperline * 20, monthsperline - 1) : 1, 1)
joinspaces = max(joinspaces, 1)
str = "\n" * centerobject(displayyear, columns) * "\n"
monthcal = [split(formatmonth(displayyear, i), "\n") for i in 1:12]
Line 3,597 ⟶ 4,775:
str
end
 
function lineprintcalendar(years)
for year in years, printer in ["tn3270"]keys(pagesizes)
println(formatyear(year, printer))
end
end
 
lineprintcalendar(1969)
</syntaxhighlight>
</lang> {{output}} <pre>
'''
1969
January February March
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 5 1 2 1 2
6 7 8 9 10 11 12 3 4 5 6 7 8 9 3 4 5 6 7 8 9
13 14 15 16 17 18 19 10 11 12 13 14 15 16 10 11 12 13 14 15 16
20 21 22 23 24 25 26 17 18 19 20 21 22 23 17 18 19 20 21 22 23
27 28 29 30 31 24 25 26 27 28 24 25 26 27 28 29 30
31
 
 
 
April May June
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 5 6 1 2 3 4 1
7 8 9 10 11 12 13 5 6 7 8 9 10 11 2 3 4 5 6 7 8
14 15 16 17 18 19 20 12 13 14 15 16 17 18 9 10 11 12 13 14 15
21 22 23 24 25 26 27 19 20 21 22 23 24 25 16 17 18 19 20 21 22
28 29 30 26 27 28 29 30 31 23 24 25 26 27 28 29
30
 
 
 
July August September
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 5 6 1 2 3 1 2 3 4 5 6 7
7 8 9 10 11 12 13 4 5 6 7 8 9 10 8 9 10 11 12 13 14
14 15 16 17 18 19 20 11 12 13 14 15 16 17 15 16 17 18 19 20 21
21 22 23 24 25 26 27 18 19 20 21 22 23 24 22 23 24 25 26 27 28
28 29 30 31 25 26 27 28 29 30 31 29 30
 
 
 
 
October November December
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 5 1 2 1 2 3 4 5 6 7
6 7 8 9 10 11 12 3 4 5 6 7 8 9 8 9 10 11 12 13 14
13 14 15 16 17 18 19 10 11 12 13 14 15 16 15 16 17 18 19 20 21
20 21 22 23 24 25 26 17 18 19 20 21 22 23 22 23 24 25 26 27 28
27 28 29 30 31 24 25 26 27 28 29 30 29 30 31'''
</pre>
 
=={{header|Kotlin}}==
{{trans|D}}
<langsyntaxhighlight lang="scala">import java.io.PrintStream
import java.text.DateFormatSymbols
import java.text.MessageFormat
Line 3,706 ⟶ 4,841:
fun main(args: Array<String>) {
System.out.printCalendar(1969, 3, Locale.US)
}</langsyntaxhighlight>
{{out}}
See D output.
=={{header|Liberty BASIC}}==
<syntaxhighlight lang="lb">
rem Adapted from LB examples included with software
[start]
prompt "Enter year(yyyy)?";year
if year<1900 then notice "1900 or later":goto [start]
ax=1:gx=8:ay=3:gy=10
locate 52,1:print year
for mr = 0 to 3
for mc = 0 to 2
mt=mt+1
aDate$ = str$(mt)+"/01/"+str$(year)
px = ax+mc*gx
py = ay+mr*gy
gosub [printout]
next mc
next mr
gosub [snoopy]
end
 
[printout]
locate 4*px-3+int((30-len(monthname$(aDate$)))/2),py
print monthname$(aDate$)
FirstDay=date$(word$(aDate$,1,"/")+"/1/"+word$(aDate$,3,"/"))
LastDay$=date$(date$(word$(date$(FirstDay+32),1,"/")+"/1/"+word$(date$(FirstDay+32),3,"/"))-1)
dow=val(word$("3 4 5 x 6 7 x 1 2",int((FirstDay/7-int(FirstDay/7))*10)+1))
locate px*4-3, py+1
print " Su Mo Tu We Th Fr Sa"
for i=1 to val(mid$(LastDay$,4,2))
y=int((i+dow-2)/7)
x=px+(i+dow-2)-y*7
x=4*x
locate x-4,py+y+2
print using("###",i)
next i
return
 
[snoopy]
locate ax, ay+4*gy
print space$(4*gx);" ,-~~-.___."
print space$(4*gx);" / ()=(() \"
print space$(4*gx);" ( ( 0"
print space$(4*gx);" \._\, ,----'"
print space$(4*gx);" ##XXXxxxxxxx"
print space$(4*gx);" / ---'~;"
print space$(4*gx);" / /~|-"
print space$(4*gx);" _____=( ~~ |______ "
print space$(4*gx);" /_____________________\ "
print space$(4*gx);" /_______________________\"
print space$(4*gx);" /_________________________\"
print space$(4*gx);"/___________________________\"
print space$(4*gx);" |____________________|"
print space$(4*gx);" |____________________|"
print space$(4*gx);" |____________________|"
print space$(4*gx);" | |"
return
 
function monthname$(aDate$)
month=val(aDate$)
monthname$=word$("January February March April May June July August September October November December",month)
end function
</syntaxhighlight>
 
{{out}}
<pre> 1969
 
January February March
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1
5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8
12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15
19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22
26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29
30 31
 
 
April May June
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 3 1 2 3 4 5 6 7
6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14
13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21
20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28
27 28 29 30 25 26 27 28 29 30 31 29 30
 
 
 
July August September
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 1 2 3 4 5 6
6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13
13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20
20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27
27 28 29 30 31 24 25 26 27 28 29 30 28 29 30
31
 
 
October November December
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1 2 3 4 5 6
5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13
12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20
19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27
26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30
 
 
,-~~-.___.
/ ()=(() \
( ( 0
\._\, ,----'
##XXXxxxxxxx
/ ---'~;
/ /~|-
_____=( ~~ |______
/_____________________\
/_______________________\
/_________________________\
/___________________________\
|____________________|
|____________________|
|____________________|
| |
 
</pre>
=={{header|Lingo}}==
<langsyntaxhighlight lang="lingo">----------------------------------------
-- @desc Class "Calendar"
-- @file parent script "Calendar"
Line 3,767 ⟶ 5,025:
on _write (me, str, x, y)
put str into char x to x+str.length-1 of line y of _calStr
end</langsyntaxhighlight>
 
Usage:
<langsyntaxhighlight lang="lingo">calObj = script("Calendar").new()
calStr = calObj.make(1969)
put calStr</langsyntaxhighlight>
 
{{out}}
Line 3,813 ⟶ 5,071:
27 28 29 30 31 24 25 26 27 28 29 30 29 30 31
</pre>
 
=={{header|Lua}}==
<langsyntaxhighlight Lualang="lua">function print_cal(year)
local months={"JANUARY","FEBRUARY","MARCH","APRIL","MAY","JUNE",
"JULY","AUGUST","SEPTEMBER","OCTOBER","NOVEMBER","DECEMBER"}
Line 3,877 ⟶ 5,134:
end
 
print_cal(1969)</langsyntaxhighlight>
{{out}}
<pre>
Line 3,919 ⟶ 5,176:
27 28 29 30 31 24 25 26 27 28 29 30 29 30 31
</pre>
 
=={{header|M2000 Interpreter}}==
Set console to 80 character by 43 lines. Produce calendar line by line, three columns of months.
Line 3,927 ⟶ 5,183:
Module Calendar get the Year and the Language Id (1033 for English, 1032 for Greek and any other which support the Window OS).
 
<syntaxhighlight lang="m2000 interpreter">
<lang M2000 Interpreter>
Module Calendar (Year, LocaleId) {
Function GetMax(Year, Month) {
Line 3,953 ⟶ 5,209:
For i=1 to 3 {
Month=i+j*3
Print Part @((i-1)*29-1), $(2,22), Title$(Ucase$(locale$(55+Month)))
}
Print
Line 3,995 ⟶ 5,251:
k=Key$ ' wait key
Calendar 2018, 1032 ' Greek
</syntaxhighlight>
</lang>
=={{header|Mathematica}}/{{header|Wolfram Language}}==
 
== Overview ==
=={{header|Mathematica}}==
This task seems to conflate 3 different programming challenges
 
1. Transforming a nested, hierarchical structure of data into linear presentation structure (a stream of printable characters)
Calendar is set of routines for handling calendars; It is built into Mathematica.
We're only going to use it for a two functions, namely, '''DayOfWeek''' and '''DaysBetween'''.
 
2. Acquiring/generating the calendar data that will be presented (specifically, support for arbitrary years and for non-Gregorian schemes)
<lang Mathematica>
Needs["Calendar`"];
</lang>
 
3. Constraining the presentation according to some configuration information (e.g. terminal width and ASCII character codes).
Monthly calendar takes a year and a month and returns a simply formatted calendar for that month.
It knows about leap years.
 
Additionally, there seems to be some implicit desire for presentation decoration options (e.g. grid dividers, spacing between elements, addition of a banner)
<lang Mathematica>
My strategy is to separate these various domains into separate families of functions that can be composed to solve the problem of actually generating a specific calendar.
monthlyCalendar[y_, m_] :=
Module[{
days = {Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday},
months = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"},
d1, shortDays, offset, daysInMonth},
 
==1. Grid structure functions==
d1 = DayOfWeek[{y, m, 1}];
The following functions were motivated by the recognition that a calendar is really a set of nested grid structures. The overall calendar is just a few elements arranged in a column, e.g. banner, year/title, and a grid of months. The grid of months is a rectangular arrangement of individual months that are all styled similarly but vary a bit in the data they contain. Each month is a grid of 3 elements in a column: the month name as title, a header row of the names of the weekdays, and a grid of integers representing the specific days/dates. Each day is a cell that could be considered an atomic element or could be considered a 1x1 matrix. The latter allows for cells to have all of the styling options of the higher level grid elements.
 
At each level, a grid is "regular" in the sense that its elements are constrained to columns and rows with nothing "spilling out" of those columns/rows. By nesting the grids in various ways, you can achieve "non-regular" patterns.
daysInMonth[year_, month_] := DaysBetween[{year, month, 1}, {If[month == 12, year + 1, year], If[month == 12, 1, month + 1], 1}];
 
Mathematica has many wrappers for handling the presentation of such structured and nested data, including Grid, TextGrid, Row, Column, and Multicolumn. However, these are just wrappers that a Mathematica Notebook knows how to present in the UI. You could apply Normal or ToString to these wrappers to get a true textual representation, but the results are not easily predictable and are extremely sensitive to the options you have included in the wrappers. Since we are going to want fine level control over spacing, alignment, borders, etc, using these wrappers would be, unfortunately, not very helpful for providing a plain, textual output.
shortDays = (StringTake[ToString[#], 3] & /@ days);
 
Therefore, I've chosen to implement "raw" textual grids from scratch with a function called DataGrid. There are two versions of DataGrid. The first version allows you to specify exactly the height and width of each row and column in terms of number of string characters. The second version allows you to specify just the "macro" grid dimensions, and the actual size of each cell will be determined by calculating the width among cells in the same column and max height among cells in the same row. With those max values, it calls the first GridData function. The cell dimensions do not account for spacing and borders, which are added after the cell is scaled to the correct character dimensions. A variety of decoration options can also be supplied. The effect of these will be demonstrated in the examples below. Each version acts on a list of cells that are already rectangular arrays of data (though their dimensions obviously don't already need to be identical--that's part of the job of DataGrid, and it's why DataGrid can be composed/nested). Also, the list of cells is "flat", and its length does not need to conform to an exact rectangle (again, this is a job of DataGrid).
offset = d1 /. Thread[days -> Range[0, 6]];
 
<syntaxhighlight lang="mathematica">DataGrid[
Grid[
rowHeights:{__Integer},
Prepend[
colWidths:{__Integer},
Prepend[
spacings:{_Integer,_Integer},
Partition[
borderWidths:{{_Integer,_Integer},{_Integer,_Integer}},
PadRight[PadLeft[Range[daysInMonth[y, m]], daysInMonth[y, m] + offset, ""],
options_Association,
36, "" ],
data:{__List?MatrixQ}]:=
7],
With[
shortDays],
(*Need to make sure we have sensible defaults for the decoration options.*)
{months[[m]], SpanFromLeft}]]]
{alignment=Lookup[options,"alignment",{0,0}],
</lang>
background=Lookup[options,"background"," "],
dividers=Lookup[options,"dividers",{" "," "," "}],
border=Lookup[options,"border"," "],
dims={Length[rowHeights],Length[colWidths]}},
(*Pad the data so that it will fit into the specified rectangle (list of lists).*)
With[{augmentedData=PadRight[data,Times@@dims,{{{background}}}]},
(*Create a matrix of dimensions based on desired rectangle. Once we have a matrix of cells we can "thread" these two matrices and use that data to coerce each cell into its final dimensions.*)
With[{cellDims=ArrayReshape[Outer[List,rowHeights,colWidths],{Times@@dims,2}]},
(*MatrixAlign, defined below, rescales and aligns each cell's data.*)
With[{undecoratedGrid=Partition[MapThread[MatrixAlign[alignment,#1,background][#2]&, {cellDims,augmentedData}],dims[[2]]]},
(*Add the spacing to each row.*)
With[{dividedRows=MapThread[Transpose[Riffle[#2,{ConstantArray[dividers[[2]],{#1,spacings[[2]]}]},{2,-2,2}]]&, {rowHeights,undecoratedGrid}]},
(*Add the spacing between rows.*)
With[{dividedColumn=Riffle[dividedRows,{Transpose[Riffle[ConstantArray[dividers[[1]],{spacings[[1]],#}]&/@colWidths,{ConstantArray[dividers[[3]],spacings]},{2,-2,2}]]},{2,-2,2}]},
(*Assemble all cell rows into actual character rows. We now have one large matrix.*)
With[{dividedGrid=Catenate[Map[Flatten,dividedColumn,{2}]]},
(*Add borders.*)
ArrayPad[dividedGrid,borderWidths,border]]]]]]]];
 
DataGrid[dims:{_Integer,_Integer},spacings_,borderWidths_,options_,data:{__List?MatrixQ}]:=
'''yearlyCalendar''' prints out calendars for each of the 12 months in the year.
(*Calculate the max height for each row and max width for each column, and then just call the previous DataGrid function above.*)
With[
{rowHeights=Flatten@BlockMap[Max[Part[#,All,All,1]]&,ArrayReshape[Dimensions/@data,Append[dims,2],1],{1,dims[[2]]}],
colWidths=Flatten@BlockMap[Max[Part[#,All,All,2]]&,ArrayReshape[Dimensions/@data,Append[dims,2],1],{dims[[1]],1}]},
DataGrid[rowHeights,colWidths,spacings,borderWidths,options,data]];
 
(*This could probably be simplified, but I like having all of the aligment options explicit and separate for testability.*)
<lang Mathematica>
MatrixAlign[{-1,-1},dims_,pad_]:=PadRight[#,dims,pad]&;
yearlyCalendar[y_] := Grid[Partition[Table[monthlyCalendar[y, k], {k, 12}], 3], Spacings -> {4, 2}];
MatrixAlign[{-1,0},dims_,pad_]:=PadRight[CenterArray[#,{Dimensions[#][[1]],dims[[2]]},pad],dims,pad]&;
</lang>
MatrixAlign[{-1,1},dims_,pad_]:=PadRight[PadLeft[#,{Dimensions[#][[1]],dims[[2]]},pad],dims,pad]&;
MatrixAlign[{0,-1},dims_,pad_]:=CenterArray[PadRight[#,{Dimensions[#][[1]],dims[[2]]},pad],dims,pad]&;
MatrixAlign[{0,0},dims_,pad_]:=CenterArray[#,dims,pad]&;
MatrixAlign[{0,1},dims_,pad_]:=CenterArray[PadLeft[#,{Dimensions[#][[1]],dims[[2]]},pad],dims,pad]&;
MatrixAlign[{1,-1},dims_,pad_]:=PadLeft[PadRight[#,{Dimensions[#][[1]],dims[[2]]},pad],dims,pad]&;
MatrixAlign[{1,0},dims_,pad_]:=PadLeft[CenterArray[#,{Dimensions[#][[1]],dims[[2]]},pad],dims,pad]&;
MatrixAlign[{1,1},dims_,pad_]:=PadLeft[#,dims,pad]&;
 
(*While the grid functions make no assumptions about the format of the data, we will be using them with string/character data, and we will eventually want to output a calendar as a single large string. AsString gives us a standard method for transforming a matrix of characters into a string with rows delimited by newlines.*)
=={{header|PowerShell}}==
AsString[matrix_List?MatrixQ]:=StringRiffle[matrix,"\n",""];</syntaxhighlight>
<lang PowerShell>
Param([int]$Year = 1969)
Begin {
$COL_WIDTH = 21
$COLS = 3
$MONTH_COUNT = 12
$MONTH_LINES = 9
 
To illustrate how DataGrid works, I'll create some sample data-grids and assemble them together into a larger data-grid, and then I'll use DataGrid itself to present all of these results. Notice the options for alignment, borders, spacings, etc.
Function CenterStr([string]$s, [int]$lineSize) {
$padSize = [int](($lineSize - $s.Length) / 2)
($(if ($padSize -gt 0) { ' ' * $padSize } else { '' }) + $s).PadRight($lineSize,' ')
}
 
<syntaxhighlight lang="mathematica">DataA={{"A"}};
Function MonthLines([int]$month) {
GridA = DataGrid[{2},{5},{0,0},{{1,1},{1,1}},<|"border"->"*","alignment"->{1,-1}|>,{DataA}];
$dt = [System.DateTime]::new($Year, $month, 1)
DataB = {{"B"},{"B"}};
$line = CenterStr $dt.ToString("MMMM") $COL_WIDTH
GridB =
$line += 'Su Mo Tu We Th Fr Sa'
DataGrid[{4,3},{4,8},{2,3},{{0,0},{0,0}},<|"background"->".","alignment"->{0,1},"dividers"->{"-","|","+"}|>,{DataB,DataB,DataB}];
$line += $(' ' * $dt.DayOfWeek.value__)
GridC =
$line += (-join ($(1..$($dt.AddMonths(1).AddDays(-1).Day)) | %{ $("" + $_).PadLeft(3) }))
DataGrid[{2,3},{2,3},{{0,1},{2,3}},<|"border"->"@","alignment"->{0,0},"dividers"->{"/","/","/"}|>,{GridA,GridB,GridA,GridB,GridA}];
$line = $line.PadRight($MONTH_LINES * $COL_WIDTH)
New-Object –TypeName PSObject –Prop(@{
'Lines'=(0..($MONTH_LINES - 1)) | %{ $_ * $COL_WIDTH } | %{ -join $line[$_..($_ + $COL_WIDTH - 1)] }
'Dt'=$dt})
}
}
Process {
Write-Output (CenterStr $Year ($COL_WIDTH * $COLS + 4))
$(0..($MONTH_COUNT / $COLS - 1)) | %{
$fm = $_ * $COLS
$monthNums = $fm..($fm + $COLS - 1) | %{ $_ + 1 }
$months = $monthNums | %{ MonthLines $_ }
$(0..($MONTH_LINES - 1)) | %{
$ml = $_
Write-Output $(-join ($(0..($COLS - 1)) | %{ $(if ($_ -eq 0) { '' } else {' '}) + $months[$_].Lines[$ml] }))
}
}
}
</lang>
 
DataGrid[{2,3},{2,12},{{0,0},{0,0}},<||>,{{{"A"}},{{"B"}},{{"C"}},GridA,GridB,GridC}]//AsString</syntaxhighlight>
=={{header|Perl}}==
 
{{out}}
<lang perl>#!/usr/bin/perl
<pre> A B C
use strict;
use warnings;
use Time::Local;
@@ ///....|||......../// @@@
@@ ///...B|||.......B/// @@@
@@ ******* ///...B|||.......B///*******@@@
@@ * * ///....|||........///* *@@@
@@ *A * ///----+++--------///*A *@@@
@@ ******* ///----+++--------///*******@@@
....|||........ @@ ///...B|||......../// @@@
...B|||.......B @@ ///...B|||......../// @@@
******* ...B|||.......B @@ ///....|||......../// @@@
* * ....|||........ @@///////////////////////////////////////////@@@
*A * ----+++-------- @@///////////////////////////////////////////@@@
******* ----+++-------- @@....|||......../// /// @@@
...B|||........ @@...B|||.......B/// /// @@@
...B|||........ @@...B|||.......B/// ******* /// @@@
....|||........ @@....|||......../// * * /// @@@
@@----+++--------/// *A * /// @@@
@@----+++--------/// ******* /// @@@
@@...B|||......../// /// @@@
@@...B|||......../// /// @@@
@@....|||......../// /// @@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@</pre>
 
HeaderGrid is a helper that defers the "gridding" of the individual header cells and data cells to functions that get passed in. There are some assumptions about presentation that feed into this design, but if your requirements differ, it's fairly easy to follow this same basic pattern of accepting functions that do the lower level work--you would just need to organize that work differently.
my @names = qw/ JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC/;
 
<syntaxhighlight lang="mathematica">HeadedGrid[
my $year = shift ||'2007';
finalSpacings:{_Integer,_Integer},
finalBorderWidths:{{_Integer,_Integer},{_Integer,_Integer}},
finalOptions_Association,
headerCellGridder_Function,
rawHeaders:{__String},
dataCellGridder_Function,
rawData:{__String}]:=
With[
{finalDims={Ceiling[(Length@rawData+Length@rawHeaders)/Length@rawHeaders],Length@rawHeaders},
headerCells=headerCellGridder/@List/@List/@Characters[rawHeaders],
dataCells=dataCellGridder/@List/@List/@Characters[rawData]},
DataGrid[finalDims,finalSpacings,finalBorderWidths,finalOptions,Join[headerCells,dataCells]]];
 
(*An example with a few decorations:*)
for my $month (0..11) {
HeadedGrid[
print " $names[$month] $year\n";
{1,1},
print calendar($year, $month), "\n\n";
{{1,1},{1,1}},
}
<|"dividers"->{"-","|","+"},"border"->"*"|>,
DataGrid[{3},{6},{0,0},{{0,0},{0,0}},<|"background"->"-"|>,#]&,
{"Su","Mo","Tu","We","Th","Fr","Sa"},
DataGrid[{3},{4},{0,0},{{0,0},{0,0}},<|"alignment"->{-1,1}|>,#]&,
ToString/@Range[31]]//AsString</syntaxhighlight>
 
{{out}}
sub calendar {
<pre>**************************************************
my ($year, $month) = @_;
*------|------|------|------|------|------|------*
my @mon_days = qw/31 28 31 30 31 30 31 31 30 31 30 31/;
*--Su--|--Mo--|--Tu--|--We--|--Th--|--Fr--|--Sa--*
++$mon_days[1] if $year % 4 == 0 && ($year % 400 == 0 || $year % 1
*------|------|------|------|------|------|------*
+00 != 0);
*------+------+------+------+------+------+------*
* 1 | 2 | 3 | 4 | 5 | 6 | 7 *
my $cal = " Sun Mon Tue Wed Thu Fri Sat\n";
* | | | | | | *
* | | | | | | *
*------+------+------+------+------+------+------*
* 8 | 9 | 10 | 11 | 12 | 13 | 14 *
* | | | | | | *
* | | | | | | *
*------+------+------+------+------+------+------*
* 15 | 16 | 17 | 18 | 19 | 20 | 21 *
* | | | | | | *
* | | | | | | *
*------+------+------+------+------+------+------*
* 22 | 23 | 24 | 25 | 26 | 27 | 28 *
* | | | | | | *
* | | | | | | *
*------+------+------+------+------+------+------*
* 29 | 30 | 31 | | | | *
* | | | | | | *
* | | | | | | *
**************************************************</pre>
 
MonthGrid will use HeadedGrid for the main part of the month, and it will take another gridding function to handle the title (month name). I could have simplified the method signature by having the caller pass in a HeadedGrid function directly, but I liked exposing more control with this function. MonthGrid offers the convenience of specifying a leading offset for the month (month and week boundaries don't typically align, so this allows for starting on the correct day of the week without requiring the caller to munge the data).
# Months are indexed beginning at 0
my $time = timegm(0,0,0,1,$month,$year);
my $wday = (gmtime $time)[6];
$cal .= " " x $wday;
my $mday = 1;
 
<syntaxhighlight lang="mathematica">MonthGrid[
while ($mday <= $mon_days[$month]) {
finalSpacings:{_Integer,_Integer},
$cal .= sprintf "%4s", $mday++;
finalBorderWidths:{{_Integer,_Integer},{_Integer,_Integer}},
$cal .= "\n" if ($wday + $mday -1) % 7 == 0;
finalOptions_Association,
}
titleGridder_Function,
return $cal;
monthName_String,
}
monthSpacings:{_Integer,_Integer},
# Let's use this as a placeholder until a better solution arrives, OK?</lang>
monthBorderWidths:{{_Integer,_Integer},{_Integer,_Integer}},
monthOptions_Association,
headerCellGridder_Function,
weekdayNames:{__String},
dayCellGridder_Function,
dayOffset_Integer,
days:{__String}]:=
DataGrid[{2,1},finalSpacings,finalBorderWidths,finalOptions,
{titleGridder[List/@List/@Characters[monthName]],
HeadedGrid[monthSpacings,monthBorderWidths,monthOptions,headerCellGridder,weekdayNames,dayCellGridder,ArrayPad[days,{dayOffset,0},""]]}];
 
(*A compact example:*)
=={{header|Perl 6}}==
MonthGrid[{0, 0}, {{0, 0}, {0, 0}}, <||>,
{{works with|Rakudo|2015.12}}
DataGrid[{1, Length@#}, {0, 1}, {{1, 1}, {0, 0}}, <||>,ToUpperCase@#] &,
<lang perl6>my $months-per-col = 3;
"September", {0, 1}, {{0, 0}, {0, 0}}, <||>,
my @week-day-names = <Mo Tu We Th Fr Sa Su>;
DataGrid[{1}, {2}, {0, 0}, {{0, 0}, {0, 0}}, <||>, #] &,
my @month-names = <Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec>;
{"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"},
DataGrid[{1}, {2}, {0, 0}, {{0, 0}, {0, 0}}, <|"alignment" -> {-1, 1}|>, #] &,
2, ToString /@ Range[31]]//AsString</syntaxhighlight>
 
{{out}}
my Int $year = +(@*ARGS.shift || 1969);
<pre>
S E P T E M B E R
Su Mo Tu We Th Fr Sa
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 </pre>
 
At this point we have everything we need to generate a calendar. Since ASCII art is just a matrix of characters, we could trivially handle the display of the Snoopy banner. To make things more interesting, let's instead just display a magnified version of the calendar year as a banner.
say fmt-year($year);
exit;
 
FractalChars takes a string and rasterizes each character and then replaces each black pixel with the original character. The output is a matrix of characters suitable as a datum in the argument to DataGrid.
sub fmt-year ($year) {
 
<syntaxhighlight lang="mathematica">FractalChars[rasterSize_,font_,char_String/;1==StringLength[char]]:=
my $str = (' ' x 30) ~ $year ~ "\n";
ReplaceAll[ImageData[ImageCrop[Binarize[Rasterize[Style[char,FontFamily->font],RasterSize->rasterSize]]]],{1->" ",0->char}];
FractalChars[rasterSize_,font_,word_String]:=FractalChars[rasterSize,font,#]&/@Characters[word];
 
(*And here's the convenience function that ultimately calls DataGrid.*)
my Array @month-strs;
BannerGrid[finalSpacings_,finalBorderWidths_,finalOptions_,charGridder_Function,rasterSize_,text_String]:=
@month-strs[$_] = fmt-month($year, $_).lines.Array for 1 .. 12;
With[
{charData=FractalChars[rasterSize,"Courier",text]},
DataGrid[{1,StringLength@text},finalSpacings,finalBorderWidths,finalOptions,charGridder/@List/@charData]];
 
(*An example banner.*)
loop ( my $month = 1; $month <= 12; $month += $months-per-col ) {
BannerGrid[{0,5},{{1,1},{0,0}},<|"border"->"X"|>,DataGrid[{1,1},{0,0},{{1,1},{0,0}},<||>,#]&,20,"1969"]//AsString</syntaxhighlight>
while @month-strs[$month] {
for ^$months-per-col {
next unless @month-strs[$month+$_];
$str ~= @month-strs[$month+$_].shift;
$str ~= " " x 3;
}
$str ~= "\n";
}
$str ~= "\n";
}
return $str;
}
sub fmt-month ($year, $month) {
my $str = sprintf "%-20s\n", @month-names[$month-1];
$str ~= @week-day-names~"\n";
my $date = DateTime.new(year => $year, month => $month);
my $week-day = $date.day-of-week;
 
{{out}}
$str ~= (" " xx $week-day-1).join(" ");
<pre>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11 9999 666666 9999
1111111 99999999 66666666 99999999
11111111 9999999999 66666666 9999999999
11111111 9999 9999 6666 9999 9999
111 9999 999 6666 9999 999
111 999 999 666 999 999
111 999 999 6666 999 999
111 999 999 666 999 999
111 999 9999 666 66666 999 9999
111 9999 9999 66666666666 9999 9999
111 9999 99999 666666666666 9999 99999
111 99999999999 66666 6666 99999999999
111 9999999999 6666 666 9999999999
111 99 999 6666 666 99 999
111 9999 6666 666 9999
111 999 6666 666 999
111 9999 666 666 9999
111 9999 6666 6666 9999
11111111111 99999 6666 6666 99999
111111111111 99999999 6666666666 99999999
111111111111 99999999 6666666 99999999
99 6 99
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</pre>
 
==2. Calendar data functions==
for $date.day .. $date.days-in-month -> $day {
Fortunately, Mathematica has many powerful calendar-related functions. Unfortunately, the semantics of calendars is sufficiently complicated that there is no practical way to create just a few standard data generators that will cover all of the implied cases. For example, the seemingly simple concept of "first day of the year" is ambiguous. The Jewish year uses one start day for religious holidays and another day for civil/secular purposes. The task definition referenced the switch-over from the Julian calendar to the Gregorian calendar, but this did not happen simultaneously around the globe, and many regions adopted the Gregorian calendar surprisingly recently. Assigning a number to a year is not standardized across calendars (e.g. consider the Chinese and Jewish calendars). The Cotsworth Calendar (effectively the International Fixed Calendar) has days that aren't assigned to any month or week--they're just dangling special days. So, we can provide some simple, general helper functions, but we assume that the calendar maker will be responsible for dealing with special cases.
 
<syntaxhighlight lang="mathematica">(*Mathematica makes it easy to get month names and day names for several standard calendars.*)
$date = DateTime.new(year => $year, month => $month, day => $day);
MonthNames[]:=MonthNames["Gregorian"];
MonthNames[calType_]:=Lookup[CalendarData[calType,"PropertyAssociation"],"MonthNames"];
 
WeekdayNames[]:=WeekdayNames["Gregorian"];
$str ~= " " if 1 < $week-day < 8;
WeekdayNames[calType_]:=Lookup[CalendarData[calType,"PropertyAssociation"],"DayNames"];
if $week-day == 8 {
$str ~= "\n";
$week-day = 1;
}
$str ~= sprintf "%2d", $day;
 
(*Since month boundaries don't align with week boundaries on most calendars, we need to pad month data with empty cells. I was tempted to create a function that would generate offsets for a given year on a given calendar, but even that required too many decisions on the part of the calendar maker to be feasible. So, I removed all of the calendar semantics. If you provide the fixed small group length (week length), the initial offset, and the list of the large group lengths (month lengths), this function will give you the offsets you need for each large group (month).*)
$week-day++;
Offsets[groupLength_,firstOffset_,lengths_List]:=FoldPairList[{#1,Mod[#1+#2,groupLength]}&,firstOffset,lengths];</syntaxhighlight>
}
$str ~= " " if $week-day < 8;
$str ~= (" " xx 8-$week-day).join(" ");
$str ~= "\n";
return $str;
}
</lang>
 
For the year 1969 on the Gregorian calendar, Mathematica can give us all of the data we need.
 
<syntaxhighlight lang="mathematica">Data1969=GroupBy[Most[DateRange[DateObject[{1969,1,1}],DateObject[{1+1969,1,1}]]],DateValue[#,"MonthName"]&];
InitialOffset1969=QuantityMagnitude[DateDifference[PreviousDate[DateObject[{1969,1,1}],Sunday],DateObject[{1969,1,1}]]];
MonthLengths1969=Length/@Values[Data1969];
Offsets1969=Offsets[7,InitialOffset1969,MonthLengths1969];
MonthNames1969=Keys@Data1969;
 
YearBanner1969=BannerGrid[{0,0},{{1,1},{0,0}},<|"border"->"X"|>,DataGrid[{1,1},{1,1},{{1,1},{5,5}},<||>,#]&,13,"1969"];
 
MonthGrids1969=
With[
{monthNameGridder=DataGrid[{1,Length@#},{0,1},{{1,1},{0,0}},<||>,ToUpperCase@#]&,
dayNameGridder=DataGrid[{1},{2},{0,0},{{0,0},{0,0}},<|"alignment"->{0,-1}|>,#]&,
dayGridder=DataGrid[{1},{2},{0,0},{{0,0},{0,0}},<|"alignment"->{-1,1}|>,#]&},
With[
{monthGridder=
MonthGrid[{0,0},{{0,0},{0,0}},<||>,monthNameGridder,#1,
{0,1},{{0,0},{0,0}},<||>,dayNameGridder,WeekdayNames[],
dayGridder,#2,#3]&},
MapThread[monthGridder,{MonthNames1969,Offsets1969,Map[ToString,Range/@MonthLengths1969,{2}]}]]];
 
MonthsGrid1969=DataGrid[{3,4},{1,4},{{0,0},{0,0}},<||>,MonthGrids1969];
 
DataGrid[{2,1},{2,0},{{0,0},{0,0}},<||>,{YearBanner1969,MonthsGrid1969}]//AsString</syntaxhighlight>
 
{{out}}
<pre> XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1 99 66 99
11111 999999 66666 999999
11111 999 999 666 999 999
11 99 99 666 99 99
11 99 99 66 99 99
11 99 999 66 99 999
11 999 999 6666666 999 999
11 99999999 66666666 99999999
11 999999 666 66 999999
11 99 66 666 99
11 99 66 666 99
11 99 66 66 99
1111111 999 6666666 999
11111111 99999 66666 99999
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
J A N U A R Y F E B R U A R Y M A R C H A P R I L
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1 1 2 3 4 5
5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8 6 7 8 9 10 11 12
12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15 13 14 15 16 17 18 19
19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22 20 21 22 23 24 25 26
26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29 27 28 29 30
30 31
M A Y J U N E J U L Y A U G U S T
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 1 2 3 4 5 6 7 1 2 3 4 5 1 2
4 5 6 7 8 9 10 8 9 10 11 12 13 14 6 7 8 9 10 11 12 3 4 5 6 7 8 9
11 12 13 14 15 16 17 15 16 17 18 19 20 21 13 14 15 16 17 18 19 10 11 12 13 14 15 16
18 19 20 21 22 23 24 22 23 24 25 26 27 28 20 21 22 23 24 25 26 17 18 19 20 21 22 23
25 26 27 28 29 30 31 29 30 27 28 29 30 31 24 25 26 27 28 29 30
31
S E P T E M B E R O C T O B E R N O V E M B E R D E C E M B E R
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 6 1 2 3 4 1 1 2 3 4 5 6
7 8 9 10 11 12 13 5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13
14 15 16 17 18 19 20 12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20
21 22 23 24 25 26 27 19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27
28 29 30 26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30 </pre>
 
It's a bit more involved to create the data for a calendar that displays the switch from Julian to Gregorian. A few major European Catholic countries made the switch in 1582, so I'll generate data for that scenario. The switch happened in October, with Thursday Oct 4 being followed by Friday Oct 15. Mathematica provides tools to both fetch the calendar data and then fiddle with the structures so that I can highlight the relevant month and dates.
 
<syntaxhighlight lang="mathematica">Dates1582France=
Join[
DateRange[DateObject[{1582,1,1},CalendarType->"Julian"],DateObject[{1582,10,4},CalendarType->"Julian"],CalendarType->"Julian"],
DateRange[DateObject[{1582,10,15}],DateObject[{1582,12,31}]]];
Data1582France=GroupBy[Dates1582France,DateValue[#,"MonthName"]&];
InitialOffset1582France=
QuantityMagnitude[DateDifference[
PreviousDate[CalendarConvert[DateObject[{1582,1,1},CalendarType->"Julian"],"Gregorian"],Sunday],
CalendarConvert[DateObject[{1582,1,1},CalendarType->"Julian"],"Gregorian"]]];
MonthLengths1582France=Length/@Values[Data1582France];
DatesByMonth1582France=Map[DateString[#,"DayShort"]&,Values[Data1582France],{2}];
Offsets1582France=Offsets[7,InitialOffset1582France,MonthLengths1582France];
MonthNames1582France=Keys@Data1582France;
 
With[
{yearBanner=BannerGrid[{0,0},{{1,1},{0,0}},<|"border"->"X"|>,DataGrid[{1,1},{1,1},{{1,1},{5,5}},<||>,#]&,13,"1582"],
monthNameGridder=DataGrid[{1,Length@#},{0,1},{{1,1},{0,0}},<||>,ToUpperCase@#]&,
dayNameGridder=DataGrid[{1},{2},{0,0},{{0,0},{0,0}},<|"alignment"->{0,-1}|>,#]&,
dayGridder=DataGrid[{1},{2},{0,0},{{0,0},{0,0}},<|"alignment"->{-1,1}|>,#]&},
With[
{monthGridder=MonthGrid[{0,0},{{0,0},{0,0}},<||>,monthNameGridder,#1,{0,1},{{0,0},{0,0}},<||>,dayNameGridder,WeekdayNames[],dayGridder,#2,#3]&},
With[
{monthCells=MapThread[monthGridder,{MonthNames1582France,Offsets1582France,Map[ToString,Range/@MonthLengths1582France,{2}]}],
octoberCells=DataGrid[{1},{2},{0,0},Switch[#,"4"|"15",{{1,1},{1,1}},_,{{0,0},{0,0}}],<|"alignment"->{-1,1},"border"->"|","background"->Switch[#,"4"|"15","|",_," "]|>,{{Characters[#]}}]&/@ArrayPad[DatesByMonth1582France[[10]],{Offsets1582France[[10]],0},""]},
With[
{octoberGrid=
DataGrid[{2,1},{0,0},{{1,1},{1,1}},<|"border"->"*"|>,
{monthNameGridder[{{Characters[MonthNames1582France[[10]]]}}],
DataGrid[{1+Ceiling[Length@octoberCells/7],7},{0,1},{{0,0},{0,0}},<|"alignment"->{0,0}|>,octoberCells]}]},
DataGrid[{2,1},{2,0},{{0,0},{0,0}},<||>,{yearBanner,DataGrid[{3,4},{2,4},{{0,0},{0,0}},<|"alignment"->{-1,0}|>,ReplacePart[monthCells,10->octoberGrid]]}]]]]]//AsString</syntaxhighlight>
 
{{out}}
<pre> XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1 55555555 888 22
11111 5555555 888888 222222
11111 55 888 888 222 222
11 55 88 888 22 22
11 555555 88 888 22
11 55555555 888 88 22
11 5 555 8888888 222
11 555 888888 222
11 55 8888 888 222
11 555 88 888 222
11 55 88 888 222
11 55555555 888 888 222 2
1111111 5555555 8888888 22222222
11111111 888888 22222222
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
J A N U A R Y F E B R U A R Y M A R C H A P R I L
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 6 1 2 3 1 2 3 1 2 3 4 5 6 7
7 8 9 10 11 12 13 4 5 6 7 8 9 10 4 5 6 7 8 9 10 8 9 10 11 12 13 14
14 15 16 17 18 19 20 11 12 13 14 15 16 17 11 12 13 14 15 16 17 15 16 17 18 19 20 21
21 22 23 24 25 26 27 18 19 20 21 22 23 24 18 19 20 21 22 23 24 22 23 24 25 26 27 28
28 29 30 31 25 26 27 28 25 26 27 28 29 30 31 29 30
M A Y J U N E J U L Y A U G U S T
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 1 2 3 4 5 6 7 1 2 3 4
6 7 8 9 10 11 12 3 4 5 6 7 8 9 8 9 10 11 12 13 14 5 6 7 8 9 10 11
13 14 15 16 17 18 19 10 11 12 13 14 15 16 15 16 17 18 19 20 21 12 13 14 15 16 17 18
20 21 22 23 24 25 26 17 18 19 20 21 22 23 22 23 24 25 26 27 28 19 20 21 22 23 24 25
27 28 29 30 31 24 25 26 27 28 29 30 29 30 31 26 27 28 29 30 31
**************************
S E P T E M B E R * * N O V E M B E R D E C E M B E R
* OCTOBER *
Su Mo Tu We Th Fr Sa * * Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 * |||| |||| * 1 2 3 4 5 6 1 2 3 4
2 3 4 5 6 7 8 * 1 2 3 ||4| |15| 16* 7 8 9 10 11 12 13 5 6 7 8 9 10 11
9 10 11 12 13 14 15 * |||| |||| * 14 15 16 17 18 19 20 12 13 14 15 16 17 18
16 17 18 19 20 21 22 *17 18 19 20 21 22 23* 21 22 23 24 25 26 27 19 20 21 22 23 24 25
23 24 25 26 27 28 29 *24 25 26 27 28 29 30* 28 29 30 26 27 28 29 30 31
30 *31 *
* *
************************** </pre>
 
==3. Output configuration==
The only remaining task is to automate the fitting of calendar data to a specified width. We could approach this in the most general way, which would allow us to fit an arbitrary data set into any pre-specified rectangle. This approach would need to actually iterate over the possible dimensions for the large scale grid, creating the grid each time and computing its dimensions. It would stop when it found dimensions that fit (for some definition of "fit"). Alternatively, if we pick a specific set of formatting options such that each month has a standard size, it's a simple matter of arithmetic to determine a grid that fits. I'm going to implement something closer to the more general approach, but only concerned with widths, and only doing the grid generation in an abstract way.
 
WidestFitDimensions will output data about the best fit it found, including the dimensions (which could be used in DataGrid) and the width of the best fit grid. There is no guarantee that a strict fit can be found, so it also provides the actual width of the best fit, and the user can determine what to do with the results. One could create another helper gridding function that uses WidestFitDimensions to automatically generate the grid, but I've already demonstrated such helper functions, so I'll just focus on computing the grid dimensions here.
 
<syntaxhighlight lang="mathematica">WidestFitDimensions[
targetWidth_Integer,
columnSpacings_Integer,
leftRightBorderWidths:{_Integer,_Integer},
data:{__List?MatrixQ}]:=
With[
{widths=Last/@Dimensions/@data,
fullWidthOfRow=Total[ArrayPad[Riffle[#,columnSpacings],leftRightBorderWidths,1]]&},
With[
{fullWidthOfGrid=Max[fullWidthOfRow/@#]&},
With[
{isTooLarge=(targetWidth<fullWidthOfGrid[#])&},
With[
{bestFitGrid=
NestWhile[Partition[widths,-1+Last@Dimensions@#,-1+Last@Dimensions@#,{1,1},0]&,
{widths},isTooLarge[#]&,1,-1+Length@widths]},
<|"dimensions"->Dimensions@bestFitGrid,"width"->fullWidthOfGrid@bestFitGrid|>]]]];
</syntaxhighlight>
 
Checking best fit for our 1969 calendar for a few widths.
<syntaxhighlight lang="mathematica">(*Choose a best fit for our 1969 calendar data on 80 character wide display.*)
WidestFitDimensions[80,4,{0,0},MonthGrids1969]</syntaxhighlight>
{{out}}
<pre><|dimensions->{4,3},width->68|></pre>
<syntaxhighlight lang="mathematica">(*Choose a best fit for our 1969 calendar data on 132 character wide display.*)
WidestFitDimensions[132,4,{0,0},MonthGrids1969]</syntaxhighlight>
{{out}}
<pre><|dimensions->{3,5},width->116|></pre>
<syntaxhighlight lang="mathematica">(*Can we fit into a 20-character wide display?*)
WidestFitDimensions[20,4,{0,0},MonthGrids1969]</syntaxhighlight>
{{out}}
<pre><|dimensions->{12,1},width->20|></pre>
=={{header|Nim}}==
{{trans|D}}
<syntaxhighlight lang="nim">import times
import strformat
 
proc printCalendar(year, nCols: int) =
var rows = 12 div nCols
var date = initDateTime(1, mJan, year, 0, 0, 0, utc())
if rows mod nCols != 0:
inc rows
var offs = getDayOfWeek(date.monthday, date.month, date.year).int
var mons: array[12, array[8, string]]
for m in 0..11:
mons[m][0] = &"{$date.month:^21}"
mons[m][1] = " Su Mo Tu We Th Fr Sa"
var dim = getDaysInMonth(date.month, date.year)
for d in 1..42:
var day = d > offs and d <= offs + dim
var str = if day: &" {d-offs:2}" else: " "
mons[m][2 + (d - 1) div 7] &= str
offs = (offs + dim) mod 7
date = date + months(1)
var snoopyString, yearString: string
formatValue(snoopyString, "[Snoopy Picture]", "^" & $(nCols * 24 + 4))
formatValue(yearString, $year, "^" & $(nCols * 24 + 4))
echo snoopyString, "\n" , yearString, "\n"
for r in 0..<rows:
var s: array[8, string]
for c in 0..<nCols:
if r * nCols + c > 11:
break
for i, line in mons[r * nCols + c]:
s[i] &= &" {line}"
for line in s:
if line == "":
break
echo line
echo ""
 
printCalendar(1969, 3)</syntaxhighlight>
{{out}}
<pre>
[Snoopy Picture]
1969
 
January February March
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 1 2
6 7 8 9 10 11 12 3 4 5 6 7 8 9 3 4 5 6 7 8 9
13 14 15 16 17 18 19 10 11 12 13 14 15 16 10 11 12 13 14 15 16
20 21 22 23 24 25 26 17 18 19 20 21 22 23 17 18 19 20 21 22 23
27 28 29 30 31 24 25 26 27 28 24 25 26 27 28 29 30
31
 
April May June
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 6 1 2 3 4 1
7 8 9 10 11 12 13 5 6 7 8 9 10 11 2 3 4 5 6 7 8
14 15 16 17 18 19 20 12 13 14 15 16 17 18 9 10 11 12 13 14 15
21 22 23 24 25 26 27 19 20 21 22 23 24 25 16 17 18 19 20 21 22
28 29 30 26 27 28 29 30 31 23 24 25 26 27 28 29
30
 
July August September
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 6 1 2 3 1 2 3 4 5 6 7
7 8 9 10 11 12 13 4 5 6 7 8 9 10 8 9 10 11 12 13 14
14 15 16 17 18 19 20 11 12 13 14 15 16 17 15 16 17 18 19 20 21
21 22 23 24 25 26 27 18 19 20 21 22 23 24 22 23 24 25 26 27 28
28 29 30 31 25 26 27 28 29 30 31 29 30
 
October November December
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 1 2 3 4 5 6 7
6 7 8 9 10 11 12 3 4 5 6 7 8 9 8 9 10 11 12 13 14
13 14 15 16 17 18 19 10 11 12 13 14 15 16 15 16 17 18 19 20 21
20 21 22 23 24 25 26 17 18 19 20 21 22 23 22 23 24 25 26 27 28
27 28 29 30 31 24 25 26 27 28 29 30 29 30 31
 
 
</pre>
=={{header|OCaml}}==
 
<syntaxhighlight lang="ocaml">#load "unix.cma"
 
let lang = "en" (* language: English *)
 
let usage () =
Printf.printf "Usage:\n%s\n" Sys.argv.(0)
 
let month_pattern =
[
[ 0; 4; 8 ];
[ 1; 5; 9 ];
[ 2; 6; 10 ];
[ 3; 7; 11 ];
 
(*
[ 0; 1; 2; 3; 4; 5 ];
[ 6; 7; 8; 9; 10; 11 ];
 
[ 0; 1; 2; 3 ];
[ 4; 5; 6; 7 ];
[ 8; 9; 10; 11 ];
*)
]
 
let month_langs = [
"en", [|
"January"; "February"; "March"; "April";
"May"; "June"; "July"; "August"; "September";
"October"; "November"; "December";
|];
"fr", [|
"janvier"; "février"; "mars"; "avril"; "mai";
"juin"; "juillet"; "août"; "septembre";
"octobre"; "novembre"; "décembre";
|];
]
 
let days_lang = [
"en", [| "Monday"; "Tuesday"; "Wednesday";
"Thursday"; "Friday"; "Saturday"; "Sunday" |];
"fr", [| "lundi"; "mardi"; "mercredi";
"jeudi"; "vendredi"; "samedi"; "dimanche" |];
]
 
let titles_lang = [
"en", "( Snoopy's best pic )";
"fr", "( Le meilleur profil de Snoopy )";
]
 
let days = List.assoc lang days_lang
let month = List.assoc lang month_langs
let title = List.assoc lang titles_lang
 
let monday_first = 6, [| 0; 1; 2; 3; 4; 5; 6 |]
let sunday_first = 0, [| 6; 0; 1; 2; 3; 4; 5 |]
 
let off, days_order = sunday_first
let off, days_order = monday_first
 
 
let shorten n s =
let len = String.length s in
if n >= len then s else
let n = if s.[n-1] = '\xC3' then n+1 else n in
if n >= len then s else
(String.sub s 0 n)
 
 
let pad size c s =
let len = String.length s in
let n1 = (size - len) / 2 in
let n2 = size - len - n1 in
String.make n1 c ^ s ^
String.make n2 c
 
 
let days = Array.map (shorten 2) days
 
 
let indices ofs =
(ofs / 7, ofs mod 7)
 
 
let t_same t1 t2 =
( t1.Unix.tm_year = t2.Unix.tm_year &&
t1.Unix.tm_mon = t2.Unix.tm_mon &&
t1.Unix.tm_mday = t2.Unix.tm_mday )
 
 
let current_year () =
let t = Unix.localtime (Unix.time ()) in
(t.Unix.tm_year + 1900)
 
 
let make_month t year month =
let empty_day = 0 in
let m = Array.make_matrix 6 7 empty_day in
let ofs = ref 0 in
for day = 1 to 31 do
let tm =
{ t with
Unix.tm_year = year - 1900;
Unix.tm_mon = month;
Unix.tm_mday = day;
}
in
let _, this = Unix.mktime tm in
if !ofs = 0 then ofs := (this.Unix.tm_wday + off) mod 7;
if t_same this tm then
let i, j = indices !ofs in
m.(i).(j) <- day;
incr ofs;
done;
(m)
 
 
let cal ~year =
let empty = [| [| |] |] in
let months = Array.make 12 empty in
let t = Unix.gmtime 0.0 in
for mon = 0 to 11 do
months.(mon) <- make_month t year mon;
done;
(months)
 
 
let print_month_label mp =
List.iter (fun i ->
let mon = pad 20 ' ' month.(i) in
Printf.printf " %s " mon
) mp;
print_newline ()
 
 
let print_day_label mp =
List.iter (fun _ ->
Array.iter (fun i ->
Printf.printf " %s" days.(i)
) days_order
; print_string " "
) mp;
print_newline ()
 
 
let print_mon m mp =
print_month_label mp;
print_day_label mp;
for w = 0 to pred 6 do
print_string begin
String.concat " " begin
List.map (fun i ->
let b = Buffer.create 132 in
for d = 0 to pred 7 do
match m.(i).(w).(d) with
| 0 -> Buffer.add_string b " "
| d -> Printf.kprintf (Buffer.add_string b) " %2d" d
done;
(Buffer.contents b)
) mp
end
end
; print_string "\n"
done
 
 
let print_cal ~y:m =
List.iter (fun mon_row ->
print_mon m mon_row
) month_pattern
 
 
let print_header lbl =
let n = List.length (List.hd month_pattern) in
let year_lbl = pad (23*n-7) ' ' lbl in
Printf.printf " %s\n" year_lbl
 
 
let print_calendar ~year =
print_header title;
print_header (string_of_int year);
print_cal (cal ~year)
 
 
let () =
let args = List.tl (Array.to_list Sys.argv) in
match args with
| [] ->
let year = current_year () in
print_calendar ~year
| ["--year"; _year] ->
let year = int_of_string _year in
print_calendar ~year
| _ ->
usage ()</syntaxhighlight>
 
{{out}}
<pre>
$ ocaml calendar.ml --year 1969
 
( Snoopy's best pic )
1969
January May September
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 5 1 2 3 4 1 2 3 4 5 6 7
6 7 8 9 10 11 12 5 6 7 8 9 10 11 8 9 10 11 12 13 14
13 14 15 16 17 18 19 12 13 14 15 16 17 18 15 16 17 18 19 20 21
20 21 22 23 24 25 26 19 20 21 22 23 24 25 22 23 24 25 26 27 28
27 28 29 30 31 26 27 28 29 30 31 29 30
February June October
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 1 1 2 3 4 5
3 4 5 6 7 8 9 2 3 4 5 6 7 8 6 7 8 9 10 11 12
10 11 12 13 14 15 16 9 10 11 12 13 14 15 13 14 15 16 17 18 19
17 18 19 20 21 22 23 16 17 18 19 20 21 22 20 21 22 23 24 25 26
24 25 26 27 28 23 24 25 26 27 28 29 27 28 29 30 31
30
March July November
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 1 2 3 4 5 6 1 2
3 4 5 6 7 8 9 7 8 9 10 11 12 13 3 4 5 6 7 8 9
10 11 12 13 14 15 16 14 15 16 17 18 19 20 10 11 12 13 14 15 16
17 18 19 20 21 22 23 21 22 23 24 25 26 27 17 18 19 20 21 22 23
24 25 26 27 28 29 30 28 29 30 31 24 25 26 27 28 29 30
31
April August December
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 5 6 1 2 3 1 2 3 4 5 6 7
7 8 9 10 11 12 13 4 5 6 7 8 9 10 8 9 10 11 12 13 14
14 15 16 17 18 19 20 11 12 13 14 15 16 17 15 16 17 18 19 20 21
21 22 23 24 25 26 27 18 19 20 21 22 23 24 22 23 24 25 26 27 28
28 29 30 25 26 27 28 29 30 31 29 30 31
</pre>
=={{header|Perl}}==
<syntaxhighlight lang="perl">#!/usr/bin/perl -l
 
use strict; # https://rosettacode.org/wiki/Calendar
use warnings;
use Time::Local;
 
my $year = shift // 1969;
my $width = shift // 80;
my $columns = int +($width + 2) / 22 or die "width too short at $width";
print map { center($_, $width), "\n" } '<reserved for snoopy>', $year;
my @months = qw( January February March April May June
July August September October November December );
my @days = qw( 31 28 31 30 31 30 31 31 30 31 30 31 );
(gmtime 86400 + timegm 1,1,1,28,1,$year)[3] == 29 and $days[1]++;
my @blocks = map # block per month
{
my $m = center($months[$_], 20) . "\nSu Mo Tu We Th Fr Sa\n" .
"00 00 00 00 00 00 00\n" x 6;
$m =~ s/00/ / for 1 .. (gmtime timegm 1,1,1,1,$_,$year )[6]; # day of week
$m =~ s/00/ center($_, 2) /e for 1 .. $days[$_];
$m =~ s/00/ /g;
[ split /\n/, $m ]
} 0 .. 11;
while( my @row = splice @blocks, 0, $columns ) # print by rows of months
{
print center(join(' ', map shift @$_, @row), $width) for 1 .. @{$row[0]};
}
 
sub center
{
my ($string, $w) = @_;
sprintf "%${w}s", $string . ' ' x ($w - length($string) >> 1);
}</syntaxhighlight>
{{out}}
<pre>
<reserved for snoopy>
1969
 
January February March
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1
5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8
12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15
19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22
26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29
30 31
April May June
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 3 1 2 3 4 5 6 7
6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14
13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21
20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28
27 28 29 30 25 26 27 28 29 30 31 29 30
July August September
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 1 2 3 4 5 6
6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13
13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20
20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27
27 28 29 30 31 24 25 26 27 28 29 30 28 29 30
31
October November December
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1 2 3 4 5 6
5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13
12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20
19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27
26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30
</pre>
When run with args 1969 132 produces:
<pre>
<reserved for snoopy>
1969
 
January February March April May June
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1 1 2 3 4 5 1 2 3 1 2 3 4 5 6 7
5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8 6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14
12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15 13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21
19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22 20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28
26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29 27 28 29 30 25 26 27 28 29 30 31 29 30
30 31
July August September October November December
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 1 2 3 4 5 6 1 2 3 4 1 1 2 3 4 5 6
6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13 5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13
13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20 12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20
20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27 19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27
27 28 29 30 31 24 25 26 27 28 29 30 28 29 30 26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
31 30
</pre>
=={{header|Phix}}==
Gregorian calender only.
<!--(phixonline)-->
<lang Phix>include builtins\timedate.e
<syntaxhighlight lang="phix">
 
with javascript_semantics
constant year = 1969
include builtins\timedate.e
function centre(string s, integer width)
integer padgap = width-length(s),
left = floor(padgap/2),
right = padgap-left
return repeat(' ',left) & s & repeat(' ',right)
end function
 
function one_month(integer year, integer month, bool sun_to_sat)
string weekdays = iff(sun_to_sat?"Su Mo Tu We Th Fr Sa"
integer dow = day_of_week(year,month,1)
:"Mo Tu We Th Fr Sa Su"),
sequence ldm = adjust_timedate(iff(month=12?{year+1,1,1,0,0,0,0,0}
line = repeat(' ',20)
:{year,month+1,1,0,0,0,0,0}),
sequence ldm = adjust_timedate(iff(month=12?{year+1,1,1,0,0,0,0,0}
timedelta(days:=-1))
:{year,month+1,1,0,0,0,0,0}),
sequence res = {centre(format_timedate(ldm,"Mmmm"),20),"Su Mo Tu We Th Fr Sa"}
timedelta(days:=-1)),
integer lastday = ldm[DT_DAY]
res = {centre(format_timedate(ldm,"Mmmm"),20),weekdays}
string line = repeat(' ',20)
integer pdow = dow*3-2day_of_week(year,month,1)
if sun_to_sat then dow = remainder(dow,7)+1 end if
integer lastday = ldm[DT_DAY],
p = dow*3-2
for d=1 to lastday do
line[p..p+1] = sprintf("%2d",d)
Line 4,214 ⟶ 6,177:
return res
end function
 
procedure print_calendar(integer year, integer width, bool sun_to_sat=false)
sequence months = repeat(0,12)
integer wide = floor((width+2)/22)
printf(1,centre("[Spot Reserved For Snoopy]",width)&"\n")
printf(1,centre(sprintf("%d",year),width)&"\n")
for month=1 to 12 do
months[month] = one_month(year,month,sun_to_sat)
end for
for month=1 to 12 by wide do
for k=1 to 9 do -- (more than enough)
integer any = 0
string line = "", this
for j=0 to wide-1 do
if length(line) then
Line 4,243 ⟶ 6,206:
end for
end procedure
 
print_calendar(1969year,80)
printf(1,join(repeat("1234567890",8),"")&"\n")
print_calendar(1969year,132,true)
printf(1,join(repeat("1234567890",13),"")&"12\n")</lang>
</syntaxhighlight>
{{out}}
<pre style="font-size:75%">
<pre>
 
[Spot Reserved For Snoopy]
1969
January February March
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 5 1 2 1 2
5 6 7 8 9 10 11 12 2 3 4 5 6 7 8 9 2 3 4 5 6 7 8 9
12 13 14 15 16 17 18 19 9 10 11 12 13 14 15 16 9 10 11 12 13 14 15 16
19 20 21 22 23 24 25 26 16 17 18 19 20 21 22 23 16 17 18 19 20 21 22 23
26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29 30
30 31
April May June
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 5 6 1 2 3 4 1 2 3 4 5 6 7 1
6 7 8 9 10 11 12 13 4 5 6 7 8 9 10 11 8 2 9 103 11 124 13 145 6 7 8
13 14 15 16 17 18 19 20 11 12 13 14 15 16 17 18 15 16 179 1810 1911 2012 2113 14 15
20 21 22 23 24 25 26 27 18 19 20 21 22 23 24 25 22 2316 2417 2518 2619 2720 2821 22
27 28 29 30 25 26 27 28 29 30 31 29 30 23 24 25 26 27 28 29
30
July August September
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 5 6 1 2 3 1 2 3 4 5 6 7
6 7 8 9 10 11 12 13 3 4 5 6 7 8 9 10 7 8 9 10 11 12 13 14
13 14 15 16 17 18 19 20 10 11 12 13 14 15 16 17 14 15 16 17 18 19 20 21
20 21 22 23 24 25 26 27 17 18 19 20 21 22 23 24 21 22 23 24 25 26 27 28
27 28 29 30 31 24 25 26 27 28 29 30 31 28 29 30
31
October November December
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 5 1 2 1 2 3 4 5 6 7
5 6 7 8 9 10 11 12 2 3 4 5 6 7 8 9 7 8 9 10 11 12 13 14
12 13 14 15 16 17 18 19 9 10 11 12 13 14 15 16 14 15 16 17 18 19 20 21
19 20 21 22 23 24 25 26 16 17 18 19 20 21 22 23 21 22 23 24 25 26 27 28
26 27 28 29 30 31 23 24 25 26 27 28 29 30 28 29 30 31
30
12345678901234567890123456789012345678901234567890123456789012345678901234567890
[Spot Reserved For Snoopy]
Line 4,306 ⟶ 6,268:
</pre>
 
=={{header|Phixmonti}}==
{{trans|Lua}}
<syntaxhighlight lang="phixmonti">include ..\Utilitys.pmt
 
32 var space
 
def bksp /# -- backspace #/
8 tochar print
enddef
 
def floor
.5 + int
enddef
 
def center
tostr align
enddef
 
def startday /# year -- day of the week of january 1 #/
1 - >ps
tps 365 * tps 4 / floor + tps 100 / floor - ps> 400 / floor + 7 mod
enddef
 
def bisiesto? /# year -- true if leap #/
dup 4 mod not over 100 mod and swap 400 mod not or
enddef
 
def snoopy
0 tcolor 15 bcolor
"snoopy.txt" "r" fopen var f
 
true
while
f fgets
dup -1 == if
drop
f fclose
false
else
print
true
endif
endwhile
15 tcolor 0 bcolor
enddef
 
( "JANUARY" "FEBRUARY" "MARCH" "APRIL" "MAY" "JUNE" "JULY" "AUGUST" "SEPTEMBER" "OCTOBER" "NOVEMBER" "DECEMBER" ) var months
"MO TU WE TH FR SA SU" var daysTitle
( 31 28 31 30 31 30 31 31 30 31 30 31 ) var daysPerMonth
daysTitle len nip var monthwidth
 
def makeMonth var days >ps
monthwidth center daysTitle 2 tolist
 
1 ps> - 1 + >ps
true
while
( )
7 for drop
tps 1 < tps days > or if
" "
else
tps
endif
2 align 0 put
ps> 1 + >ps
endfor
0 put
len 8 <
endwhile
ps> drop
enddef
 
def print_cal >ps
tps bisiesto? if daysPerMonth 29 2 set var daysPerMonth endif
5 space over repeat var spaces
snoopy
3 monthwidth * swap 2 * +
"--- " tps tostr " ---" chain chain swap center ? nl
ps> startday var inicio
( )
 
12 for >ps
months tps get nip inicio
daysPerMonth ps> get nip >ps
tps makeMonth 0 put
inicio ps> + 7 mod var inicio
endfor
( 0 3 ) for var i
8 for var k
3 for var j
i 3 * j + get
k get
list? if
10 tcolor
len for
get print " " print
endfor
drop
bksp
else
11 tcolor
print
endif
drop
spaces print
endfor
nl
endfor
nl
endfor
drop
enddef
 
2020 print_cal</syntaxhighlight>
{{out}}
<pre>
co;
NM0 l lXM0cM
MM 0M;
Mc ;o: lMMMMMMMXOOOOMX:
ON M `c o :MK
M W '; l :M
o ,N 0` MO
M 'MM. WM' KK
M `:`` 0M .,,,,, K:
O:;cMXcK M, `MMMMMMMMM M
cK,lMoMXlMM`.O 0XXXXXK 0
M MMMlMM;MM:N.0 0o
locOMMMKMMMMMX o` ` M
M :MMMMMlWMoWMK O .Mo cK
M MMMMMMMMMMMO 0 c: : oM
cK MMMMMMMMMMMM 0 :O `M oMl
M ,MMMMMMMOMMW 0 cK ` oM`oWNMMM'
M ,MMM0MMMMM :W ::: cMl'
0M lMNMMMM.`M ,:,MMo lMMMX
KMc NW M0 `WcX;M'
WW .M :
M;O000KMO`
MMMMo::c,:0
'M cM
 
 
--- 2020 ---
 
JANUARY FEBRUARY MARCH
MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU
1 2 3 4 5 1 2 2 3 4 5 6 7 8
6 7 8 9 10 11 12 3 4 5 6 7 8 9 9 10 11 12 13 14 15
13 14 15 16 17 18 19 10 11 12 13 14 15 16 16 17 18 19 20 21 22
20 21 22 23 24 25 26 17 18 19 20 21 22 23 23 24 25 26 27 28 29
27 28 29 30 31 24 25 26 27 28 29 30 31
 
 
APRIL MAY JUNE
MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU
1 2 3 4 5 1 2 3 1 2 3 4 5 6 7
6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14
13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21
20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28
27 28 29 30 25 26 27 28 29 30 31 29 30
 
 
JULY AUGUST SEPTEMBER
MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU
1 2 3 4 5 1 2 1 2 3 4 5 6
6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13
13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20
20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27
27 28 29 30 31 24 25 26 27 28 29 30 28 29 30
31
 
OCTOBER NOVEMBER DECEMBER
MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU
1 2 3 4 2 3 4 5 6 7 8 1 2 3 4 5 6
5 6 7 8 9 10 11 9 10 11 12 13 14 15 7 8 9 10 11 12 13
12 13 14 15 16 17 18 16 17 18 19 20 21 22 14 15 16 17 18 19 20
19 20 21 22 23 24 25 23 24 25 26 27 28 29 21 22 23 24 25 26 27
26 27 28 29 30 31 30 28 29 30 31
 
 
 
=== Press any key to exit ===</pre>
=={{header|PicoLisp}}==
This "calendar" is nicely formatted, and fits into 20 columns ;-)
<langsyntaxhighlight PicoLisplang="picolisp">(de cal (Year)
(prinl "====== " Year " ======")
(for Dat (range (date Year 1 1) (date Year 12 31))
Line 4,320 ⟶ 6,472:
(pack "Week " (week Dat)) ) ) ) ) )
 
(cal 1969)</langsyntaxhighlight>
Output:
<pre>====== 1969 ======
Line 4,346 ⟶ 6,498:
30 Tue
31 Wed</pre>
 
=={{header|Pike}}==
 
Line 4,354 ⟶ 6,505:
this script also highlights holidays by region. regions may be chosen by 2-letter country name, as well as some special 'regions': christianity, orthodox, bahai, islamic, among others.
 
<langsyntaxhighlight Pikelang="pike">#!/bin/env pike
 
int main(int argc, array(string) argv)
Line 4,473 ⟶ 6,624:
return dayname;
}
</syntaxhighlight>
</lang>
Output: (holidays lost in copy-paste)
<pre>
Line 4,511 ⟶ 6,662:
27 28 29 30 31 24 25 26 27 28 29 30 29 30 31
</pre>
 
=={{header|PL/I}}==
<syntaxhighlight lang="pl/i">
<lang PL/I>
calendar: procedure (year) options (main);
declare year character (4) varying;
Line 4,565 ⟶ 6,715:
 
end calendar;
</syntaxhighlight>
</lang>
Output:
<pre>
Line 4,617 ⟶ 6,767:
28 29 30 31 25 26 27 28 25 26 27 28 29 30 31
</pre>
=={{header|PowerShell}}==
<syntaxhighlight lang="powershell">
Param([int]$Year = 1969)
Begin {
$COL_WIDTH = 21
$COLS = 3
$MONTH_COUNT = 12
$MONTH_LINES = 9
 
Function CenterStr([string]$s, [int]$lineSize) {
$padSize = [int](($lineSize - $s.Length) / 2)
($(if ($padSize -gt 0) { ' ' * $padSize } else { '' }) + $s).PadRight($lineSize,' ')
}
 
Function MonthLines([int]$month) {
$dt = [System.DateTime]::new($Year, $month, 1)
$line = CenterStr $dt.ToString("MMMM") $COL_WIDTH
$line += 'Su Mo Tu We Th Fr Sa'
$line += $(' ' * $dt.DayOfWeek.value__)
$line += (-join ($(1..$($dt.AddMonths(1).AddDays(-1).Day)) | %{ $("" + $_).PadLeft(3) }))
$line = $line.PadRight($MONTH_LINES * $COL_WIDTH)
New-Object –TypeName PSObject –Prop(@{
'Lines'=(0..($MONTH_LINES - 1)) | %{ $_ * $COL_WIDTH } | %{ -join $line[$_..($_ + $COL_WIDTH - 1)] }
'Dt'=$dt})
}
}
Process {
Write-Output (CenterStr $Year ($COL_WIDTH * $COLS + 4))
$(0..($MONTH_COUNT / $COLS - 1)) | %{
$fm = $_ * $COLS
$monthNums = $fm..($fm + $COLS - 1) | %{ $_ + 1 }
$months = $monthNums | %{ MonthLines $_ }
$(0..($MONTH_LINES - 1)) | %{
$ml = $_
Write-Output $(-join ($(0..($COLS - 1)) | %{ $(if ($_ -eq 0) { '' } else {' '}) + $months[$_].Lines[$ml] }))
}
}
}
</syntaxhighlight>
=={{header|Prolog}}==
Call the write_calendar(Year) predicate to print a calendar for a year.
Works with swi-prolog and requires the day_of_the_week library call.
 
<syntaxhighlight lang="prolog">% Write out the calender, because format can actually span multiple lines, it is easier
% to write out the static parts in place and insert the generated parts into that format.
write_calendar(Year) :-
month_x3_format(Year, 1, 2, 3, F1_3),
month_x3_format(Year, 4, 5, 6, F4_6),
month_x3_format(Year, 7, 8, 9, F7_9),
month_x3_format(Year, 10, 11, 12, F10_12),
format('
 
~w
 
January February March
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
~w
 
April May June
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
~w
 
July August September
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
~w
 
October November December
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
~w
', [Year, F1_3, F4_6, F7_9, F10_12]), !.
 
% Generate the data for a row of months and then create an atom one row at a time
% for all of the months.
month_x3_format(Year, M1, M2, M3, F) :-
calc_month_rows(Year, M1, M1r),
calc_month_rows(Year, M2, M2r),
calc_month_rows(Year, M3, M3r),
month_x3_format(M1r, M2r, M3r, F).
month_x3_format(M1, M2, M3, '') :- maplist(=(' '), M1), maplist(=(' '), M2), maplist(=(' '), M3).
month_x3_format(M1, M2, M3, F) :-
month_format(' ', M1, M1r, F1),
month_format(F1, M2, M2r, F2),
month_format(F2, M3, M3r, F3),
atom_concat(F3, '\n', F4),
month_x3_format(M1r, M2r, M3r, Fr),
atom_concat(F4, Fr, F).
month_format(Orig, [Su,Mo,Tu,We,Th,Fr,Sa|R], R, F) :-
maplist(day_format, [Su,Mo,Tu,We,Th,Fr,Sa], Formatted),
format(atom(F2), '~w~w~w~w~w~w~w ', Formatted),
atom_concat(Orig, F2, F).
 
day_format(' ', ' ') :- !.
day_format(D, F) :- D < 10, format(atom(F), '~w ', D).
day_format(D, F) :- D >= 10, format(atom(F), '~w ', D).
 
% Calculate the days of a month, this is done by getting the first day of the month,
% then offsetting that with spaces from the start and then adding 1-NumDaysinMonth and
% finally spaces until the end. The maximum possible size is used and then truncated later.
calc_month_rows(Year, Month, Result) :-
length(Result, 42), % max 6 rows of 7 days
month_days(Month, Year, DaysInMonth),
day_of_the_week(date(Year, Month, 1), FirstWeekDay),
day_offset(FirstWeekDay, Offset),
day_print_map(DaysInMonth, Offset, Result).
 
day_print_map(DaysInMonth, 0, [1|R]) :-
day_print_map2(DaysInMonth, 2, R).
day_print_map(DaysInMonth, Offset, [' '|R]) :-
dif(Offset, 0),
succ(NewOffset, Offset),
day_print_map(DaysInMonth, NewOffset, R).
 
day_print_map2(D, D, [D|R]) :- day_print_map(R).
day_print_map2(D, N, [N|R]) :- dif(D,N), succ(N, N1), day_print_map2(D, N1, R).
 
day_print_map([]).
day_print_map([' '|R]) :- day_print_map(R).
 
% Figure out the number of days in a month based on whether it is a leap year or not.
month_days(2, Year, Days) :-
is_leap_year(Year) -> Days = 29
; Days = 28.
month_days(Month, _, Days) :-
dif(Month, 2),
nth1(Month, [31, _, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], Days).
 
% Figure out the space offset based on the day the month starts on.
day_offset(D, D) :- dif(D, 7).
day_offset(7, 0).
 
% Test for leap years
is_leap_year(Year) :-
0 is Year mod 100 -> 0 is Year mod 400
; 0 is Year mod 4.</syntaxhighlight>
=={{header|Python}}==
The Python [https://docs.python.org/3/library/calendar.html calendar].prcal function prints calendars with the following formatting options: optional parameters w, l, and c are for date column width, lines per week, and number of spaces between month columns, respectively.
 
<langsyntaxhighlight lang="python">>>> import calendar
>>> help(calendar.prcal)
Help on method pryear in module calendar:
Line 4,663 ⟶ 6,949:
13 14 15 16 17 18 19 10 11 12 13 14 15 16 15 16 17 18 19 20 21
20 21 22 23 24 25 26 17 18 19 20 21 22 23 22 23 24 25 26 27 28
27 28 29 30 31 24 25 26 27 28 29 30 29 30 31</langsyntaxhighlight>
 
=={{header|R}}==
<syntaxhighlight lang="R">
library(lubridate)
library(stringi)
 
# Helper function padding
pad_d <- function(gr) gr %>% stri_pad_left(2) %>% stri_c(collapse = " ")
pad_l <- function(gr) gr %>% pad_d() %>% stri_pad_left(20)
pad_r <- function(gr) gr %>% pad_d() %>% stri_pad_right(20)
pad_20 <- " " %s*% 20
 
# 1st week mapping
idx_week <- list("1"=1,"7"=2,"6"=3,"5"=4,"4"=5,"3"=6,"2"=7)
 
# Generate a single month
gen_cal <- function(date_str) {
str_l <- list()
# Pick up month name
month_name <- month(ymd(date_str),label = T,abbr = F) %>%
as.character() %>%
stri_pad_both(20)
# Add to list with day header
str_l[length(str_l)+1] <- month_name
str_l[length(str_l)+1] <- "Mo Tu We Th Fr Sa Su"
# Day list for the month
cc <- 1:days_in_month(as.Date(date_str))
# Staring week
wd <- wday(ymd(date_str))
st <- idx_week[as.character(wd)][[1]]
 
# Add 1st week
str_l[length(str_l)+1] <- pad_l(head(cc,st))
# Middle weeks
cc <- tail(cc,-st)
while (length(cc) > 7) {
str_l[length(str_l)+1] <- pad_l(head(cc,7))
cc <- tail(cc,-7)
}
# Last week
str_l[length(str_l)+1] <- pad_r(cc)
 
# Pad for empty week
if (length(str_l)==7)
str_l[length(str_l)+1] <- pad_20
 
str_l
}
 
# Print calendar
print_calendar <- function(target_year) {
cat("\n",stri_pad_both(target_year,64),"\n\n")
for (j in seq.int(1,12,3)) {
cal <- sapply(j:(j+2),\(x) gen_cal(paste0(target_year,"/",x,"/1")))
xres <- paste(cal[,1],cal[,2],cal[,3],sep = " ")
for (i in xres) cat(i,"\n")
}
}
 
#
# Main
#
 
print_calendar("1969")
</syntaxhighlight>
 
{{out}}
<pre>
1969
 
January February March
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 5 1 2 1 2
6 7 8 9 10 11 12 3 4 5 6 7 8 9 3 4 5 6 7 8 9
13 14 15 16 17 18 19 10 11 12 13 14 15 16 10 11 12 13 14 15 16
20 21 22 23 24 25 26 17 18 19 20 21 22 23 17 18 19 20 21 22 23
27 28 29 30 31 24 25 26 27 28 24 25 26 27 28 29 30
31
April May June
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 5 6 1 2 3 4 1
7 8 9 10 11 12 13 5 6 7 8 9 10 11 2 3 4 5 6 7 8
14 15 16 17 18 19 20 12 13 14 15 16 17 18 9 10 11 12 13 14 15
21 22 23 24 25 26 27 19 20 21 22 23 24 25 16 17 18 19 20 21 22
28 29 30 26 27 28 29 30 31 23 24 25 26 27 28 29
30
July August September
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 5 6 1 2 3 1 2 3 4 5 6 7
7 8 9 10 11 12 13 4 5 6 7 8 9 10 8 9 10 11 12 13 14
14 15 16 17 18 19 20 11 12 13 14 15 16 17 15 16 17 18 19 20 21
21 22 23 24 25 26 27 18 19 20 21 22 23 24 22 23 24 25 26 27 28
28 29 30 31 25 26 27 28 29 30 31 29 30
October November December
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 5 1 2 1 2 3 4 5 6 7
6 7 8 9 10 11 12 3 4 5 6 7 8 9 8 9 10 11 12 13 14
13 14 15 16 17 18 19 10 11 12 13 14 15 16 15 16 17 18 19 20 21
20 21 22 23 24 25 26 17 18 19 20 21 22 23 22 23 24 25 26 27 28
27 28 29 30 31 24 25 26 27 28 29 30 29 30 31
</pre>
 
=={{header|Racket}}==
<langsyntaxhighlight lang="racket">#lang racket
(require racket/date net/base64 file/gunzip)
(define (calendar yr)
Line 4,697 ⟶ 7,091:
(λ(s) (equal? "" s)))))
 
(calendar 1969)</langsyntaxhighlight>
 
{{out}}
Line 4,749 ⟶ 7,143:
26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30</pre>
=={{header|Raku}}==
(formerly Perl 6)
<syntaxhighlight lang="raku" line>my $months-per-row = 3;
my @weekday-names = <Mo Tu We Th Fr Sa Su>;
my @month-names = <Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec>;
 
my Int() $year = @*ARGS.shift || 1969;
say fmt-year($year);
 
sub fmt-year ($year) {
my @month-strs;
@month-strs[$_] = [fmt-month($year, $_).lines] for 1 .. 12;
my @C = ' ' x 30 ~ $year, '';
for 1, 1+$months-per-row ... 12 -> $month {
while @month-strs[$month] {
for ^$months-per-row -> $column {
@C[*-1] ~= @month-strs[$month+$column].shift ~ ' ' x 3 if @month-strs[$month+$column];
}
@C.push: '';
}
@C.push: '';
}
@C.join: "\n";
}
 
sub fmt-month ($year, $month) {
my $date = Date.new($year,$month,1);
@month-names[$month-1].fmt("%-20s\n") ~ @weekday-names ~ "\n" ~
((' ' xx $date.day-of-week - 1), (1..$date.days-in-month)».fmt('%2d')).flat.rotor(7, :partial).join("\n") ~
(' ' if $_ < 7) ~ (' ' xx 7-$_).join(' ') given Date.new($year, $month, $date.days-in-month).day-of-week;
}</syntaxhighlight>
=={{header|Rebol}}==
<langsyntaxhighlight lang="rebol">
Rebol []
do [if "" = y: ask "Year (ENTER for current):^/^/" [prin y: now/year]
foreach m system/locale/months [
Line 4,764 ⟶ 7,189:
]
] ask "^/^/Press [ENTER] to Continue..."]
</syntaxhighlight>
</lang>
 
=={{header|REXX}}==
Line 4,807 ⟶ 7,232:
<br>specified. &nbsp; The choice could've been performed programmatically, but I never believe that a program
<br>could best choose over what the user wants, as it depends on esthetics and looks (fashion).
<langsyntaxhighlight lang="rexx">/*REXX program to show any year's (monthly) calendar (with/without grid)*/
 
@abc='abcdefghijklmnopqrstuvwxyz'; @abcU=@abc; upper @abcU
Line 4,953 ⟶ 7,378:
put:_=arg(1);_=translate(_,,'_'chk);if \grid then _=ungrid(_);if lowerCase then _=lower(_);if upperCase then upper _;if shortest&_=' ' then return;call tell _;return
tell:say arg(1);return
ungrid:return translate(arg(1),,"│║─═┤┐└┴┬├┼┘┌╔╗╚╝╟╢╞╡╫╪╤╧╥╨╠╣")</langsyntaxhighlight>
'''output''' when using the input of: <tt> 1/1/1969 (noGrid smallest narrowest) </tt>
<pre>
Line 4,995 ⟶ 7,420:
Output when using the input of: <tt> 1/1/1969 (smallest narrowest width 156 calSpaces 5) </tt>
<br>A width of 156 was used to illustrate showing a grid, otherwise it would fit in 132 columns.
 
<pre">
(Shown at three-quarter size.)
 
<pre style="font-size:75%">
┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐
│ January 1969 │ │ February 1969 │ │ March 1969 │ │ April 1969 │ │ May 1969 │ │ June 1969 │
Line 5,045 ⟶ 7,473:
| |
</pre>
 
=={{header|Ring}}==
<langsyntaxhighlight lang="ring">
# Project : Calendar
 
Line 5,204 ⟶ 7,631:
next
next
</syntaxhighlight>
</lang>
Output image:
 
[https://www.dropbox.com/s/sj37yypiq45o5cd/CalmoSoftCalendar.jpg?dl=0 Calendar]
=={{header|RPL}}==
Screens of calculators running RPL have a maximum of 7 lines and 22 columns, so we can only display one month at a time.
 
<code>WKDAY</code> is defined at [[Last Friday of each month#RPL|Last Friday of each month]]
[[File:RPL Calendar.png|thumb|Screenshot of a HP-48 emulator]]
{{works with|HP|48}}
« FP DUP 2 TRNC 1 → month line
« CLLCD "Mo Tu We Th Fr Sa Su" 1 DISP
1 + DUP <span style="color:blue">WKDAY</span> 1 - NEG DATE+
'''DO''' ""
1 7 '''START'''
OVER FP 2 TRNC month ==
" " 4 PICK IP →STR + DUP SIZE DUP 1 -
SWAP SUB " " IFTE + " " +
SWAP 1 DATE+ SWAP
'''NEXT'''
'line' INCR DISP
'''UNTIL''' DUP FP 2 TRNC month ≠ '''END'''
7 FREEZE
» » ‘<span style="color:blue">CAL</span>’ STO
 
1.072023 <span style="color:blue">CAL</span>
 
=={{header|Ruby}}==
<code>Date</code> class, from the standard library, knows how many days in a month, and which day is Sunday, for both Julian and Gregorian calendars. This program uses <code>Date</code> class, plus its own assumptions, to create the calendar. This program assumes that every year has 12 months and starts with January 1, and every month fits in 6 weeks starting with Sunday.
 
<langsyntaxhighlight lang="ruby">require 'date'
 
# Creates a calendar of _year_. Returns this calendar as a multi-line
Line 5,281 ⟶ 7,730:
80; end; end; end
 
puts cal(Integer(ARGV[0]), columns)</langsyntaxhighlight>
 
Here is 1969 in 132 columns.
Line 5,342 ⟶ 7,791:
</pre>
 
=={{header|Rust}}==
<syntaxhighlight lang="rust">// Assume your binary name is 'calendar'.
// Command line:
// >>$ calendar 2019 150
// First argument: year number.
// Second argument (optional): text area width (in characters).
 
extern crate chrono;
 
use std::{env, cmp};
use chrono::{NaiveDate, Datelike};
 
const MONTH_WIDTH: usize = 22;
 
fn print_header(months: &[&str]) {
const DAYS_OF_WEEK: &str = "SU MO TU WE TH FR SA ";
println!();
for m in months {
print!("{:^20} ", m);
}
println!("\n{}", DAYS_OF_WEEK.repeat(months.len()));
}
 
fn get_week_str(days: i32, week_num: i32, start_day_of_week: i32) -> Option<String> {
let start = week_num * 7 - start_day_of_week + 1;
let end = (week_num + 1) * 7 - start_day_of_week;
let mut ret = String::with_capacity(MONTH_WIDTH);
if start > days {
None
} else {
for i in start..(end + 1) {
if i <= 0 || i > days {
ret.push_str(" ");
} else {
if i < 10 {
ret.push_str(" ");
}
ret.push_str(&i.to_string());
}
ret.push_str(" ");
}
ret.push_str(" ");
Some(ret)
}
}
 
fn main() {
const MONTH_NAMES: [&str; 12] = ["JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE", "JULY",
"AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER"];
const DEFAULT_TEXT_WIDTH: usize = 100;
 
let args: Vec<String> = env::args().collect();
let year: i32 = args[1].parse().expect("The first argument must be a year");
let width: usize = if args.len() > 2 {
cmp::max(MONTH_WIDTH, args[2].parse().expect("The second argument should be text width"))
} else {
DEFAULT_TEXT_WIDTH
};
let months_in_row = width / MONTH_WIDTH;
let month_rows = if MONTH_NAMES.len() % months_in_row == 0 {
MONTH_NAMES.len() / months_in_row
} else {
MONTH_NAMES.len() / months_in_row + 1
};
 
let start_days_of_week: Vec<i32> =
(1..13).map(|x| NaiveDate::from_ymd(year, x, 1).weekday().num_days_from_sunday() as i32).collect();
 
let month_days: [i32; 12] = if NaiveDate::from_ymd_opt(year, 2, 29).is_some() {
[31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
} else {
[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
};
 
println!("{year:^w$}", w=width, year=year.to_string());
for i in 0..month_rows {
let start = i * months_in_row;
let end = cmp::min((i + 1) * months_in_row, MONTH_NAMES.len());
print_header(&MONTH_NAMES[start..end]);
let mut count = 0;
let mut row_num = 0;
while count < months_in_row {
let mut row_str = String::with_capacity(width);
for j in start..end {
match get_week_str(month_days[j], row_num, start_days_of_week[j]) {
None => {
count += 1;
row_str.push_str(&" ".repeat(MONTH_WIDTH));
},
Some(week_str) => row_str.push_str(&week_str)
}
}
if count < months_in_row {
println!("{}", row_str);
}
row_num += 1;
}
}
}
</syntaxhighlight>
=={{header|Scala}}==
{{libheader|Scala}}
Line 5,347 ⟶ 7,896:
=== Scala Version 1 ===
 
<syntaxhighlight lang="scala">import java.util.{ Calendar, GregorianCalendar }
[[Category:Scala examples needing attention]]
<lang Scala>import java.util.{ Calendar, GregorianCalendar }
import language.postfixOps
import collection.mutable.ListBuffer
Line 5,500 ⟶ 8,048:
printCalendar(getGregCal(1969), List("[Snoopy Picture]", "1969"))
printCalendar(getGregCal(1582), List("[Snoopy Picture]", "1582"), printerWidth = 132)
}</langsyntaxhighlight>
 
{{out}}
Line 5,570 ⟶ 8,118:
{{works with|Scala|2.10.1}}
 
<syntaxhighlight lang="scala">/**
<lang Scala>/**
* Loosely based on the Ruby implementation.
*
Line 5,619 ⟶ 8,167:
}
 
}</langsyntaxhighlight>
 
<syntaxhighlight lang="scala">/**
<lang Scala>/**
* This provides extra classes needed for the main
* algorithm.
Line 5,673 ⟶ 8,221:
}
 
}</langsyntaxhighlight>
 
Sample output for 1792:
Line 5,705 ⟶ 8,253:
31
</pre>
 
=={{header|Seed7}}==
<langsyntaxhighlight lang="seed7">$ include "seed7_05.s7i";
include "time.s7i";
 
Line 5,759 ⟶ 8,306:
begin
printCalendar(1969, 3);
end func;</langsyntaxhighlight>
 
Original source: [http://seed7.sourceforge.net/algorith/date.htm#calendar]
Line 5,805 ⟶ 8,352:
</pre>
 
=={{header|Sidef}}==
{{trans|Perl 6Raku}}
<langsyntaxhighlight lang="ruby">require('DateTime')
 
define months_per_col = 3
Line 5,858 ⟶ 8,404:
}
 
print fmt_year(ARGV ? Number(ARGV[0]) : 1969)</langsyntaxhighlight>
{{out}}
<pre>
Line 5,894 ⟶ 8,440:
27 28 29 30 31 24 25 26 27 28 29 30 29 30 31
</pre>
=={{header|Simula}}==
{{trans|C}}
The subtleties of the post-increment logic which is used in the c program took me some time to detect.
For symmetry I also implemented the pre-increment.
<syntaxhighlight lang="simula">BEGIN
INTEGER WIDTH, YEAR;
INTEGER COLS, LEAD, GAP;
TEXT ARRAY WDAYS(0:6);
CLASS MONTH(MNAME); TEXT MNAME;
BEGIN INTEGER DAYS, START_WDAY, AT_POS;
END MONTH;
REF(MONTH) ARRAY MONTHS(0:11);
WIDTH := 80; YEAR := 1969;
 
BEGIN
TEXT T;
INTEGER I, M;
FOR T :- "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa" DO BEGIN
WDAYS(I) :- T; I := I+1;
END;
I := 0;
FOR T :- "January", "February", "March",
"April", "May", "June",
"July", "August", "September",
"October", "November", "December" DO BEGIN
MONTHS(I) :- NEW MONTH(T); I := I+1;
END;
I := 0;
FOR M := 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 DO BEGIN
MONTHS(I).DAYS := M; I := I+1;
END;
END;
 
BEGIN
 
PROCEDURE SPACE(N); INTEGER N;
BEGIN
WHILE N > 0 DO BEGIN
OUTCHAR(' '); N := N-1;
END;
END SPACE;
 
PROCEDURE INIT_MONTHS;
BEGIN
INTEGER I;
 
IF MOD(YEAR,4) = 0 AND MOD(YEAR,100) <> 0 OR MOD(YEAR,400) = 0 THEN
MONTHS(1).DAYS := 29;
 
YEAR := YEAR-1;
MONTHS(0).START_WDAY
:= MOD(YEAR * 365 + YEAR//4 - YEAR//100 + YEAR//400 + 1, 7);
 
FOR I := 1 STEP 1 UNTIL 12-1 DO
MONTHS(I).START_WDAY :=
MOD(MONTHS(I-1).START_WDAY + MONTHS(I-1).DAYS, 7);
 
COLS := (WIDTH + 2) // 22;
WHILE MOD(12,COLS) <> 0 DO
COLS := COLS-1;
GAP := IF COLS - 1 <> 0 THEN (WIDTH - 20 * COLS) // (COLS - 1) ELSE 0;
IF GAP > 4 THEN
GAP := 4;
LEAD := (WIDTH - (20 + GAP) * COLS + GAP + 1) // 2;
YEAR := YEAR+1;
END INIT_MONTHS;
 
PROCEDURE PRINT_ROW(ROW); INTEGER ROW;
BEGIN
INTEGER C, I, FROM, UP_TO;
INTEGER PROCEDURE PREINCREMENT(I); NAME I; INTEGER I;
BEGIN I := I+1; PREINCREMENT := I;
END PREINCREMENT;
INTEGER PROCEDURE POSTINCREMENT(I); NAME I; INTEGER I;
BEGIN POSTINCREMENT := I; I := I+1;
END POSTINCREMENT;
FROM := ROW * COLS;
UP_TO := FROM + COLS;
SPACE(LEAD);
FOR C := FROM STEP 1 UNTIL UP_TO-1 DO BEGIN
I := MONTHS(C).MNAME.LENGTH;
SPACE((20 - I)//2);
OUTTEXT(MONTHS(C).MNAME);
SPACE(20 - I - (20 - I)//2 + (IF C = UP_TO - 1 THEN 0 ELSE GAP));
END;
OUTIMAGE;
 
SPACE(LEAD);
FOR C := FROM STEP 1 UNTIL UP_TO-1 DO BEGIN
FOR I := 0 STEP 1 UNTIL 7-1 DO BEGIN
OUTTEXT(WDAYS(I)); OUTTEXT(IF I = 6 THEN "" ELSE " ");
END;
IF C < UP_TO - 1 THEN
SPACE(GAP)
ELSE
OUTIMAGE;
END;
 
WHILE TRUE DO BEGIN
FOR C := FROM STEP 1 UNTIL UP_TO-1 DO
IF MONTHS(C).AT_POS < MONTHS(C).DAYS THEN
GO TO IBREAK;
IBREAK:
IF C = UP_TO THEN
GO TO OBREAK;
 
SPACE(LEAD);
FOR C := FROM STEP 1 UNTIL UP_TO-1 DO BEGIN
FOR I := 0 STEP 1 UNTIL MONTHS(C).START_WDAY-1 DO
SPACE(3);
WHILE POSTINCREMENT(I) < 7 AND MONTHS(C).AT_POS < MONTHS(C).DAYS DO BEGIN
OUTINT(PREINCREMENT(MONTHS(C).AT_POS),2);
IF I < 7 OR C < UP_TO - 1 THEN
SPACE(1);
END;
WHILE POSTINCREMENT(I) <= 7 AND C < UP_TO-1 DO
SPACE(3);
IF C < UP_TO - 1 THEN
SPACE(GAP - 1);
MONTHS(C).START_WDAY := 0;
END;
OUTIMAGE;
END;
OBREAK:
OUTIMAGE;
END PRINT_ROW;
 
PROCEDURE PRINT_YEAR;
BEGIN
INTEGER ROW;
TEXT BUF;
INTEGER STRLEN;
BUF :- BLANKS(32); BUF.PUTINT(YEAR); BUF.SETPOS(1);
WHILE BUF.MORE AND THEN BUF.GETCHAR = ' ' DO
STRLEN := STRLEN+1;
BUF :- BUF.SUB(STRLEN+1, 32-STRLEN);
SPACE((WIDTH - BUF.LENGTH) // 2);
OUTTEXT(BUF); OUTIMAGE; OUTIMAGE;
WHILE ROW * COLS < 12 DO BEGIN
PRINT_ROW(ROW);
ROW := ROW+1;
END;
END PRINT_YEAR;
 
INIT_MONTHS;
PRINT_YEAR;
END;
END;</syntaxhighlight>
{{out}}
<pre>
1969
 
January February March
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1
5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8
12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15
19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22
26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29
30 31
 
April May June
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 3 1 2 3 4 5 6 7
6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14
13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21
20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28
27 28 29 30 25 26 27 28 29 30 31 29 30
 
July August September
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 1 2 3 4 5 6
6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13
13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20
20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27
27 28 29 30 31 24 25 26 27 28 29 30 28 29 30
31
 
October November December
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1 2 3 4 5 6
5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13
12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20
19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27
26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30
 
</pre>
=={{header|Smalltalk}}==
 
This implementation has been developed using '''Cuis Smalltalk''' [https://github.com/Cuis-Smalltalk/Cuis-Smalltalk-Dev] with '''Aconcagua''' loaded.
To run it, evaluate: <syntaxhighlight lang="smalltalk">CalendarPrinter printOnTranscriptForYearNumber: 1969</syntaxhighlight>
<syntaxhighlight lang="smalltalk">
"Instance Variables:
- yearToPrint: The year to print the calendar of
- stream: The stream used to print the calendar
- monthsOfYear: A collection of all the months of yearToPrint, for example January 1969, February 1969, and so on
- currentMonths: Group of 3 months under print, for example from January to March or April to June, and so on
- monthOfYearCurrentDate: A collection that associates a month with the date to print for that month. It is used to
know which day number should be printed for each month when iterating over the day of weeks of each row"
Object subclass: #CalendarPrinter
instanceVariableNames: 'yearToPrint stream monthsOfYear currentMonths monthOfYearCurrentDate'
classVariableNames: ''
poolDictionaries: ''
category: 'CalendarPrinter'
 
CalendarPrinter class>>printOnTranscriptForYearNumber: aYearNumber
(self for: (GregorianYear number: aYearNumber) on: Transcript) value
CalendarPrinter class>>for: aYear on: aStream
^self new initializeFor: aYear on: aStream
initializeFor: aYear on: aStream
yearToPrint := aYear.
stream := aStream.
monthsOfYear := yearToPrint months.
monthOfYearCurrentDate := monthsOfYear collect: [ :aMonthOfYear | aMonthOfYear firstDate ].
 
value
"Prints the year number (header) and then its months"
self
printHeader;
printMonths.
 
printHeader
"Prints the year number centered"
self center: yearToPrint number printString in: self numberOfCharactersPerLine.
stream newLine; newLine.
 
printMonths
"Prints each group of 3 months, for example from January to March, then April to June and so on"
(January to: December by: 3*month) do: [ :aMonth | self printMonthsStartingOn: aMonth ].
 
printMonthsStartingOn: aMonth
"For each group of 3 months starting in aMonth, prints the name of the month (header),
the name of the days of the week (Mo Tu ...), and then the day numbers"
currentMonths := aMonth to: aMonth next next.
self
printMonthsHeader;
printDaysOfWeekHeader;
printDayNumbers.
 
printMonthsHeader
"Prints the current group of 3 months names, centered"
currentMonths
do: [ :currentMonth | self center: currentMonth printString in: self numberOfCharactersPerMonth ]
separatedBy: [ stream space: 3 ].
stream newLine.
 
printDaysOfWeekHeader
"Prints the names of the days of week for each month of the current group of 3 months"
currentMonths
do: [ :currentMonth | self printOneMonthDaysOfWeekHeader ]
separatedBy: [ stream space: 3 ].
stream newLine.
 
printOneMonthDaysOfWeekHeader
"Prints the name of the days of week"
(Sunday to: Saturday)
do: [ :aDayOfWeek | stream nextPutAll: (aDayOfWeek printString first: 2) ]
separatedBy: [ stream space ]
 
printDayNumbers
"While there are day numbers to print, prints them in a row"
[self hasDayNumbersToPrint] whileTrue: [ self printDayNumbersRow ].
 
hasDayNumbersToPrint
"If any of the group of 3 months currently printing has day numbers to print returns true, otherwise false"
^currentMonths anySatisfy: [ :currentMonth | self isCurrentDateAtSameMonthOfYearAs: currentMonth ]
isCurrentDateAtSameMonthOfYearAs: currentMonth
"Returns true if the date to print for currentMonth is actually for the currentMonth"
^(self currentDateOf: currentMonth) month = currentMonth
 
printDayNumbersRow
"For each month of the group of 3, prints a row of day numbers"
currentMonths
do: [ :currentMonth | self printDayNumbersRowOf: currentMonth ]
separatedBy: [ stream space: 3 ].
stream newLine
 
printDayNumbersRowOf: currentMonth
"Prints the day numbers of the current week"
(Sunday to: Saturday)
do: [ :aDayOfWeek | self printDayNumberOf: currentMonth for: aDayOfWeek ]
separatedBy: [ stream space ]
 
printDayNumberOf: currentMonth for: aDayOfWeek
"If the current date of the current month corresponds to aDayOfWeeks, prints its day number,
if not, leaves a space
This is important to leave the spaces in the first row and last row for those day of week
that do not have a day number related"
| currentDate |
currentDate := self currentDateOf: currentMonth.
(self hasToPrint: currentDate of: currentMonth for: aDayOfWeek)
ifTrue: [
currentDate dayNumber printOn: stream length: 2 zeroPadded: false.
self calculateNextCurrentDateOf: currentMonth ]
ifFalse: [ stream space: 2 ]! !
 
hasToPrint: aDate of: aCurrentMonth for: aDayOfWeek
"Returns whether aDate is part of aCurrentMonth and its day of week is aDayOfWeek.
It is used to decide whether to print the date day number or leave an space"
^(aDate month = aCurrentMonth) and: [aDate day = aDayOfWeek]
 
currentDateOf: currentMonth
"Returns the date to print for currentMonth"
^monthOfYearCurrentDate at: currentMonth number
 
calculateNextCurrentDateOf: currentMonth
"Changes the date to print of the currentMonth to the next date"
monthOfYearCurrentDate at: currentMonth number put: (self currentDateOf: currentMonth) next
 
center: stringToCenter in: aNumberOfCharacters
"Prints stringToCenter centered in a line of aNumberOfCharacters total"
| centerStart |
centerStart := aNumberOfCharacters - stringToCenter size // 2.
stream
space: centerStart;
nextPutAll: stringToCenter;
space: aNumberOfCharacters - centerStart - stringToCenter size
 
numberOfCharactersPerLine
"Returns the number of characters per line"
^66
 
numberOfCharactersPerMonth
"Returns the number of character per month"
^20
</syntaxhighlight>
{{out}}
<pre>
1969
January February March
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1
5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8
12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15
19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22
26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29
30 31
April May June
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 3 1 2 3 4 5 6 7
6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14
13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21
20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28
27 28 29 30 25 26 27 28 29 30 31 29 30
July August September
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 1 2 3 4 5 6
6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13
13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20
20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27
27 28 29 30 31 24 25 26 27 28 29 30 28 29 30
31
October November December
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1 2 3 4 5 6
5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13
12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20
19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27
26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30
</pre>
=={{header|SPL}}==
<langsyntaxhighlight lang="spl">year = 1969
#.output(#.str(year,">68<"))
> row, 0..3
Line 5,932 ⟶ 8,842:
<
<= lines
.</langsyntaxhighlight>
{{out}}
<pre>
Line 5,969 ⟶ 8,879:
</pre>
=={{header|Swift}}==
<syntaxhighlight lang="swift">import Foundation
 
let monthWidth = 20
let monthGap = 2
let dayNames = "Su Mo Tu We Th Fr Sa"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMMM"
 
func rpad(string: String, width: Int) -> String {
return string.count >= width ? string
: String(repeating: " ", count: width - string.count) + string
}
 
func lpad(string: String, width: Int) -> String {
return string.count >= width ? string
: string + String(repeating: " ", count: width - string.count)
}
 
func centre(string: String, width: Int) -> String {
if string.count >= width {
return string
}
let c = (width - string.count)/2
return String(repeating: " ", count: c) + string
+ String(repeating: " ", count: width - string.count - c)
}
 
func formatMonth(year: Int, month: Int) -> [String] {
let calendar = Calendar.current
let dc = DateComponents(year: year, month: month, day: 1)
let date = calendar.date(from: dc)!
let firstDay = calendar.component(.weekday, from: date) - 1
let range = calendar.range(of: .day, in: .month, for: date)!
let daysInMonth = range.count
var lines: [String] = []
lines.append(centre(string: dateFormatter.string(from: date), width: monthWidth))
lines.append(dayNames)
var padWidth = 2
var line = String(repeating: " ", count: 3 * firstDay)
for day in 1...daysInMonth {
line += rpad(string: String(day), width: padWidth)
padWidth = 3
if (firstDay + day) % 7 == 0 {
lines.append(line)
line = ""
padWidth = 2
}
}
if line.count > 0 {
lines.append(lpad(string: line, width: monthWidth))
}
return lines
}
 
func printCentred(string: String, width: Int) {
print(rpad(string: string, width: (width + string.count)/2))
}
 
public func printCalendar(year: Int, width: Int) {
let months = min(12, max(1, (width + monthGap)/(monthWidth + monthGap)))
let lineWidth = monthWidth * months + monthGap * (months - 1)
printCentred(string: "[Snoopy]", width: lineWidth)
printCentred(string: String(year), width: lineWidth)
var firstMonth = 1
while firstMonth <= 12 {
if firstMonth > 1 {
print()
}
let lastMonth = min(12, firstMonth + months - 1)
let monthCount = lastMonth - firstMonth + 1
var lines: [[String]] = []
var lineCount = 0
for month in firstMonth...lastMonth {
let monthLines = formatMonth(year: year, month: month)
lineCount = max(lineCount, monthLines.count)
lines.append(monthLines)
}
for i in 0..<lineCount {
var line = ""
for month in 0..<monthCount {
if month > 0 {
line.append(String(repeating: " ", count: monthGap))
}
line.append(i < lines[month].count ? lines[month][i]
: String(repeating: " ", count: monthWidth))
}
print(line)
}
firstMonth = lastMonth + 1
}
}
 
printCalendar(year: 1969, width: 80)</syntaxhighlight>
 
{{out}}
<pre>
[Snoopy]
1969
January February March
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1
5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8
12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15
19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22
26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29
30 31
 
April May June
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 3 1 2 3 4 5 6 7
6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14
13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21
20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28
27 28 29 30 25 26 27 28 29 30 31 29 30
 
July August September
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 1 2 3 4 5 6
6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13
13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20
20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27
27 28 29 30 31 24 25 26 27 28 29 30 28 29 30
31
 
October November December
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1 2 3 4 5 6
5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13
12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20
19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27
26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30
</pre>
=={{header|Tcl}}==
Due to the prevalence of 80 column devices instead of 132 column ones, this code produces 3 months at a time instead of 4.
<langsyntaxhighlight lang="tcl">package require Tcl 8.5
 
# Produce information about the days in a month, without any assumptions about
Line 6,046 ⟶ 9,089:
 
snoopy
cal</langsyntaxhighlight>
Which produces this output:
<pre>
Line 6,085 ⟶ 9,128:
</pre>
If a different year is chosen, it's printed…
<langsyntaxhighlight lang="tcl">snoopy
cal 1969</langsyntaxhighlight>
<pre>
[Snoopy Picture]
Line 6,123 ⟶ 9,166:
</pre>
The code also handles Julian/Gregorian switch dates correctly, but ''must'' be told what locale to format the switch as and for what timezone in that case. For example, Spain was one of the first countries to make the change:
<langsyntaxhighlight lang="tcl">snoopy
cal 1582 :Europe/Madrid es_ES</langsyntaxhighlight>
<pre>
[Snoopy Picture]
Line 6,161 ⟶ 9,204:
</pre>
As can be seen, a Real Programmer has many intricacies to deal with!
 
=={{header|uBasic/4tH}}==
The required "Snoopy" code is here. Use it when you feel like it.
<syntaxhighlight lang="text">Print " XXXX"
Print " X XX"
Print " X *** X XXXXX"
Line 6,207 ⟶ 9,249:
Print " =====********** * X ) \\ )"
Print " ====* * X \\ \\ )XXXXX"
Print " =========********** XXXXXXXXXXXXXXXXXXXXXX"</langsyntaxhighlight>
This is the code that generates the calendar:
<syntaxhighlight lang="text">Input "Year to print: "; Y ' input required year
 
Push 63 : Gosub _Space ' center year
Line 6,336 ⟶ 9,378:
010 Print " October "; : Return
011 Print " November"; : Return
012 Print " December"; : Return</langsyntaxhighlight>
Output (missing Snoopy):
<pre>Year to print: 1969
Line 6,360 ⟶ 9,402:
 
0 OK, 0:2753</pre>
 
=={{header|UNIX Shell}}==
All Unix variations come with the cal command which makes the task very easy.
<langsyntaxhighlight lang="bash">
#!/bin/sh
echo "Snoopy goes here"
cal 1969
</syntaxhighlight>
</lang>
 
Output produced:
Line 6,407 ⟶ 9,448:
30
</pre>
=={{header|VBScript}}==
VBScript has a good set of time-date functions and can easily get the names of weekdays and months from the OS. The program sends its output line by line to stdout so it can be redirected to a file or to a printer. By default the code will print the calendar in the locale set in your Windows, you can select another one if required. It should be called from cscript.
 
<syntaxhighlight lang="vb">
'call it with year, number of months per row (1,2,3,4,6) and locale ("" for default)
docal 1969,6,""
 
function center (s,n) x=n-len(s):center=space(x\2+(x and 1))& s & space(x\2):end function
sub print(x) wscript.stdout.writeline x : end sub
function iif(a,b,c) :if a then iif=b else iif =c end if : end function
 
sub docal (yr,nmonth,sloc)
'yr year to print
'nmonth number of monts side to side, allowed values :1,2,3,4,6
'sloc locale to use . "" uses the default
 
dim ld(6)
dim d(6)
if nmonth=5 or nmonth>6 or nmonth<1 then wscript.stderr.writeline "Can't use width " & nmonth :exit sub
 
'set the locale (names of months and weekdays plus first day of week)
if sloc<>"" then Setlocale sloc
 
'make a row of short weekday names to put on top of the month days
'trim the names to 2 char and align them right
wday=""
for i=1 to 7
wday=wday &" "&right(" "& left(weekdayname(i,true,vbUseSystemDayOfWeek),2),2)
next
 
'print header of the calendar
ncols=nmonth*21+(nmonth-1)*1
print center("[Snoopy]",ncols)
print center(yr,ncols)
print string(ncols,"=")
 
'row of months
for i=1 to 12\nmonth
s="": s1="":esp=""
for j=1 to nmonth
'build header of the month row
s=s & esp & center(monthname(m+j),21)
s1=s1 & esp & wday
'get negative offset of first day of week to the weekday of day 1 of each month
d(j)= -weekday(dateserial(yr,m+j,1),vbUseSystemDayOfWeek)+2
'get last day of each month from Windows
ld(j)=day(dateserial(yr,m+j+1,0))
esp=" "
next
'print the row of months header (name of month and weekday names)
print s: print s1
'weekday rows. makes 5 or 6 rows according to the month requiring most
while(d(1)<ld(1)) or (d(2)<ld(2)) or (d(3)<ld(3)) or (d(4)<ld(4))or (d(5)<ld(5)) or (d(6)<ld(6))
s=""
for j=1 to nmonth
'fill present week row
for k=1 to 7
'add a day number only if inside the range of days of this montg
s=s& right(space(3)&iif(d(j)<1 or d(j)>ld(j),"",d(j)),3)
d(j)=d(j)+1
next
s=s&" "
next
'print a complete row of days
print s
wend
'go for the next row of monts
m=m+nmonth
if i<>12\nmonth then print ""
next
 
'print footer
print string(ncols,"=")
end sub
</syntaxhighlight>
output
<pre>
[Snoopy]
1969
===================================================================================================================================
enero febrero marzo abril mayo junio
lu ma mi ju vi sá do lu ma mi ju vi sá do lu ma mi ju vi sá do lu ma mi ju vi sá do lu ma mi ju vi sá do lu ma mi ju vi sá do
1 2 3 4 5 1 2 1 2 1 2 3 4 5 6 1 2 3 4 1
6 7 8 9 10 11 12 3 4 5 6 7 8 9 3 4 5 6 7 8 9 7 8 9 10 11 12 13 5 6 7 8 9 10 11 2 3 4 5 6 7 8
13 14 15 16 17 18 19 10 11 12 13 14 15 16 10 11 12 13 14 15 16 14 15 16 17 18 19 20 12 13 14 15 16 17 18 9 10 11 12 13 14 15
20 21 22 23 24 25 26 17 18 19 20 21 22 23 17 18 19 20 21 22 23 21 22 23 24 25 26 27 19 20 21 22 23 24 25 16 17 18 19 20 21 22
27 28 29 30 31 24 25 26 27 28 24 25 26 27 28 29 30 28 29 30 26 27 28 29 30 31 23 24 25 26 27 28 29
 
julio agosto septiembre octubre noviembre diciembre
lu ma mi ju vi sá do lu ma mi ju vi sá do lu ma mi ju vi sá do lu ma mi ju vi sá do lu ma mi ju vi sá do lu ma mi ju vi sá do
1 2 3 4 5 6 1 2 3 1 2 3 4 5 6 7 1 2 3 4 5 1 2 1 2 3 4 5 6 7
7 8 9 10 11 12 13 4 5 6 7 8 9 10 8 9 10 11 12 13 14 6 7 8 9 10 11 12 3 4 5 6 7 8 9 8 9 10 11 12 13 14
14 15 16 17 18 19 20 11 12 13 14 15 16 17 15 16 17 18 19 20 21 13 14 15 16 17 18 19 10 11 12 13 14 15 16 15 16 17 18 19 20 21
21 22 23 24 25 26 27 18 19 20 21 22 23 24 22 23 24 25 26 27 28 20 21 22 23 24 25 26 17 18 19 20 21 22 23 22 23 24 25 26 27 28
28 29 30 31 25 26 27 28 29 30 31 29 30 27 28 29 30 31 24 25 26 27 28 29 30 29 30 31
===================================================================================================================================
</pre>
=={{header|Vedit macro language}}==
This implementation uses the '''calendar.vdm''' macro that comes with Vedit. (So it serves as an example of how to call other macros from a macro.)
Line 6,413 ⟶ 9,554:
Calendar.vdm draws one month calendar. That is then copied as columnar block and pasted to the 1969 calendar.
 
<langsyntaxhighlight lang="vedit">Buf_Switch(Buf_Free)
Config_Tab(5,30,55)
#9 = 1 // first day of week: 0=Su, 1=Mo
Line 6,433 ⟶ 9,574:
EOF
Ins_Newline(2)
} </langsyntaxhighlight>
 
The code above creates calendar for 80x43 display. For 132 column display, change #3 (number of months per line) to 4 or 6, and adjust the tab positions if required.
The following would work with all widhts, but the left/right margin would not be balanced.
<syntaxhighlight lang ="vedit">Config_Tab(22)</langsyntaxhighlight>
 
Output:
Line 6,484 ⟶ 9,625:
27 28 29 30 31 24 25 26 27 28 29 30 29 30 31
</pre>
=={{header|Visual Basic .NET}}==
'''Compiler:''' Roslyn Visual Basic (language version >= 15.8)
{{works with|.NET Core|2.1}}
 
Inspired by C#. Uses iterators to generate months row-by-row and interleave them to print multiple months beside each other. Attempts to scale to specified row/column count. Minimal validation of numeric arguments is performed, so crashes may occur for certain too-small row and column counts.
 
Does not handle 1752.
 
Options and imports statements (all parts must be in one file):
<syntaxhighlight lang="vbnet">Option Compare Binary
Option Explicit On
Option Infer On
Option Strict On
 
Imports System.Globalization
Imports System.Text
Imports System.Runtime.InteropServices
Imports System.Runtime.CompilerServices</syntaxhighlight>
 
Helper to parse command-line arguments.
<syntaxhighlight lang="vbnet">Module ArgHelper
ReadOnly _ArgDict As New Dictionary(Of String, String)()
 
Delegate Function TryParse(Of T, TResult)(value As T, <Out> ByRef result As TResult) As Boolean
 
Sub InitializeArguments(args As String())
For Each item In args
item = item.ToUpperInvariant()
 
If item.Length > 0 AndAlso item(0) <> """"c Then
Dim colonPos = item.IndexOf(":"c, StringComparison.Ordinal)
 
If colonPos <> -1 Then
' Split arguments with colons into key(part before colon) / value(part after colon) pairs.
_ArgDict.Add(item.Substring(0, colonPos), item.Substring(colonPos + 1, item.Length - colonPos - 1))
End If
End If
Next
End Sub
 
Sub FromArgument(Of T)(
key As String,
<Out> ByRef var As T,
getDefault As Func(Of T),
tryParse As TryParse(Of String, T),
Optional validate As Predicate(Of T) = Nothing)
 
Dim value As String = Nothing
If _ArgDict.TryGetValue(key.ToUpperInvariant(), value) Then
If Not (tryParse(value, var) AndAlso (validate Is Nothing OrElse validate(var))) Then
Console.WriteLine($"Invalid value for {key}: {value}")
Environment.Exit(-1)
End If
Else
var = getDefault()
End If
End Sub
End Module</syntaxhighlight>
 
Program:
<syntaxhighlight lang="vbnet">Module Program
Sub Main(args As String())
Dim dt As Date
Dim columns, rows, monthsPerRow As Integer
Dim vertStretch, horizStretch, resizeWindow As Boolean
 
InitializeArguments(args)
FromArgument("date", dt, Function() New Date(1969, 1, 1), AddressOf Date.TryParse)
FromArgument("cols", columns, Function() 80, AddressOf Integer.TryParse, Function(v) v >= 20)
FromArgument("rows", rows, Function() 43, AddressOf Integer.TryParse, Function(v) v >= 0)
FromArgument("ms/row", monthsPerRow, Function() 0, AddressOf Integer.TryParse, Function(v) v <= 12 AndAlso v <= columns \ 20)
FromArgument("vstretch", vertStretch, Function() True, AddressOf Boolean.TryParse)
FromArgument("hstretch", horizStretch, Function() True, AddressOf Boolean.TryParse)
FromArgument("wsize", resizeWindow, Function() True, AddressOf Boolean.TryParse)
 
' The scroll bar in command prompt seems to take up part of the last column.
If resizeWindow Then
Console.WindowWidth = columns + 1
Console.WindowHeight = rows
End If
 
If monthsPerRow < 1 Then monthsPerRow = Math.Max(columns \ 22, 1)
 
For Each row In GetCalendarRows(dt:=dt, width:=columns, height:=rows, monthsPerRow:=monthsPerRow, vertStretch:=vertStretch, horizStretch:=horizStretch)
Console.Write(row)
Next
End Sub
 
Iterator Function GetCalendarRows(
dt As Date,
width As Integer,
height As Integer,
monthsPerRow As Integer,
vertStretch As Boolean,
horizStretch As Boolean) As IEnumerable(Of String)
 
Dim year = dt.Year
Dim calendarRowCount As Integer = CInt(Math.Ceiling(12 / monthsPerRow))
' Make room for the three empty lines on top.
Dim monthGridHeight As Integer = height - 3
 
Yield "[Snoopy]".PadCenter(width) & Environment.NewLine
Yield year.ToString(CultureInfo.InvariantCulture).PadCenter(width) & Environment.NewLine
Yield Environment.NewLine
 
Dim month = 0
Do While month < 12
Dim rowHighestMonth = Math.Min(month + monthsPerRow, 12)
 
Dim cellWidth = width \ monthsPerRow
 
' Special case when displaying only one calendar cell in a row to make 20-wide work. Adds padding between cells otherwise.
Dim cellContentWidth = If(monthsPerRow = 1, cellWidth, (cellWidth * 19) \ 20)
 
Dim cellHeight = monthGridHeight \ calendarRowCount
Dim cellContentHeight = (cellHeight * 19) \ 20
 
' Creates a month cell for the specified month (1-12).
Dim getMonthFrom =
Function(m As Integer) BuildMonth(
dt:=New Date(dt.Year, m, 1),
width:=cellContentWidth,
height:=cellContentHeight,
vertStretch:=vertStretch,
horizStretch:=horizStretch).Select(Function(x) x.PadCenter(cellWidth))
 
' The months in this row of the calendar.
Dim monthsThisRow As IEnumerable(Of IEnumerable(Of String)) =
Enumerable.Select(Enumerable.Range(month + 1, rowHighestMonth - month), getMonthFrom)
 
Dim calendarRow As IEnumerable(Of String) =
Interleaved(
monthsThisRow,
useInnerSeparator:=False,
useOuterSeparator:=True,
outerSeparator:=Environment.NewLine)
 
Dim en = calendarRow.GetEnumerator()
Dim hasNext = en.MoveNext()
Do While hasNext
 
Dim current As String = en.Current
 
' To maintain the (not strictly needed) contract of yielding complete rows, keep the newline after
' the calendar row with the last terminal row of the row.
hasNext = en.MoveNext()
Yield If(hasNext, current, current & Environment.NewLine)
Loop
 
month += monthsPerRow
Loop
End Function
 
''' <summary>
''' Interleaves the elements of the specified sub-sources by making successive passes through the source
''' enumerable, yielding a single element from each sub-source in sequence in each pass, optionally inserting a
''' separator between elements of adjacent sub-sources and optionally a different separator at the end of each
''' pass through all the sources. (i.e., between elements of the last and first source)
''' </summary>
''' <typeparam name="T">The type of the elements of the sub-sources.</typeparam>
''' <param name="sources">A sequence of the sequences whose elements are to be interleaved.</param>
''' <param name="useInnerSeparator">Whether to insert <paramref name="useInnerSeparator"/> between the elements ofadjacent sub-sources.</param>
''' <param name="innerSeparator">The separator between elements of adjacent sub-sources.</param>
''' <param name="useOuterSeparator">Whether to insert <paramref name="outerSeparator"/> between the elements of the last and first sub-sources.</param>
''' <param name="outerSeparator">The separator between elements of the last and first sub-source.</param>
''' <param name="whileAny">If <see langword="true"/>, the enumeration continues until every given subsource is empty;
''' if <see langword="false"/>, the enumeration stops as soon as any enumerable no longer has an element to supply for the next pass.</param>
Iterator Function Interleaved(Of T)(
sources As IEnumerable(Of IEnumerable(Of T)),
Optional useInnerSeparator As Boolean = False,
Optional innerSeparator As T = Nothing,
Optional useOuterSeparator As Boolean = False,
Optional outerSeparator As T = Nothing,
Optional whileAny As Boolean = True) As IEnumerable(Of T)
Dim sourceEnumerators As IEnumerator(Of T)() = Nothing
 
Try
sourceEnumerators = sources.Select(Function(x) x.GetEnumerator()).ToArray()
Dim numSources = sourceEnumerators.Length
Dim enumeratorStates(numSources - 1) As Boolean
 
Dim anyPrevIters As Boolean = False
Do
' Indices of first and last sub-sources that have elements.
Dim firstActive = -1, lastActive = -1
 
' Determine whether each sub-source that still have elements.
For i = 0 To numSources - 1
enumeratorStates(i) = sourceEnumerators(i).MoveNext()
If enumeratorStates(i) Then
If firstActive = -1 Then firstActive = i
lastActive = i
End If
Next
 
' Determine whether to yield anything in this iteration based on whether whileAny is true.
' Not yielding anything this iteration implies that the enumeration has ended.
Dim thisIterHasResults As Boolean = If(whileAny, firstActive <> -1, firstActive = 0 AndAlso lastActive = numSources - 1)
If Not thisIterHasResults Then Exit Do
 
' Don't insert a separator on the first pass.
If anyPrevIters Then
If useOuterSeparator Then Yield outerSeparator
Else
anyPrevIters = True
End If
 
' Go through and yield from the sub-sources that still have elements.
For i = 0 To numSources - 1
If enumeratorStates(i) Then
' Don't insert a separator before the first element.
If i > firstActive AndAlso useInnerSeparator Then Yield innerSeparator
Yield sourceEnumerators(i).Current
End If
Next
Loop
 
Finally
If sourceEnumerators IsNot Nothing Then
For Each en In sourceEnumerators
en.Dispose()
Next
End If
End Try
End Function
 
''' <summary>
''' Returns the rows representing one month cell without trailing newlines. Appropriate leading and trailing
''' whitespace is added so that every row has the length of width.
''' </summary>
''' <param name="dt">A date within the month to represent.</param>
''' <param name="width">The width of the cell.</param>
''' <param name="height">The height.</param>
''' <param name="vertStretch">If <see langword="true" />, blank rows are inserted to fit the available height.
''' Otherwise, the cell has a constant height of </param>
''' <param name="horizStretch">If <see langword="true" />, the spacing between individual days is increased to
''' fit the available width. Otherwise, the cell has a constant width of 20 characters and is padded to be in
''' the center of the expected width.</param>
Iterator Function BuildMonth(dt As Date, width As Integer, height As Integer, vertStretch As Boolean, horizStretch As Boolean) As IEnumerable(Of String)
Const DAY_WDT = 2 ' Width of a day.
Const ALLDAYS_WDT = DAY_WDT * 7 ' Width of al ldays combined.
 
' Normalize the date to January 1.
dt = New Date(dt.Year, dt.Month, 1)
 
' Horizontal whitespace between days of the week. Constant of 6 represents 6 separators per line.
Dim daySep As New String(" "c, Math.Min((width - ALLDAYS_WDT) \ 6, If(horizStretch, Integer.MaxValue, 1)))
' Number of blank lines between rows.
Dim vertblankCount = If(Not vertStretch, 0, (height - 8) \ 7)
 
' Width of each day * 7 days in one row + day separator length * 6 separators per line.
Dim blockWidth = ALLDAYS_WDT + daySep.Length * 6
 
' The whitespace at the beginning of each line.
Dim leftPad As New String(" "c, (width - blockWidth) \ 2)
' The whitespace for blank lines.
Dim fullPad As New String(" "c, width)
 
' Lines are "staged" in the stringbuilder.
Dim sb As New StringBuilder(leftPad)
Dim numLines = 0
 
' Get the current line so far form the stringbuilder and begin a new line.
' Returns the current line and trailing blank lines used for vertical padding (if any).
' Returns empty enumerable if the height requirement has been reached.
Dim EndLine =
Function() As IEnumerable(Of String)
Dim finishedLine As String = sb.ToString().PadRight(width)
sb.Clear()
sb.Append(leftPad)
 
' Use an inner iterator to prevent lazy execution of side effects of outer function.
Return If(numLines >= height,
Enumerable.Empty(Of String)(),
Iterator Function() As IEnumerable(Of String)
Yield finishedLine
numLines += 1
 
For i = 1 To vertblankCount
If numLines >= height Then Return
Yield fullPad
numLines += 1
Next
End Function())
End Function
 
' Yield the month name.
sb.Append(PadCenter(dt.ToString("MMMM", CultureInfo.InvariantCulture), blockWidth))
For Each l In EndLine()
Yield l
Next
 
' Yield the header of weekday names.
Dim weekNmAbbrevs = [Enum].GetNames(GetType(DayOfWeek)).Select(Function(x) x.Substring(0, 2))
sb.Append(String.Join(daySep, weekNmAbbrevs))
For Each l In EndLine()
Yield l
Next
 
' Day of week of first day of month.
Dim startWkDy = CInt(dt.DayOfWeek)
 
' Initialize with empty space for the first line.
Dim firstPad As New String(" "c, (DAY_WDT + daySep.Length) * startWkDy)
sb.Append(firstPad)
 
Dim d = dt
Do While d.Month = dt.Month
sb.AppendFormat(CultureInfo.InvariantCulture, $"{{0,{DAY_WDT}}}", d.Day)
 
' Each row ends on saturday.
If d.DayOfWeek = DayOfWeek.Saturday Then
For Each l In EndLine()
Yield l
Next
Else
sb.Append(daySep)
End If
 
d = d.AddDays(1)
Loop
 
' Keep adding empty lines until the height quota is met.
Dim nextLines As IEnumerable(Of String)
Do
nextLines = EndLine()
For Each l In nextLines
Yield l
Next
Loop While nextLines.Any()
End Function
 
''' <summary>
''' Returns a new string that center-aligns the characters in this string by padding to the left and right with
''' the specified character to a specified total length.
''' </summary>
''' <param name="s">The string to center-align.</param>
''' <param name="totalWidth">The number of characters in the resulting string.</param>
''' <param name="paddingChar">The padding character.</param>
<Extension()>
Private Function PadCenter(s As String, totalWidth As Integer, Optional paddingChar As Char = " "c) As String
Return s.PadLeft(((totalWidth - s.Length) \ 2) + s.Length, paddingChar).PadRight(totalWidth, paddingChar)
End Function
End Module
</syntaxhighlight>
 
====Command-line arguments:====
Syntax: <name>:<value>, space-separated and optionally enclosed in quotes.
* date: Date within year to display. Accepts whatever the .NET DateTime parser is able to parse. Default: 1969-01-01.
* cols: Number of columns to display. Default: 80. Min: 20.
* rows: Number of rows to display. Default: 43. Min: 0.
* ms/row: Number of months per row (or as many as possible for values < 1). Default: 0. Max: 12 or cols*20.
* vstretch: Whether individual months are expanded with whitespace to fill vertical space. Default: true.
* hstretch: Whether individual months are expanded with whitespace to fill horizontal space. Default: true.
* wsize: Whether to resize the command window to the value given by ''cols'' and ''rows''. Set to false if the program is crashing with an error about the console buffer. Default: true.
 
{{out|note=80x43 [default with no args]}}
<pre> [Snoopy]
1969
 
January February March
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1
5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8
12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15
19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22
26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29
30 31
April May June
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 3 1 2 3 4 5 6 7
6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14
13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21
20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28
27 28 29 30 25 26 27 28 29 30 31 29 30
July August September
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 1 2 3 4 5 6
6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13
13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20
20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27
27 28 29 30 31 24 25 26 27 28 29 30 28 29 30
31
October November December
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1 2 3 4 5 6
5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13
12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20
19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27
26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30
</pre>
 
{{out|input=cols:132 rows:60 ms/row:4|note=132-column demonstrating stretching}}
<pre> [Snoopy]
1969
 
January February March April
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1 1 2 3 4 5
5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8 6 7 8 9 10 11 12
12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15 13 14 15 16 17 18 19
19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22 20 21 22 23 24 25 26
26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29 27 28 29 30
30 31
May June July August
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 1 2 3 4 5 6 7 1 2 3 4 5 1 2
4 5 6 7 8 9 10 8 9 10 11 12 13 14 6 7 8 9 10 11 12 3 4 5 6 7 8 9
11 12 13 14 15 16 17 15 16 17 18 19 20 21 13 14 15 16 17 18 19 10 11 12 13 14 15 16
18 19 20 21 22 23 24 22 23 24 25 26 27 28 20 21 22 23 24 25 26 17 18 19 20 21 22 23
25 26 27 28 29 30 31 29 30 27 28 29 30 31 24 25 26 27 28 29 30
31
September October November December
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 6 1 2 3 4 1 1 2 3 4 5 6
7 8 9 10 11 12 13 5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13
14 15 16 17 18 19 20 12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20
21 22 23 24 25 26 27 19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27
28 29 30 26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30
</pre>
 
{{out|input=cols:132 rows:30 ms/row:6|note=132-column unstretched}}
<pre> [Snoopy]
1969
 
January February March April May June
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1 1 2 3 4 5 1 2 3 1 2 3 4 5 6 7
5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8 6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14
12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15 13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21
19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22 20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28
26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29 27 28 29 30 25 26 27 28 29 30 31 29 30
30 31
July August September October November December
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 1 2 3 4 5 6 1 2 3 4 1 1 2 3 4 5 6
6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13 5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13
13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20 12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20
20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27 19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27
27 28 29 30 31 24 25 26 27 28 29 30 28 29 30 26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
31 30
</pre>
 
{{out|input=cols:20 rows:120 wsize:false|note=20-column}}
 
<pre> [Snoopy]
1969
 
January
Su Mo Tu We Th Fr Sa
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
February
Su Mo Tu We Th Fr Sa
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
March
Su Mo Tu We Th Fr Sa
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
April
Su Mo Tu We Th Fr Sa
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
May
Su Mo Tu We Th Fr Sa
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
June
Su Mo Tu We Th Fr Sa
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
July
Su Mo Tu We Th Fr Sa
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
August
Su Mo Tu We Th Fr Sa
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
September
Su Mo Tu We Th Fr Sa
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
October
Su Mo Tu We Th Fr Sa
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
November
Su Mo Tu We Th Fr Sa
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
December
Su Mo Tu We Th Fr Sa
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
</pre>
=={{header|Wren}}==
{{libheader|Wren-date}}
{{libheader|Wren-fmt}}
{{libheader|Wren-seq}}
<syntaxhighlight lang="wren">import "./date" for Date
import "./fmt" for Fmt
import "./seq" for Lst
 
var calendar = Fn.new { |year|
var snoopy = "🐶"
var days = "Su Mo Tu We Th Fr Sa"
var months = [
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
]
Fmt.print("$70m", snoopy)
var yearStr = "--- %(year) ---"
Fmt.print("$70m\n", yearStr)
var first = List.filled(3, 0)
var mlen = List.filled(3, 0)
var c = 0
for (chunk in Lst.chunks(months, 3)) {
for (i in 0..2) Fmt.write("$20m ", chunk[i])
System.print()
for (i in 0..2) System.write("%(days) ")
System.print()
first[0] = Date.new(year, c*3 + 1, 1).dayOfWeek % 7
first[1] = Date.new(year, c*3 + 2, 1).dayOfWeek % 7
first[2] = Date.new(year, c*3 + 3, 1).dayOfWeek % 7
mlen[0] = Date.monthLength(year, c*3 + 1)
mlen[1] = Date.monthLength(year, c*3 + 2)
mlen[2] = Date.monthLength(year, c*3 + 3)
for (i in 0..5) {
for (j in 0..2) {
var start = 1 + 7 * i - first[j]
for (k in start..start+6) {
if (k >= 1 && k <= mlen[j]) {
Fmt.write("$2d ", k)
} else {
System.write(" ")
}
}
System.write(" ")
}
System.print()
}
System.print()
c = c + 1
}
}
 
calendar.call(1969)</syntaxhighlight>
 
{{out}}
<pre>
🐶
--- 1969 ---
 
January February March
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1
5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8
12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15
19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22
26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29
30 31
 
April May June
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 3 1 2 3 4 5 6 7
6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14
13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21
20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28
27 28 29 30 25 26 27 28 29 30 31 29 30
 
July August September
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 1 2 3 4 5 6
6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13
13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20
20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27
27 28 29 30 31 24 25 26 27 28 29 30 28 29 30
31
 
October November December
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1 2 3 4 5 6
5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13
12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20
19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27
26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30
</pre>
 
=={{header|WYLBUR}}==
 
Unlike IBM 3278 terminals, WYLBUR was "of the time" of 1969. And rather than being a simulation of its display in 20-column mode, the "output" below is an adaptation of the actual display (as simple to create & use in any other text editor not using proportional spacing) for html. This entry is intended to show that WYLBUR could display 1969's calendar in a much smaller area than traditional alternatives (even without ORVYL). It also accomodates the display of Julian and even Old Style Calendars. One has to calculate the day for one Key Date in a given Calendar year, but using a less involved formula than for a pure computer program, since the burden for knowing whether certain months fall in a leap year shifts to the user.
 
A month appears as numbers (Roman numerals for leap years) below a column of dates which are defined as "Key Dates" for the corresponding months. A Key Day is the day of the week on which Key Dates occur in a Calendar year. Step A describes how to find the Key Day, which is used in Step B to display a calendar just by sliding the columns of dates in the lower output window. In WYLBUR, one slides the row of weekdays instead by inserting or deleting spaces to the left of the first "S" (and vastly easier to align than here via javascript).
 
A. Calculate the Key Day: for a given date in the Gregorian Calendar, calculate the day on which its Key Dates occur using ([YE32 div
16]+ YEAR div 4 + YEAR) mod 7. (For Julian & Old Style dates, omit the [YE32...] term where the non-century digits of the YEAR are
replaced by 32.) The remainder of the division by 7 gives the Key Day as follows: 0=Sunday -> 6=Saturday. For the Gregorian 1969, (120 + 492 + 1969) mod 7 gives Friday as the Key Day.
 
B. Display the calendar for November: slide the columns so that 28 rests under the Key Day. One has as well the calendar for the
prior MARCH & non-leap FEB corresponding to the relevant Calendar of the given date, as shown in the Month Key.
 
C. Display the calendar for another month: slide the columns so that the Key Day appears in the same column as the number of
the month to be displayed, as shown in the Month Key.
 
N.B. the output window may not scroll in Microsoft browsers; in Firefox a monospaced font might need to be specified, if it's using a
proportional one; Chrome displays this properly for both desktop & mobile (9.87+) versions.
{{output}}
<pre> Any Year Calendar
--------------------
S M T W T F S
</pre>
<pre style="height:35x;width:25ex;">
 
......................1..2..3..4..5..6
.1..2..3..4..5..6..7..8..9.10.11.12.13
.8..9.10.11.12.13.14.15.16.17.18.19.20
15.16.17.18.19.20.21.22.23.24.25.26.27
22.23.24.25.26.27.28.29.30.31
29.30.31
..........i.09.................i.09...
ii.05.00.04.12.06.03.ii.05.00.04.12.06
08.13.10.07.xv.14.11.08.13.10.07.xv.14
</pre>
Month Key
over the following
span of months for
relevant Calendar:
<pre>
00 non-leap JAN: Julian or Gregorian
.i a leap JAN on Julian or Gregorian
ii a leap FEB on Julian or Gregorian
03 non-leap FEB: Julian or Gregorian
03 MARCH on Julian or Gregorian
--
03 25-31 MARCH: Old Style Calendar
04 to 12: April-December on all three
13 jan on Old Style Calendar
14 feb on Old Style Calendar
14 march 01-24: O. S. non-leap year
xv march 01-24: Old Style leap year
</pre>
=={{header|XLISP}}==
Targets the 132-column imaginary line printer. The day of the week on 1 January of a given year is found using Gauss's algorithm; <tt>LEAP-YEARP</tt> is taken from the Rosetta Code task on leap years.
<langsyntaxhighlight lang="lisp">(defun calendar (year)
(define months-list '(("JANUARY" 31) ("FEBRUARY" 28) ("MARCH" 31) ("APRIL" 30) ("MAY" 31) ("JUNE" 30) ("JULY" 31) ("AUGUST" 31) ("SEPTEMBER" 30) ("OCTOBER" 31) ("NOVEMBER" 30) ("DECEMBER" 31)))
(define days #(" Sunday " "Monday " "Tuesday " "Wednesday " "Thursday " "Friday " "Saturday"))
Line 6,545 ⟶ 10,418:
(print-calendar months-list (gauss-algorithm year)))
 
(calendar 1969)</langsyntaxhighlight>
{{out}}
<pre> ******** SNOOPY CALENDAR 1969 ********
Line 6,661 ⟶ 10,534:
21 22 23 24 25 26 27
28 29 30 31 </pre>
 
=={{header|XPL0}}==
<langsyntaxhighlight XPL0lang="xpl0">include c:\cxpl\codes; \intrinsic 'code' declarations
 
func WeekDay(Year, Month, Day); \Return day of week (0=Sun 1=Mon..6=Sat)
Line 6,721 ⟶ 10,593:
];
 
Calendar(1969)</langsyntaxhighlight>
 
{{out}}
Line 6,764 ⟶ 10,636:
30
</pre>
 
=={{header|Yabasic}}==
{{trans|Lua}}
<syntaxhighlight lang="yabasic">
<lang Yabasic>
clear screen
 
Line 6,875 ⟶ 10,746:
 
print_cal(2018)
</syntaxhighlight>
</lang>
 
=={{header|zkl}}==
Gregorian calender only. Hard coded to a fit on a 80x43 terminal (somewhat half assed).
<langsyntaxhighlight lang="zkl">var [const] D=Time.Date, days="Su Mo Tu We Th Fr Sa";
 
fcn center(text,m) { String(" "*((m-text.len())/2),text) }
Line 6,904 ⟶ 10,774:
 
if(vm.numArgs){ y:=vm.nthArg(0).toInt(); oneYear(y,"").println(); }
else oneYear().println();</langsyntaxhighlight>
oneMonth produces a list of strings that make up a one month calender. Each day is three characters, the first line is padded with blanks to line it up with the 1st day of the week. The entire month is one long list of "days" that is then chunked into a list of weeks (one line per week). oneYear takes 3 months and builds the page line by line.
{{out}}
3

edits