Calendar: Difference between revisions
m (→{{header|Perl}}: enable Perl syntax highlighting) |
m (→{{header|Pike}}: difficult to read long lines of code) |
||
Line 2,019: | Line 2,019: | ||
=={{header|Pike}}== |
=={{header|Pike}}== |
||
{{lines_too_long}} |
|||
the Calendar in Pike does not handle the transitions from the Julian to the Gregorian calendar, but it handles those separately. |
the Calendar in Pike does not handle the transitions from the Julian to the Gregorian calendar, but it handles those separately. |
||
the default calendar is ISO, other options are Gregorian, Julian, Bahai, Coptic, Islamic and Discordian. |
the default calendar is ISO, other options are Gregorian, Julian, Bahai, Coptic, Islamic and Discordian. |
Revision as of 10:27, 4 February 2014
You are encouraged to solve this task according to the task description, using any language you may know.
Create a routine that will generate a text calendar for any year. Test the calendar by generating a calendar for the year 1969, on a device of the time. Choose one of the following devices:
- A line printer with a width of 132 characters.
- An 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.)
Kudos (κῦδος) for routines that also correctly transition from Julian to Gregorian calendar in September 1752.
This task is inspired by Real Programmers Don't Use PASCAL by Ed Post, Datamation, volume 29 number 7, July 1983.
THE REAL PROGRAMMER'S NATURAL HABITAT "Taped to the wall is a line-printer Snoopy calender for the year 1969."
For further Kudos see task CALENDAR, where all code is to be in UPPERCASE.
For economy of size, do not actually include Snoopy generation in either the code or the output, instead just output a place-holder.
Ada
Specification of a "Printable_Calendar" package (printable_calendar.ads):
<lang Ada>with Ada.Calendar.Formatting;
package Printable_Calendar is
subtype String20 is String(1 .. 20); type Month_Rep_Type is array (Ada.Calendar.Month_Number) of String20;
type Description is record Weekday_Rep: String20; Month_Rep: Month_Rep_Type; end record; -- for internationalization, you only need to define a new description
Default_Description: constant Description := (Weekday_Rep => "Mo Tu We Th Fr Sa So", Month_Rep => (" January ", " February ", " March ", " April ", " May ", " June ", " July ", " August ", " September ", " October ", " November ", " December "));
type Calendar (<>) is tagged private;
-- Initialize a calendar for devices with 80- or 132-characters per row function Init_80(Des: Description := Default_Description) return Calendar; function Init_132(Des: Description := Default_Description) return Calendar;
-- the following procedures output to standard IO; override if neccessary procedure New_Line(Cal: Calendar); procedure Put_String(Cal: Calendar; S: String);
-- the following procedures do the real stuff procedure Print_Line_Centered(Cal: Calendar'Class; Line: String); procedure Print(Cal: Calendar'Class; Year: Ada.Calendar.Year_Number; Year_String: String); -- this is the main Thing
private
type Calendar is tagged record Columns, Rows, Space_Between_Columns: Positive; Left_Space: Natural;
Weekday_Rep: String20; Month_Rep: Month_Rep_Type; end record;
end Printable_Calendar;</lang>
Next the implementation (printable_calendar.ads):
<lang Ada>with Ada.Text_IO;
package body Printable_Calendar is
use Ada.Calendar; package F renames Ada.Calendar.Formatting;
function Days_Per_Month(Year: Year_Number; Month: Month_Number) return Day_Number is begin case Month is when 1 | 3 | 5 | 7 | 8 | 10 | 12 => return 31; when 4 | 6 | 9 | 11 => return 30; when 2 => if Year mod 4 /= 0 then return 28; elsif Year mod 100 /= 0 then return 29; elsif Year mod 400 /= 0 then return 28; else return 29; end if; end case; end Days_Per_Month;
type Full_Month_Rep is array (1 .. 6) of String20; function Generate_Printable_Month (Y: Ada.Calendar.Year_Number; M: Ada.Calendar.Month_Number) return Full_Month_Rep is
X: Full_Month_Rep := (others => " "); -- If X=Generate_Printable_Month(2011, 01), the result could be -- " January ", -- Month_Rep(01) -- "Mo Tu We Th Fr Sa Su" -- Weekday_Rep -- " 1 2" -- X(1) -- " 3 4 5 6 7 8 9" -- X(2) -- "10 11 12 13 14 15 16" -- X(3) -- "17 18 19 20 21 22 23" -- X(4) -- "24 25 26 27 28 29 30" -- X(5) -- "31 " -- X(6)
Row: Integer range 1 .. 6 := 1; Day_Index: constant array(F.Day_Name) of Positive := (1, 4, 7, 10, 13, 16, 19); begin for I in 1 .. Days_Per_Month(Y, M) loop declare Weekday: constant F.Day_Name := F.Day_Of_Week(F.Time_Of(Y, M, I)); Pos: constant Positive := Day_Index(Weekday); Cleartext_Name: constant String := Day_Number'Image(I); L: constant Positive := Cleartext_Name'Last; begin X(Row)(Pos .. Pos+1) := Cleartext_Name(L-1 .. L); if F."="(Weekday, F.Sunday) then Row := Row + 1; end if; end; end loop; return X; end Generate_Printable_Month;
procedure Print(Cal: Calendar'class; Year: Ada.Calendar.Year_Number; Year_String: String) is
The_Month: Month_Number := Month_Number'First;
procedure Write_Space(Length: Natural) is begin for I in 1 .. Length loop Cal.Put_String(" "); end loop; end Write_Space;
Year_Rep: array(Month_Number) of Full_Month_Rep;
begin -- print the year Cal.Print_Line_Centered(Year_String);
-- generate a printable form for all the months for Month in Month_Number loop Year_Rep(Month) := Generate_Printable_Month(Year, Month); end loop;
begin while True loop
-- new line Cal.New_Line;
-- write month names Write_Space(Cal.Left_Space); for Month in The_Month .. The_Month+Cal.Columns-2 loop Cal.Put_String(Cal.Month_Rep(Month)); Write_Space(Cal.Space_Between_Columns); end loop; Cal.Put_String(Cal.Month_Rep(The_Month+Cal.Columns-1)); Cal.New_Line;
-- write "Mo Tu .. So" - or whatever is defined by Weekday_Rep Write_Space(Cal.Left_Space); for Month in The_Month .. The_Month+Cal.Columns-2 loop Cal.Put_String(Cal.Weekday_Rep); Write_Space(Cal.Space_Between_Columns); end loop; Cal.Put_String(Cal.Weekday_Rep); Cal.New_Line;
-- write the dates for I in 1 .. 6 loop Write_Space(Cal.Left_Space); for Month in The_Month .. The_Month+Cal.Columns-2 loop Cal.Put_String(Year_Rep(Month)(I)); Write_Space(Cal.Space_Between_Columns); end loop; Cal.Put_String(Year_Rep(The_Month+Cal.Columns-1)(I)); Cal.New_Line; end loop;
The_Month := The_Month + Cal.Columns; -- this will eventually raise Constraint_Error to terminate the loop end loop; exception when Constraint_Error => null; end; end Print;
procedure New_Line(Cal: Calendar) is begin Ada.Text_IO.New_Line; end New_Line;
procedure Put_String(Cal: Calendar; S: String) is begin Ada.Text_IO.Put(S); end Put_String;
procedure Print_Line_Centered(Cal: Calendar'Class; Line: String) is Width : constant Positive := Cal.Columns*20 + (Cal.Columns-1)*Cal.Space_Between_Columns + Cal.Left_Space; begin if Line'Length >= Width-1 then Cal.Put_String(Line); Cal.New_Line; else Print_Line_Centered(Cal, " " & Line & " "); end if; end Print_Line_Centered;
function Init_80(Des: Description := Default_Description) return Calendar is X: Calendar:= (Columns => 3, Rows => 4, Space_Between_Columns => 4, Left_Space => 1, Weekday_Rep => Des.Weekday_Rep, Month_Rep => Des.Month_Rep ); begin return X; end Init_80;
function Init_132(Des: Description := Default_Description) return Calendar is X: Calendar:= (Columns => 6, Rows => 2, Space_Between_Columns => 2, Left_Space => 1, Weekday_Rep => Des.Weekday_Rep, Month_Rep => Des.Month_Rep ); begin return X; end Init_132;
end Printable_Calendar;</lang>
Now, the main program is really simple:
<lang Ada>with Printable_Calendar;
procedure Cal is
C: Printable_Calendar.Calendar := Printable_Calendar.Init_80;
begin
C.Print_Line_Centered("[reserved for Snoopy]"); C.New_Line; C.Print(1969, "Nineteen-Sixty-Nine");
end Cal;</lang>
Here is the output:
[reserved for Snoopy] Nineteen-Sixty-Nine January February March Mo Tu We Th Fr Sa So Mo Tu We Th Fr Sa So Mo Tu We Th Fr Sa So 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 So Mo Tu We Th Fr Sa So Mo Tu We Th Fr Sa So 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 So Mo Tu We Th Fr Sa So Mo Tu We Th Fr Sa So 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 So Mo Tu We Th Fr Sa So Mo Tu We Th Fr Sa So 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
To get a 132-character-wide output, you just have to replace "Init_80" by "Init_132" in the main program.
ALGOL 68
<lang algol68>#!/usr/local/bin/a68g --script #
PROC print calendar = (INT year, page width)VOID: (
[]STRING month names = ( "January","February","March","April","May","June", "July","August","September","October","November","December"), weekday names = ("Su","Mo","Tu","We","Th","Fr","Sa"); FORMAT weekday fmt = $g,n(UPB weekday names - LWB weekday names)(" "g)$;
# Juggle the calendar format to fit the printer/screen width # INT day width = UPB weekday names[1], day gap=1; INT month width = (day width+day gap) * UPB weekday names-1; INT month heading lines = 2; INT month lines = (31 OVER UPB weekday names+month heading lines+2); # +2 for head/tail weeks # INT year cols = (page width+1) OVER (month width+1); INT year rows = (UPB month names-1)OVER year cols + 1; INT month gap = (page width - year cols*month width + 1)OVER year cols; INT year width = year cols*(month width+month gap)-month gap; INT year lines = year rows*month lines;
MODE MONTHBOX = [month lines, month width]CHAR; MODE YEARBOX = [year lines, year width]CHAR;
INT week start = 1; # Sunday #
PROC days in month = (INT year, month)INT: CASE month IN 31, IF year MOD 4 EQ 0 AND year MOD 100 NE 0 OR year MOD 400 EQ 0 THEN 29 ELSE 28 FI, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ESAC;
PROC day of week = (INT year, month, day)INT: ( # Day of the week by Zeller’s Congruence algorithm from 1887 # INT y := year, m := month, d := day, c; IF m <= 2 THEN m +:= 12; y -:= 1 FI; c := y OVER 100; y %*:= 100; (d - 1 + ((m + 1) * 26) OVER 10 + y + y OVER 4 + c OVER 4 - 2 * c) MOD 7 );
MODE SIMPLEOUT = UNION(STRING, []STRING, INT);
PROC cputf = (REF[]CHAR out, FORMAT fmt, SIMPLEOUT argv)VOID:( FILE f; STRING s; associate(f,s); putf(f, (fmt, argv)); out[:UPB s]:=s; close(f) );
PROC month repr = (INT year, month)MONTHBOX:( MONTHBOX month box; FOR line TO UPB month box DO month box[line,]:=" "* 2 UPB month box OD; STRING month name = month names[month];
# center the title # cputf(month box[1,(month width - UPB month name ) OVER 2+1:], $g$, month name); cputf(month box[2,], weekday fmt, weekday names);
INT first day := day of week(year, month, 1); FOR day TO days in month(year, month) DO INT line = (day+first day-week start) OVER UPB weekday names + month heading lines + 1; INT char =((day+first day-week start) MOD UPB weekday names)*(day width+day gap) + 1; cputf(month box[line,char:char+day width-1],$g(-day width)$, day) OD; month box );
PROC year repr = (INT year)YEARBOX:( YEARBOX year box; FOR line TO UPB year box DO year box[line,]:=" "* 2 UPB year box OD; FOR month row FROM 0 TO year rows-1 DO FOR month col FROM 0 TO year cols-1 DO INT month = month row * year cols + month col + 1; IF month > UPB month names THEN done ELSE INT month col width = month width+month gap; year box[ month row*month lines+1 : (month row+1)*month lines, month col*month col width+1 : (month col+1)*month col width-month gap ] := month repr(year, month) FI OD OD; done: year box );
INT center = (year cols*(month width+month gap) - month gap - 1) OVER 2; INT indent = (page width - year width) OVER 2;
printf(( $n(indent + center - 9)k g l$, "[Insert Snoopy here]", $n(indent + center - 1)k 4d l$, year, $l$, $n(indent)k n(year width)(g) l$, year repr(year) ))
);
main: ( CO inspired by http://www.ee.ryerson.ca/~elf/hack/realmen.html
Real Programmers Don't Use PASCAL - Ed Post Datamation, volume 29 number 7, July 1983 THE REAL PROGRAMMER'S NATURAL HABITAT
"Taped to the wall is a line-printer Snoopy calender for the year 1969." CO
INT mankind stepped on the moon = 1969, line printer width = 80; # as at 1969! # print calendar(mankind stepped on the moon, line printer width)
)</lang> Output:
[Insert Snoopy here] 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
AutoHotkey
<lang AutoHotkey>Calendar(Yr){ LastDay := [], Day := [] Titles = (ltrim ______January_________________February_________________March_______ _______April____________________May____________________June________ ________July___________________August_________________September_____ ______October_________________November________________December______ ) StringSplit, title, titles, `n Res := "________________________________" Yr "`r`n"
loop 4 { ; 4 Vertical Sections Day[1]:=Yr SubStr("0" A_Index*3 -2, -1) 01 Day[2]:=Yr SubStr("0" A_Index*3 -1, -1) 01 Day[3]:=Yr SubStr("0" A_Index*3 , -1) 01 Res .= "`r`n" title%A_Index% "`r`nSu Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa" loop , 6 { ; 6 Weeks max per month Week := A_Index, Res .= "`r`n" loop, 21 { ; 3 weeks times 7 days Mon := Ceil(A_Index/7), ThisWD := Mod(A_Index-1,7)+1 FormatTime, WD, % Day[Mon], WDay FormatTime, dd, % Day[Mon], dd if (WD>ThisWD) { Res .= "__ " continue } dd := ((Week>3) && dd <10) ? "__" : dd, Res .= dd " ", LastDay[Mon] := Day[Mon], Day[Mon] +=1, Days Res .= ((wd=7) && A_Index < 21) ? "___" : "" FormatTime, dd, % Day[Mon], dd } } Res .= "`r`n" } StringReplace, Res, Res,_,%A_Space%, all Res:=RegExReplace(Res,"`am)(^|\s)\K0", " ") return res }</lang> Examples:<lang AutoHotkey>Gui, font,s8, COURIER Gui, add, edit, vYr w40 r1 Limit4 Number, 1969 Gui, add, edit, vEdit2 w580 r38 Gui, Add, Button, Default Hidden gSubmit Gui, show
Submit: Gui, Submit, NoHide GuiControl,, Edit2, % Calendar(Yr) return
GuiEscape: GuiClose: ExitApp return</lang>
Outputs:
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
AutoIt
<lang AutoIt>
- include <Date.au3>
- Set the count of characters in each line, minimum is 20 - one month.
Global $iPrintSize = 132
- Set the count of months, you want to print side by side. With "0" it calculates automatically.
- The number will corrected, if it not allowed to print in an rectangle.
- If your print size is to small for given count, it will set back to automatically calculation.
Global $iSideBySide = 3
- Set the count of spaces between months.
Global $iSpace = 4
_CreateCalendar( 1969 )
Func _CreateCalendar($_iYear)
Local $aMon[12] = [' January ', ' February ', ' March ', _
' April ', ' May ', ' June ', _
' July ', ' August ', ' September ', _
' October ', ' November ', ' December ']
Local $sHead = 'Mo Tu We Th Fr Sa Su'
Local $aDaysInMonth[12] = [31,28,31,30,31,30,31,31,30,31,30,31]
If _DateIsLeapYear($_iYear) Then $aDaysInMonth[1] = 29
; == assign date in weekday table for the whole year Local $aAllDaysInMonth[6][7][12] ; [ lines ][ weekdays ][ months ] Local $iDay = 1, $iShift For $i = 1 To 12 $iShift = _DateToDayOfWeekISO($_iYear, $i, 1) -1 For $j = 0 To 5 For $k = $iShift To 6 $aAllDaysInMonth[$j][$k][$i-1] = $iDay $iDay += 1 If $iDay > $aDaysInMonth[$i-1] Then ExitLoop(2) Next $iShift = 0 Next $iDay = 1 Next
; == check given side by side count, calculate if needed If $iSideBySide > 0 Then If $iPrintSize < ($iSideBySide *(20 +$iSpace) -$iSpace) Then $iSideBySide = 0 EndIf Switch $iSideBySide Case 0 $iSideBySide = Int($iPrintSize /(20 +$iSpace)) If $iPrintSize < 20 Then Return _PrintLine('Escape: Size Error') If $iPrintSize < (20 +$iSpace) Then $iSideBySide = 1 Case 5 $iSideBySide = 4 Case 7 To 11 $iSideBySide = 6 EndSwitch
; == create space string Local $sSpace = For $i = 1 To $iSpace $sSpace &= ' ' Next
; == print header _PrintLine(@LF) _PrintLine('[ here is Snoopy ]', @LF) _PrintLine(StringRegExpReplace($_iYear, '(\d)(\d)(\d)(\d)', '$1 $2 $3 $4'), @LF)
; == create data for each line, in dependence to count of months in one line Local $sLine, $iRight, $sTmp1, $sTmp2 For $n = 0 To 12 /$iSideBySide -1 $sTmp1 = $sTmp2 = For $z = 0 To $iSideBySide -1 $sTmp1 &= $aMon[$iSideBySide *$n+$z] & $sSpace $sTmp2 &= $sHead & $sSpace Next _PrintLine(StringTrimRight($sTmp1, $iSpace)) _PrintLine(StringTrimRight($sTmp2, $iSpace)) For $j = 0 To 5 $sLine = For $i = 1 To $iSideBySide For $k = 0 To 6 $iRight = 3 If $k = 0 Then $iRight = 2 $sLine &= StringRight(' ' & $aAllDaysInMonth[$j][$k][$iSideBySide*$n+$i-1], $iRight) Next If $i < $iSideBySide Then $sLine &= $sSpace Next _PrintLine($sLine) Next Next EndFunc ;==>_CreateCalendar
Func _PrintLine($_sLine, $_sLF=) Local $iLen = StringLen($_sLine) Local $sSpace = , $sLeft = For $i = 1 To $iPrintSize-1 $sSpace &= ' ' Next If $iLen < $iPrintSize Then $sLeft = StringLeft($sSpace, Int(($iPrintSize-$iLen)/2)) ConsoleWrite($sLeft & $_sLine & $_sLF & @LF) EndFunc ;==>_PrintLine </lang> Output
[ here is Snoopy ] 1 9 6 9 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
--BugFix (talk) 00:40, 15 November 2013 (UTC)
AWK
<lang AWK>
Works with Gnu awk version 3.1.5 and with BusyBox v1.20.0.git awk To change the output width, change the value assigned to variable pagewide
- !/bin/gawk -f
BEGIN{
wkdays = "Su Mo Tu We Th Fr Sa" pagewide = 80 blank=" " for (i=1; i<pagewide; i++) blank = blank " " # month name accessed as substr(month,num*10,10) # where num is number of month, 1-12 month= " January February March April " month= month " May June July August " month= month " September October November December " # table of days per month accessed as substr(days,2*month,2) days =" 312831303130313130313031" line1 = "" line2 = "" line3 = "" line4 = "" line5 = "" line6 = "" line7 = "" line8 = ""
- print " year: " year " starts on: " dow(year)
}
function center(text, half) {
half = (pagewide - length(text))/2 return substr(blank,1,half) text substr(blank,1,half) }
function min(a,b) {
if (a < b) return a else return b }
function makewk (fst,lst,day, i,wstring ){
wstring="" for (i=1;i<day;i++) wstring=wstring " " for (i=fst;i<=lst;i++) wstring=wstring sprintf("%2d ",i) return substr(wstring " ",1,20) }
function dow (year, y){
y=year y= (y*365+int(y/4) - int(y/100) + int(y/400) +1) %7
- leap year adjustment
leap = 0 if (year % 4 == 0) leap = 1 if (year % 100 == 0) leap = 0 if (year % 400 == 0) leap = 1 y = y - leap if (y==-1) y=6 if (y==0) y=7 return (y) }
function prmonth (nmonth, newdow,monsize ){
line1 = line1 " " (substr(month,10*nmonth,10)) " " line2 = line2 (wkdays) " " line3 = line3 (makewk(1,8-newdow,newdow)) " " line4 = line4 (makewk(9-newdow,15-newdow,1)) " " line5 = line5 (makewk(16-newdow,22-newdow,1)) " " line6 = line6 (makewk(23-newdow,29-newdow,1)) " " line7 = line7 (makewk(30-newdow,min(monsize,36-newdow),1)) " " line8 = line8 (makewk(37-newdow,monsize,1)) " "
if (length(line3) + 22 > pagewide) {
print center(line1) print center(line2) print center(line3) print center(line4) print center(line5) print center(line6) print center(line7) print center(line8) line1 = "" line2 = "" line3 = "" line4 = "" line5 = "" line6 = "" line7 = "" line8 = "" }
} /q/{
exit }
{
monsize=substr(days,2*1,2) newdow=dow($1) print center("[ picture of Snoopy goes here ]") print center(sprintf("%d",$1) ) # January - December for (i=1; i<13; i++) { prmonth(i,newdow,monsize) newdow=(monsize+newdow) %7 if (newdow == 0) newdow = 7 monsize=substr(days,2+2*i,2) if (leap == 1 && monsize == 28) monsize = 29 } }
</lang> Output:
[ picture of Snoopy goes here ] 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
BBC BASIC
The day and month names are in the language for which the PC is configured. <lang bbcbasic> INSTALL @lib$+"DATELIB"
VDU 23,22,640;570;8,15,16,128 year% = 1969 PRINT TAB(38); year% DIM dom%(2), mjd%(2), dim%(2) FOR day% = 1 TO 7 days$ += LEFT$(FN_date$(FN_mjd(day%, 1, 1905), "ddd"), 2) + " " NEXT FOR month% = 1 TO 10 STEP 3 PRINT FOR col% = 0 TO 2 mjd%(col%) = FN_mjd(1, month% + col%, year%) month$ = FN_date$(mjd%(col%), "MMMM") PRINT TAB(col%*24 + 16 - LEN(month$)/2) month$; NEXT FOR col% = 0 TO 2 PRINT TAB(col%*24 + 6) days$; dim%(col%) = FN_dim(month% + col%, year%) NEXT dom%() = 1 col% = 0 REPEAT dow% = FN_dow(mjd%(col%)) IF dom%(col%)<=dim%(col%) THEN PRINT TAB(col%*24 + dow%*3 + 6); dom%(col%); dom%(col%) += 1 mjd%(col%) += 1 ENDIF IF dow%=6 OR dom%(col%)>dim%(col%) col% = (col% + 1) MOD 3 UNTIL dom%(0)>dim%(0) AND dom%(1)>dim%(1) AND dom%(2)>dim%(2) PRINT NEXT
</lang> Output:
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
C
With arbitrary display width (>= 20 though) and auto spacing. <lang C>#include <stdio.h>
- include <stdlib.h>
- include <string.h>
int width = 80, year = 1969; int cols, lead, gap;
const char *wdays[] = { "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa" }; struct months { const char *name; int days, start_wday, at; } months[12] = { { "January", 31, 0, 0 }, { "Februray", 28, 0, 0 }, { "March", 31, 0, 0 }, { "April", 30, 0, 0 }, { "May", 31, 0, 0 }, { "June", 30, 0, 0 }, { "July", 31, 0, 0 }, { "August", 31, 0, 0 }, { "September", 30, 0, 0 }, { "October", 31, 0, 0 }, { "November", 30, 0, 0 }, { "December", 31, 0, 0 } };
void space(int n) { while (n-- > 0) putchar(' '); }
void init_months() { int i;
if ((!(year % 4) && (year % 100)) || !(year % 400)) months[1].days = 29;
year--; months[0].start_wday = (year * 365 + year/4 - year/100 + year/400 + 1) % 7;
for (i = 1; i < 12; i++) months[i].start_wday = (months[i-1].start_wday + months[i-1].days) % 7;
cols = (width + 2) / 22; while (12 % cols) cols--; gap = cols - 1 ? (width - 20 * cols) / (cols - 1) : 0; if (gap > 4) gap = 4; lead = (width - (20 + gap) * cols + gap + 1) / 2;
year++;
}
void print_row(int row) { int c, i, from = row * cols, to = from + cols; space(lead); for (c = from; c < to; c++) { i = strlen(months[c].name); space((20 - i)/2); printf("%s", months[c].name); space(20 - i - (20 - i)/2 + ((c == to - 1) ? 0 : gap)); } putchar('\n');
space(lead); for (c = from; c < to; c++) { for (i = 0; i < 7; i++) printf("%s%s", wdays[i], i == 6 ? "" : " "); if (c < to - 1) space(gap); else putchar('\n'); }
while (1) { for (c = from; c < to; c++) if (months[c].at < months[c].days) break; if (c == to) break;
space(lead); for (c = from; c < to; c++) { for (i = 0; i < months[c].start_wday; i++) space(3); while(i++ < 7 && months[c].at < months[c].days) { printf("%2d", ++months[c].at); if (i < 7 || c < to - 1) putchar(' '); } while (i++ <= 7 && c < to - 1) space(3); if (c < to - 1) space(gap - 1); months[c].start_wday = 0; } putchar('\n'); } putchar('\n'); }
void print_year() { int row; char buf[32]; sprintf(buf, "%d", year); space((width - strlen(buf)) / 2); printf("%s\n\n", buf); for (row = 0; row * cols < 12; row++) print_row(row); }
int main(int c, char **v) { int i, year_set = 0; for (i = 1; i < c; i++) { if (!strcmp(v[i], "-w")) { if (++i == c || (width = atoi(v[i])) < 20) goto bail; } else if (!year_set) { if (!sscanf(v[i], "%d", &year) || year <= 0) year = 1969; year_set = 1; } else goto bail; }
init_months(); print_year(); return 0;
bail: fprintf(stderr, "bad args\nUsage: %s year [-w width (>= 20)]\n", v[0]); exit(1); }</lang>
C++
<lang cpp>
- include <windows.h>
- include <iostream>
//-------------------------------------------------------------------------------------------------- using namespace std;
//--------------------------------------------------------------------------------------------------
class calender
{
public:
void drawCalender( int y ) {
year = y; for( int i = 0; i < 12; i++ ) firstdays[i] = getfirstday( i );
isleapyear(); build();
}
private:
void isleapyear() {
isleap = false;
if( !( year % 4 ) ) { if( year % 100 ) isleap = true; else if( !( year % 400 ) ) isleap = true; }
}
int getfirstday( int m ) {
int y = year;
int f = y + 1 + 3 * m - 1; m++; if( m < 3 ) y--; else f -= int( .4 * m + 2.3 );
f += int( y / 4 ) - int( ( y / 100 + 1 ) * 0.75 ); f %= 7;
return f;
}
void build() {
int days[] = { 31, isleap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; int lc = 0, lco = 0, ystr = 7, start = 2, fd = 0, m = 0; HANDLE h = GetStdHandle( STD_OUTPUT_HANDLE ); COORD pos = { 0, ystr }; draw();
for( int i = 0; i < 4; i++ ) { for( int j = 0; j < 3; j++ ) { int d = firstdays[fd++], dm = days[m++]; pos.X = d * 3 + start; SetConsoleCursorPosition( h, pos );
for( int dd = 0; dd < dm; dd++ ) { if( dd < 9 ) cout << 0 << dd + 1 << " "; else cout << dd + 1 << " ";
pos.X += 3; if( pos.X - start > 20 ) { pos.X = start; pos.Y++; SetConsoleCursorPosition( h, pos ); } }
start += 23; pos.X = start; pos.Y = ystr; SetConsoleCursorPosition( h, pos ); } ystr += 9; start = 2; pos.Y = ystr; }
}
void draw() {
system( "cls" ); cout << "+--------------------------------------------------------------------+" << endl; cout << "| [SNOOPY] |" << endl; cout << "| |" << endl; cout << "| == " << year << " == |" << endl; cout << "+----------------------+----------------------+----------------------+" << endl; cout << "| JANUARY | FEBRUARY | MARCH |" << endl; cout << "| SU MO TU WE TH FR SA | SU MO TU WE TH FR SA | SU MO TU WE TH FR SA |" << endl; cout << "| | | |" << endl; cout << "| | | |" << endl; cout << "| | | |" << endl; cout << "| | | |" << endl; cout << "| | | |" << endl; cout << "| | | |" << endl; cout << "+----------------------+----------------------+----------------------+" << endl; cout << "| APRIL | MAY | JUNE |" << endl; cout << "| SU MO TU WE TH FR SA | SU MO TU WE TH FR SA | SU MO TU WE TH FR SA |" << endl; cout << "| | | |" << endl; cout << "| | | |" << endl; cout << "| | | |" << endl; cout << "| | | |" << endl; cout << "| | | |" << endl; cout << "| | | |" << endl; cout << "+----------------------+----------------------+----------------------+" << endl; cout << "| JULY | AUGUST | SEPTEMBER |" << endl; cout << "| SU MO TU WE TH FR SA | SU MO TU WE TH FR SA | SU MO TU WE TH FR SA |" << endl; cout << "| | | |" << endl; cout << "| | | |" << endl; cout << "| | | |" << endl; cout << "| | | |" << endl; cout << "| | | |" << endl; cout << "| | | |" << endl; cout << "+----------------------+----------------------+----------------------+" << endl; cout << "| OCTOBER | NOVEMBER | DECEMBER |" << endl; cout << "| SU MO TU WE TH FR SA | SU MO TU WE TH FR SA | SU MO TU WE TH FR SA |" << endl; cout << "| | | |" << endl; cout << "| | | |" << endl; cout << "| | | |" << endl; cout << "| | | |" << endl; cout << "| | | |" << endl; cout << "| | | |" << endl; cout << "+----------------------+----------------------+----------------------+" << endl;
}
int firstdays[12], year; bool isleap;
}; //-------------------------------------------------------------------------------------------------- int main( int argc, char* argv[] ) {
int y; calender cal;
while( true ) {
system( "cls" ); cout << "Enter the year( yyyy ) --- ( 0 to quit ): "; cin >> y; if( !y ) return 0;
cal.drawCalender( y ); cout << endl << endl << endl << endl << endl << endl << endl << endl;
system( "pause" );
} return 0;
} //-------------------------------------------------------------------------------------------------- </lang> Output:
+--------------------------------------------------------------------+ | [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 | | 01 02 03 04 | 01 | 01 | | 05 06 07 08 09 10 11 | 02 03 04 05 06 07 08 | 02 03 04 05 06 07 08 | | 12 13 14 15 16 17 18 | 09 10 11 12 13 14 15 | 09 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 | | 01 02 03 04 05 | 01 02 03 | 01 02 03 04 05 06 07 | | 06 07 08 09 10 11 12 | 04 05 06 07 08 09 10 | 08 09 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 | | 01 02 03 04 05 | 01 02 | 01 02 03 04 05 06 | | 06 07 08 09 10 11 12 | 03 04 05 06 07 08 09 | 07 08 09 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 | | 01 02 03 04 | 01 | 01 02 03 04 05 06 | | 05 06 07 08 09 10 11 | 02 03 04 05 06 07 08 | 07 08 09 10 11 12 13 | | 12 13 14 15 16 17 18 | 09 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 | | +----------------------+----------------------+----------------------+
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.
<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), ' ')); } }
}
</lang>
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. <lang COBOL>
IDENTIFICATION DIVISION. PROGRAM-ID. CALEND. ENVIRONMENT DIVISION. INPUT-OUTPUT SECTION. DATA DIVISION. WORKING-STORAGE SECTION. 01 WS-DAY-NAMES-DEF. 03 FILLER PIC X(09) VALUE 'SUNDAY '. 03 FILLER PIC X(09) VALUE 'MONDAY '. 03 FILLER PIC X(09) VALUE 'TUESDAY '. 03 FILLER PIC X(09) VALUE 'WEDNESDAY'. 03 FILLER PIC X(09) VALUE 'THURSDAY '. 03 FILLER PIC X(09) VALUE 'FRIDAY '. 03 FILLER PIC X(09) VALUE 'SATURDAY '. 01 FILLER REDEFINES WS-DAY-NAMES-DEF. 03 WS-DAY-NAME PIC X(09) OCCURS 07 TIMES. 01 WS-MTH-INFO-DEF. 03 FILLER PIC X(11) VALUE 'JANUARY 31'. 03 FILLER PIC X(11) VALUE 'FEBRUARY 28'. 03 FILLER PIC X(11) VALUE 'MARCH 31'. 03 FILLER PIC X(11) VALUE 'APRIL 30'. 03 FILLER PIC X(11) VALUE 'MAY 31'. 03 FILLER PIC X(11) VALUE 'JUNE 30'. 03 FILLER PIC X(11) VALUE 'JULY 31'. 03 FILLER PIC X(11) VALUE 'AUGUST 31'. 03 FILLER PIC X(11) VALUE 'SEPTEMBER30'. 03 FILLER PIC X(11) VALUE 'OCTOBER 31'. 03 FILLER PIC X(11) VALUE 'NOVEMBER 30'. 03 FILLER PIC X(11) VALUE 'DECEMBER 31'. 01 FILLER REDEFINES WS-MTH-INFO-DEF. 03 WS-MTH-INFO-TABLE OCCURS 12 TIMES. 05 WS-MTH-INFO-NAME PIC X(09). 05 WS-MTH-INFO-DAYS PIC 9(02).
01 WS-MTH-AREA. 03 WS-MTH-DD PIC S99. 03 WS-DAY1 PIC 9. 03 WS-DAYS PIC 99. 03 WS-DD PIC 9. 03 WS-WK PIC 9. 03 WS-MM PIC 99. 03 WS-QQ PIC 99. 03 WS-MTH-MONTH OCCURS 12 TIMES. 05 WS-MTH-WEEK OCCURS 6 TIMES. 07 WS-DAY-FLD OCCURS 7 TIMES. 09 WS-DAY PIC ZZ. 01 INPDATE-RECORD. 05 INPD-YEAR PIC 9(04). 05 FILLER PIC X(01). 05 INPD-MONTH PIC 9(02). 05 FILLER PIC X(01). 05 INPD-DAY PIC 9(02). 01 WMS-DOW PIC 9(01). 01 WS-PRT PIC X(132). 01 WS-COL PIC 9(03) VALUE 0. 01 WS-PP PIC 9(03) VALUE 0. 01 WS-CFGN. 03 FILLER PIC 9(03) VALUE 80. 03 FILLER PIC 9(02) VALUE 5. 03 FILLER PIC 9(01) VALUE 1. 03 FILLER PIC 9(02) VALUE 5. 03 FILLER PIC 9(01) VALUE 2. 01 WS-CFGW. 03 FILLER PIC 9(03) VALUE 120. 03 FILLER PIC 9(02) VALUE 10. 03 FILLER PIC 9(01) VALUE 2. 03 FILLER PIC 9(02) VALUE 10. 03 FILLER PIC 9(01) VALUE 3. 01 WS-CFG. 03 WS-LS PIC 9(03) VALUE 120. 03 WS-LMAR PIC 9(02) VALUE 10. 03 WS-SPBD PIC 9(01) VALUE 2. 03 WS-SPBC PIC 9(02) VALUE 10. 03 WS-DNMW PIC 9(01) VALUE 3. PROCEDURE DIVISION. MOVE '1969-01-01' TO INPDATE-RECORD MOVE WS-CFGN TO WS-CFG IF (FUNCTION MOD ( INPD-YEAR , 400 ) = 0 OR (FUNCTION MOD ( INPD-YEAR , 4 ) = 0 AND FUNCTION MOD ( INPD-YEAR , 100 ) NOT = 0)) MOVE 29 TO WS-MTH-INFO-DAYS (02) ELSE MOVE 28 TO WS-MTH-INFO-DAYS (02) END-IF PERFORM VARYING WS-MM FROM 1 BY +1 UNTIL WS-MM > 12 MOVE WS-MM TO INPD-MONTH CALL 'DATE2DOW' USING INPDATE-RECORD, WMS-DOW COMPUTE WS-MTH-DD = 1 - WMS-DOW COMPUTE WS-DAYS = WS-MTH-INFO-DAYS (INPD-MONTH) PERFORM VARYING WS-WK FROM 1 BY +1 UNTIL WS-WK > 6 PERFORM VARYING WS-DD FROM 1 BY +1 UNTIL WS-DD > 7 COMPUTE WS-MTH-DD = WS-MTH-DD + 1 IF (WS-MTH-DD < 1) OR (WS-MTH-DD > WS-DAYS) MOVE 0 TO WS-DAY (WS-MM, WS-WK, WS-DD) ELSE MOVE WS-MTH-DD TO WS-DAY (WS-MM, WS-WK, WS-DD) END-IF END-PERFORM END-PERFORM END-PERFORM COMPUTE WS-MM = 0 PERFORM VARYING WS-QQ FROM 1 BY +1 UNTIL WS-QQ > 4 INITIALIZE WS-PRT COMPUTE WS-PP = 1 PERFORM VARYING WS-COL FROM 1 BY +1 UNTIL WS-COL > 3 COMPUTE WS-MM = 3 * (WS-QQ - 1) + WS-COL IF WS-COL = 1 COMPUTE WS-PP = WS-PP + WS-LMAR + 2 - WS-DNMW ELSE COMPUTE WS-PP = WS-PP + WS-SPBC + 2 - WS-DNMW END-IF MOVE WS-MTH-INFO-NAME (WS-MM) TO WS-PRT(WS-PP:9) COMPUTE WS-PP = WS-PP + ( 2 * 7 + WS-SPBD * 6 + WS-SPBD - 1) - 4 MOVE INPD-YEAR TO WS-PRT (WS-PP:4) COMPUTE WS-PP = WS-PP + 4 END-PERFORM DISPLAY WS-PRT (1:WS-LS) INITIALIZE WS-PRT COMPUTE WS-PP = 1 PERFORM VARYING WS-COL FROM 1 BY +1 UNTIL WS-COL > 3 COMPUTE WS-MM = 3 * (WS-QQ - 1) + WS-COL IF WS-COL = 1 COMPUTE WS-PP = WS-PP + WS-LMAR + 2 - WS-DNMW ELSE COMPUTE WS-PP = WS-PP + WS-SPBC + 2 - WS-DNMW END-IF PERFORM VARYING WS-DD FROM 1 BY +1 UNTIL WS-DD > 7 IF WS-DD > 1 COMPUTE WS-PP = WS-PP + WS-SPBD + 2 - WS-DNMW END-IF MOVE WS-DAY-NAME (WS-DD) (1:WS-DNMW) TO WS-PRT (WS-PP:WS-DNMW) COMPUTE WS-PP = WS-PP + WS-DNMW END-PERFORM END-PERFORM DISPLAY WS-PRT (1:WS-LS) PERFORM VARYING WS-WK FROM 1 BY +1 UNTIL WS-WK > 6 INITIALIZE WS-PRT COMPUTE WS-PP = 1 PERFORM VARYING WS-COL FROM 1 BY +1 UNTIL WS-COL > 3 COMPUTE WS-MM = 3 * (WS-QQ - 1) + WS-COL IF WS-COL = 1 COMPUTE WS-PP = WS-PP + WS-LMAR ELSE COMPUTE WS-PP = WS-PP + WS-SPBC END-IF PERFORM VARYING WS-DD FROM 1 BY +1 UNTIL WS-DD > 7 IF WS-DD > 1 COMPUTE WS-PP = WS-PP + WS-SPBD END-IF MOVE WS-DAY (WS-MM, WS-WK, WS-DD) TO WS-PRT (WS-PP:2) COMPUTE WS-PP = WS-PP + 2 END-PERFORM END-PERFORM DISPLAY WS-PRT (1:WS-LS) END-PERFORM DISPLAY ' ' END-PERFORM GOBACK . END PROGRAM CALEND. IDENTIFICATION DIVISION. PROGRAM-ID. DATE2DOW. ENVIRONMENT DIVISION. DATA DIVISION. WORKING-STORAGE SECTION. 01 WMS-WORK-AREA. 03 WMS-YEAR PIC 9(04). 03 WMS-MONTH PIC 9(02). 03 WMS-CSYS PIC 9(01) VALUE 1. 03 WMS-SUM pic 9(04). LINKAGE SECTION. 01 INPDATE-RECORD. 05 INPD-YEAR PIC 9(04). 05 FILLER PIC X(01). 05 INPD-MONTH PIC 9(02). 05 FILLER PIC X(01). 05 INPD-DAY PIC 9(02). 01 WMS-DOW PIC 9(01). PROCEDURE DIVISION USING INPDATE-RECORD, WMS-DOW. 1010-CONVERT-DATE-TO-DOW. IF INPD-MONTH < 3 COMPUTE WMS-MONTH = INPD-MONTH + 12 COMPUTE WMS-YEAR = INPD-YEAR - 1 ELSE COMPUTE WMS-MONTH = INPD-MONTH COMPUTE WMS-YEAR = INPD-YEAR END-IF COMPUTE WMS-SUM = ( INPD-DAY + 2 * WMS-MONTH + WMS-YEAR + FUNCTION INTEGER (6 * (WMS-MONTH + 1) / 10) + FUNCTION INTEGER ( WMS-YEAR / 4 ) - FUNCTION INTEGER ( WMS-YEAR / 100 ) + FUNCTION INTEGER ( WMS-YEAR / 400 ) + WMS-CSYS ) COMPUTE WMS-DOW = FUNCTION MOD (WMS-SUM, 7) + 1 GOBACK . END PROGRAM DATE2DOW.
</lang> Output (based on 80 character wide display)
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
D
<lang d>import std.stdio, std.datetime, std.string, std.conv;
void printCalendar(in uint year, in uint nCols) in {
assert(nCols > 0 && nCols <= 12);
} body {
immutable rows = 12 / nCols + (12 % nCols != 0); auto date = Date(year, 1, 1); auto offs = cast(int)date.dayOfWeek; const months = "January February March April May June July August September October November December".split;
string[8][12] mons; foreach (immutable m; 0 .. 12) { mons[m][0] = months[m].center(21); mons[m][1] = " Su Mo Tu We Th Fr Sa"; immutable dim = date.daysInMonth; foreach (immutable d; 1 .. 43) { immutable day = d > offs && d <= offs + dim; immutable str = day ? format(" %2s", d-offs) : " "; mons[m][2 + (d - 1) / 7] ~= str; } offs = (offs + dim) % 7; date.add!"months"(1); }
"[Snoopy Picture]".center(nCols * 24 + 4).writeln; writeln(year.text.center(nCols * 24 + 4), "\n"); foreach (immutable r; 0 .. rows) { string[8] s; foreach (immutable c; 0 .. nCols) { if (r * nCols + c > 11) break; foreach (immutable i, line; mons[r * nCols + c]) s[i] ~= format(" %s", line); } writefln("%-(%s\n%)\n", s); }
}
void main() {
printCalendar(1969, 3);
}</lang>
[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 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
Icon and 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. <lang Icon>procedure main(A) printCalendar(\A[1]|1969) end
procedure printCalendar(year) #: Print a 3 column x 80 char calendar
cols := 3 # fixed width mons := [] # table of months "January February March April May June " || "July August September October November December " ? while put(mons, tab(find(" "))) do move(1)
write(center("[Snoopy Picture]",cols * 24 + 4)) # mandatory .. write(center(year,cols * 24 + 4), "\n") # ... headers M := list(cols) # coexpr container every mon := 0 to 9 by cols do { # go through months by cols writes(" ") every i := 1 to cols do { writes(center(mons[mon+i],24)) # header months M[i] := create CalendarFormatWeek(1969,mon + i) # formatting coexpr } write() every 1 to 7 do { # 1 to max rows every c := 1 to cols do { # for each column writes(" ") every 1 to 7 do writes(right(@M[c],3)) # each row day element } write() } }
end
link datetime
procedure CalendarFormatWeek(year,m) #: Format Week for Calendar static D initial D := [31,28,31,30,31,30,31,31,30,31,30,31]
every suspend "Su"|"Mo"|"Tu"|"We"|"Th"|"Fr"|"Sa" # header every 1 to (d := (julian(m,1,year)+1)%7) do suspend "" # lead day alignment every suspend 1 to D[m] do d +:= 1 # days if m = 2 & IsLeapYear(year) then suspend (d +:= 1, 29) # LY adjustment every d to (6*7) do suspend "" # trailer alignment end</lang>
datetime.icn provides julian and IsLeapYear
Output:
[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 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
J
Solution: <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</lang> Example use: <lang j> 80 formatCalendar 1969
[Insert Snoopy here] 1969 Jan │ Feb │ Mar 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
─────────────────────┼─────────────────────┼─────────────────────
Apr │ May │ Jun 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 │ │
─────────────────────┼─────────────────────┼─────────────────────
Jul │ Aug │ Sep 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 │
─────────────────────┼─────────────────────┼─────────────────────
Oct │ Nov │ Dec 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 │ </lang>
Mathematica
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.
<lang Mathematica> Needs["Calendar`"]; </lang>
Monthly calendar takes a year and a month and returns a simply formatted calendar for that month. It knows about leap years.
<lang Mathematica> 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},
d1 = DayOfWeek[{y, m, 1}];
daysInMonth[year_, month_] := DaysBetween[{year, month, 1}, {If[month == 12, year + 1, year], If[month == 12, 1, month + 1], 1}];
shortDays = (StringTake[ToString[#], 3] & /@ days);
offset = d1 /. Thread[days -> Range[0, 6]];
Grid[ Prepend[ Prepend[ Partition[ PadRight[PadLeft[Range[daysInMonth[y, m]], daysInMonth[y, m] + offset, ""], 36, "" ], 7], shortDays], {monthsm, SpanFromLeft}]]]
</lang>
yearlyCalendar prints out calendars for each of the 12 months in the year.
<lang Mathematica>
yearlyCalendar[y_] := Grid[Partition[Table[monthlyCalendar[y, k], {k, 12}], 3], Spacings -> {4, 2}];
</lang>
Perl
<lang perl>#!/usr/bin/perl use strict; use warnings; use Time::Local;
my @names = qw/ JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC/;
my $year = shift ||'2007';
for my $month (0..11) {
print " $names[$month] $year\n"; print calendar($year, $month), "\n\n";
}
sub calendar {
my ($year, $month) = @_; my @mon_days = qw/31 28 31 30 31 30 31 31 30 31 30 31/; ++$mon_days[1] if $year % 4 == 0 && ($year % 400 == 0 || $year % 1
+00 != 0);
my $cal = " Sun Mon Tue Wed Thu Fri Sat\n";
# 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;
while ($mday <= $mon_days[$month]) { $cal .= sprintf "%4s", $mday++; $cal .= "\n" if ($wday + $mday -1) % 7 == 0; } return $cal;
}
- Let's use this as a placeholder until a better solution arrives, OK?</lang>
Perl 6
<lang perl6>my $months-per-col = 3; my @week-day-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); exit;
sub fmt-year ($year) {
my $str = (' ' x 30) ~ $year ~ "\n";
my @month-strs; @month-strs[$_] = fmt-month($year, $_).lines for 1 .. 12;
loop ( my $month = 1; $month <= 12; $month += $months-per-col ) { 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;
$str ~= (" " xx $week-day-1).join(" ");
for $date.day .. $date.days-in-month -> $day {
$date = DateTime.new(year => $year, month => $month, day => $day);
$str ~= " " if 1 < $week-day < 8; if $week-day == 8 { $str ~= "\n"; $week-day = 1; } $str ~= sprintf "%2d", $day;
$week-day++; } $str ~= " " if $week-day < 8; $str ~= (" " xx 8-$week-day).join(" "); $str ~= "\n"; return $str;
} </lang>
PicoLisp
This "calendar" is nicely formatted, and fits into 20 columns ;-) <lang PicoLisp>(de cal (Year)
(prinl "====== " Year " ======") (for Dat (range (date Year 1 1) (date Year 12 31)) (let D (date Dat) (tab (3 3 4 8) (when (= 1 (caddr D)) (get *Mon (cadr D)) ) (caddr D) (day Dat *Day) (when (=0 (% (inc Dat) 7)) (pack "Week " (week Dat)) ) ) ) ) )
(cal 1969)</lang> Output:
====== 1969 ====== Jan 1 Wed 2 Thu 3 Fri 4 Sat 5 Sun 6 Mon Week 2 7 Tue .... 28 Sat 29 Sun 30 Mon Week 27 Jul 1 Tue 2 Wed 3 Thu 4 Fri .... 25 Thu 26 Fri 27 Sat 28 Sun 29 Mon Week 53 30 Tue 31 Wed
Pike
the Calendar in Pike does not handle the transitions from the Julian to the Gregorian calendar, but it handles those separately. the default calendar is ISO, other options are Gregorian, Julian, Bahai, Coptic, Islamic and Discordian.
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.
<lang Pike>#!/bin/env pike
int main(int argc, array(string) argv) {
object cal = Calendar; object year; string region = "us";
array date = argv[1..]; if (sizeof(date) && objectp(Calendar[date[0]]) && Calendar[date[0]]->Day) { cal = Calendar[date[0]]; date = Array.shift(date)[1]; }
if (sizeof(date) && (int)date[0]) { year = cal.Year((int)date[0]); date = Array.shift(date)[1]; }
if (sizeof(date)) region = date[0];
if (!year) year = cal.Year();
print_year(year, region);
}
array make_month(object month, int field_width, void|string region) {
array out =({}); mapping holidays = ([]); object today = Calendar.Day();
if (region) holidays = Calendar.Events.find_region(region)->scan_events(month);
array weekday_names = sprintf("%*.*s", field_width, field_width, month->week()->days()->week_day_shortname()[*]);
out += ({ ({ month->month_name(), month->month_no(), month->year_name() }) }); out += ({ weekday_names }); out += showday(month->weeks()->days()[*][*], month, today, holidays, field_width);
out += ({ ({ " "*field_width })*sizeof(weekday_names) });
return out;
}
string print_month(object _month, void|int field_width, void|string region) {
if (!field_width) field_width = 2; array month = make_month(_month, field_width, region); string out = "";
out += sprintf("%|*s\n", (field_width+1)*sizeof(month[1])-1, sprintf("%s", month[0][0])); out += sprintf((month[1..][*]*" ")*"\n"); return out;
}
string print_year(object year, void|string region) {
array output = ({}); int day_width = 2; int columns = Stdio.stdout.tcgetattr()->columns; int month_width = sizeof(make_month(year->month(), day_width)[1]) * (day_width+1) - 1; if (columns < month_width) columns = month_width;
// try to find an optimal good looking solution to spread the months // across the terminal width // for the common calendar of 12 months this is easy but we need to // account for caledars that have more than 12 months float max_width = (float)((columns+2)/(month_width+2)); float max_height = ceil(year->number_of_months()/max_width); float w = max_width; while(ceil(year->number_of_months()/(w-1)) == max_height) w--; foreach(print_month(year->months()[*], day_width, region)/w;; array row) { array rows = row[*]/"\n"; int l = max(@sizeof(rows[*])); foreach(rows; int i;) { // the last line of each month is an empty line. // repeat the line as many times as needed to make the months equally long rows[i]+=({ rows[i][-1] })*(l-sizeof(rows[i])); } rows = Array.transpose(rows); output += rows[*]*" "; } write("%*|s\n", sizeof(output[1]), year->format_nice()); write(output * "\n"); write("\n");
}
string showday(object day, object month, object today, mapping holidays, int field_width) {
string dayname; if (day->month() == month) { dayname = (string)day->month_day(); dayname = " "*(sizeof((string)month->number_of_days())-sizeof(dayname))+dayname; if (day == today) dayname = sprintf("%|*.*s", field_width, field_width, dayname); else dayname = sprintf("%|*.*s", field_width, field_width, dayname); if (holidays[day]) dayname = sprintf("%|s", dayname); } else dayname = " "*field_width; return dayname;
} </lang> Output: (holidays lost in copy-paste)
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
PL/I
<lang PL/I> calendar: procedure (year) options (main);
declare year character (4) varying; declare (a, b, c) (0:5,0:6) character (3); declare name_month(12) static character (9) varying initial ( 'JANUARY', 'FEBRUARY', 'MARCH', 'APRIL', 'MAY', 'JUNE', 'JULY', 'AUGUST', 'SEPTEMBER', 'OCTOBER', 'NOVEMBER', 'DECEMBER'); declare i fixed; declare (mm, mmp1, mmp2) pic '99';
put edit (center('CALENDAR FOR ' || YEAR, 67)) (a); put skip (2);
do mm = 1 to 12 by 3; mmp1 = mm + 1; mmp2 = mm + 2; call prepare_month('01' || mm || YEAR, a); call prepare_month('01' || mmp1 || YEAR, b); call prepare_month('01' || mmp2 || YEAR, c);
put skip edit (center(name_month(mm), 23), center(name_month(mmp1), 23), center(name_month(mmp2), 23) ) (a); put skip edit ((3)' M T W T F S S ') (a); do i = 0 to 5; put skip edit (a(i,*), b(i,*), c(i,*)) (7 a, x(2)); end; end;
prepare_month: procedure (start, month);
declare month(0:5,0:6) character (3); declare start character (8); declare i pic 'ZZ9'; declare offset fixed; declare (j, day) fixed binary (31); declare (this_month, next_month, k) fixed binary;
day = days(start, 'DDMMYYYY'); offset = weekday(day) - 1; if offset = 0 then offset = 7; month = ; do j = day by 1; this_month = substr(daystodate(j, 'DDMMYYYY'), 3, 2); next_month = substr(daystodate(j+1, 'DDMMYYYY'), 3, 2); if this_month^= next_month then leave; end; i = 1; do k = offset-1 to offset+j-day-1; month(k/7, mod(k,7)) = i; i = i + 1; end;
end prepare_month;
end calendar; </lang> Output:
CALENDAR FOR 1969 JANUARY FEBRUARY MARCH M T W T F S S M T W T F S S M T W T F S S 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 M T W T F S S M T W T F S S M T W T F S S 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 M T W T F S S M T W T F S S M T W T F S S 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 M T W T F S S M T W T F S S M T W T F S S 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
Extract for 2013:
CALENDAR FOR 2013 JANUARY FEBRUARY MARCH M T W T F S S M T W T F S S M T W T F S S 1 2 3 4 5 6 1 2 3 1 2 3 7 8 9 10 11 12 13 4 5 6 7 8 9 10 4 5 6 7 8 9 10 14 15 16 17 18 19 20 11 12 13 14 15 16 17 11 12 13 14 15 16 17 21 22 23 24 25 26 27 18 19 20 21 22 23 24 18 19 20 21 22 23 24 28 29 30 31 25 26 27 28 25 26 27 28 29 30 31
Python
The Python calendar.pryear 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.
Although rumoured to be getting an anti-gravity module, Python as yet does not include a snoopy module ;-) <lang python>>>> import calendar >>> help(calendar.prcal) Help on method pryear in module calendar:
pryear(self, theyear, w=0, l=0, c=6, m=3) method of calendar.TextCalendar instance
Print a years calendar.
>>> calendar.prcal(1969)
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
>>> print('1234567890'*8) 12345678901234567890123456789012345678901234567890123456789012345678901234567890 >>> </lang>
Racket
<lang racket>
- lang racket
(require racket/date) (define (calendar yr)
(define (nsplit n l) (if (null? l) l (cons (take l n) (nsplit n (drop l n))))) (define months (for/list ([mn (in-naturals 1)] [mname '(January February March April May June July August September October November December)]) (define s (find-seconds 0 0 12 1 mn yr)) (define pfx (date-week-day (seconds->date s))) (define days (let ([? (if (= mn 12) (λ(x y) y) (λ(x y) x))]) (round (/ (- (find-seconds 0 0 12 1 (? (+ 1 mn) 1) (? yr (+ 1 yr))) s) 60 60 24)))) (list* (~a mname #:width 20 #:align 'center) "Su Mo Tu We Th Fr Sa" (map string-join (nsplit 7 `(,@(make-list pfx " ") ,@(for/list ([d days]) (~a (+ d 1) #:width 2 #:align 'right)) ,@(make-list (- 42 pfx days) " "))))))) (let* ([s '(" 11,-~4-._3. 41-4! 10/ ()=(2) 3\\ 40~a! 9( 3( 80 39-4! 10\\._\\" ", ,-4'! 5#2X3x7! 12/ 2-3'~2;! 11/ 4/~2|-! 9=( 3~4 2|! 3/~42\\! " "2/_23\\! /_25\\!/_27\\! 3|_20|! 3|_20|! 3|_20|! 3| 20|!!")] [s (regexp-replace* #rx"!" (string-append* s) "\n")] [s (regexp-replace* #rx".(?:[1-7][0-9]*|[1-9])" s (λ(m) (make-string (string->number (substring m 1)) (string-ref m 0))))]) (printf s yr)) (for-each displayln (dropf-right (for*/list ([3ms (nsplit 3 months)] [s (apply map list 3ms)]) (regexp-replace #rx" +$" (string-join s " ") "")) (λ(s) (equal? "" s)))))
(calendar 1969) </lang>
REXX
Rather than build a program from scratch, I took my generalized REXX program that generated (as an
option) any calendar for any month, and by extension, any number of months (so that an entire
year could be displayed/written). To make the program much smaller, a LOT of code was removed
(but it's still a sledgehammer doing the work of a small hammer).
Some of the code removed:
- almost all error checking and the issuing of error messages.
- the option of using "simple" characters as opposed to a true grid (of ASCII extended characters).
- the option of highlighting of today's date.
- the option of using colors.
- the specifying of what language to use (over 90 languages, default is English).
- the option of using indentation.
- the option of using different date formats (to specify the date).
- the option of using a time addition/subtraction for the date (* -4score-7years).
- the option of showing the phases of the moon.
- the option of showing the day-of-the-year (as on financial calendars and others).
- the option of specifying a calendar fill character (those empty cells in a monthly calender).
- the option of drawing Snoopy (three versions) and also many other animals/ASCII art.
- the specifing of alternate outputs (a file/printer/XEDIT/stack/GLOBALVs/etc).
- the option of displaying the year in blocked form (at the top of the calendar):
11 9999999 6666666 9999999 111 999999999 666666666 999999999 1111 99 99 66 66 99 99 11 99 99 66 99 99 11 99 999 66 99 999 11 999999999 66 666666 999999999 11 99999 99 6666666666 99999 99 11 99 666 66 99 11 99 66 66 99 11 99 99 66 66 99 99 111111 99999999 66666666 99999999 111111 999999 666666 999999
Most of the code is dealing with drawing a cell (grid) for each day-of-the-month, so the program
is a bit more complex than it has to be for this task. Also, it was designed for any year, any
month(s), and any size screen/device to show (display) it. Accommodations were made in the program
to allow the choice of what type of cells would be generated: small/smaller/smallest for height, and
narrow/narrower/narrowest for the width. The size (width/depth) of the output device/terminal can be
specified. The choice could've been performed programmatically, but I never believe that a program
could best choose over what the user wants, as it depends on esthetics and looks (fashion).
<lang rexx>/*REXX program to show any year's (monthly) calendar (with/without grid)*/
@abc='abcdefghijklmnopqrstuvwxyz'; @abcU=@abc; upper @abcU calfill=' '; mc=12; _='1 3 1234567890' "fb"x parse var _ grid calspaces # chk . cv_ days.1 days.2 days.3 daysn sd sw _=0; parse var _ cols 1 jd 1 lowerCase 1 maxKalPuts 1 narrow 1,
narrower 1 narrowest 1 short 1 shorter 1 shortest 1, small 1 smaller 1 smallest 1 upperCase
parse arg mm '/' dd "/" yyyy _ '(' ops; uops=ops if _\== | \is#(mm) | \is#(dd) | \is#(yyyy) then call erx 86
do while ops\==; ops=strip(ops,'L'); parse var ops _1 2 1 _ . 1 _o ops upper _ select when abb('CALSPaces') then calspaces=nai() when abb('DEPth') then sd=nai() when abbn('GRIDs') then grid=no() when abbn('LOWercase') then lowerCase=no() when abb('CALMONths') then mc=nai() when abbn('NARrow') then narrow=no() when abbn('NARROWER') then narrower=no() when abbn('NARROWESt') then narrowest=no() when abbn('SHORt') then short=no() when abbn('SHORTER') then shorter=no() when abbn('SHORTESt') then shortest=no() when abbn('SMALl') then small=no() when abbn('SMALLER') then smaller=no() when abbn('SMALLESt') then smallest=no() when abbn('UPPercase') then upperCase=no() when abb('WIDth') then sw=nai() otherwise nop end /*select*/ end /*do while opts\== ...*/
mc=int(mc,'monthscalender'); if mc>0 then cal=1 days='Sunday Monday Tuesday Wednesday Thursday Friday Saturday' months='January February March April May June July August September October November December' days=' 'days; months=' 'months cyyyy=right(date(),4); hyy=left(cyyyy,2); lyy=right(cyyyy,2) dy.=31; _=30; parse var _ dy.4 1 dy.6 1 dy.9 1 dy.11; dy.2=28+ly(yyyy) yy=right(yyyy,2); sd=p(sd 43); sw=p(sw 80); cw=10; cindent=1; calwidth=76 if small then do; narrow=1 ; short=1 ; end if smaller then do; narrower=1 ; shorter=1 ; end if smallest then do; narrowest=1; shortest=1; end if shortest then shorter=1 if shorter then short =1 if narrow then do; cw=9; cindent=3; calwidth=69; end if narrower then do; cw=4; cindent=1; calwidth=34; end if narrowest then do; cw=2; cindent=1; calwidth=20; end cv_=calwidth+calspaces+2 calfill=left(copies(calfill,cw),cw)
do j=1 for 7; _=word(days,j) do jw=1 for 3; _d=strip(substr(_,cw*jw-cw+1,cw)) if jw=1 then _d=centre(_d,cw+1) else _d=left(_d,cw+1) days.jw=days.jw||_d end /*jw*/ __=daysn if narrower then daysn=__||centre(left(_,3),5) if narrowest then daysn=__||center(left(_,2),3) end /*j*/
_yyyy=yyyy; calPuts=0; cv=1; _mm=mm+0; month=word(months,mm) dy.2=28+ly(_yyyy); dim=dy._mm; _dd=01; dow=dow(_mm,_dd,_yyyy); $dd=dd+0
/*─────────────────────────────now: the business of the building the cal*/ call calGen
do _j=2 to mc if cv_\== then do cv=cv+cv_ if cv+cv_>=sw then do; cv=1; call calPut call fcalPuts;call calPb end else calPuts=0 end else do;call calPb;call calPut;call fcalPuts;end _mm=_mm+1; if _mm==13 then do; _mm=1; _yyyy=_yyyy+1; end month=word(months,_mm); dy.2=28+ly(_yyyy); dim=dy._mm dow=dow(_mm,_dd,_yyyy); $dd=0; call calGen end /*_j*/
call fcalPuts return _
/*─────────────────────────────calGen subroutine────────────────────────*/ calGen: cellX=;cellJ=;cellM=;calCells=0;calline=0 call calPut call calPutl copies('─',calwidth),"┌┐"; call calHd call calPutl month ' ' _yyyy ; call calHd if narrowest | narrower then call calPutl daysn
else do jw=1 for 3 if space(days.jw)\== then call calPutl days.jw end
calft=1; calfb=0
do jf=1 for dow-1; call cellDraw calFill,calFill; end do jy=1 for dim; call cellDraw jy; end
calfb=1
do 7; call cellDraw calFill,calFill; end
if sd>32 & \shorter then call calPut return
/*─────────────────────────────cellDraw subroutine──────────────────────*/ cellDraw: parse arg zz,cdDOY;zz=right(zz,2);calCells=calCells+1 if calCells>7 then do
calLine=calLine+1 cellX=substr(cellX,2) cellJ=substr(cellJ,2) cellM=substr(cellM,2) cellB=translate(cellX,,")(─-"#) if calLine==1 then call cx call calCsm; call calPutl cellX; call calCsj; call cx cellX=; cellJ=; cellM=; calCells=1 end
cdDOY=right(cdDOY,cw); cellM=cellM'│'center(,cw) cellX=cellX'│'centre(zz,cw); cellJ=cellJ'│'center(,cw) return
/*═════════════════════════════general 1-line subs══════════════════════*/ abb:arg abbu;parse arg abb;return abbrev(abbu,_,abbl(abb)) abbl:return verify(arg(1)'a',@abc,'M')-1 abbn:parse arg abbn;return abb(abbn)|abb('NO'abbn) calCsj:if sd>49&\shorter then call calPutl cellB;if sd>24&\short then call calPutl cellJ; return calCsm:if sd>24&\short then call calPutl cellM;if sd>49&\shorter then call calPutl cellB;return calHd:if sd>24&\shorter then call calPutl;if sd>32&\shortest then call calPutl;return calPb:if \grid&shortest then call put chk;return calPut:calPuts=calPuts+1;maxKalPuts=max(maxKalPuts,calPuts);if symbol('CT.'calPuts)\=='VAR' then ct.calPuts=;ct.calPuts=overlay(arg(1),ct.calPuts,cv);return calPutl:call calPut copies(' ',cindent)left(arg(2)"│",1)center(arg(1),calwidth)||right('│'arg(2),1);return cx:cx_='├┤';cx=copies(copies('─',cw)'┼',7);if calft then do;cx=translate(cx,'┬',"┼");calft=0;end;if calfb then do;cx=translate(cx,'┴',"┼");cx_='└┘';calfb=0;end;call calPutl cx,cx_;return dow:procedure;arg m,d,y;if m<3 then do;m=m+12;y=y-1;end;yl=left(y,2);yr=right(y,2);w=(d+(m+1)*26%10+yr+yr%4+yl%4+5*yl)//7;if w==0 then w=7;return w er:parse arg _1,_2;call '$ERR' "14"p(_1) p(word(_1,2) !fid(1)) _2;if _1<0 then return _1;exit result err:call er '-'arg(1),arg(2);return erx:call er '-'arg(1),arg(2);exit fcalPuts: do j=1 for maxKalPuts;call put ct.j;end;ct.=;maxKalPuts=0;calPuts=0;return int:int=numx(arg(1),arg(2));if \isint(int) then call erx 92,arg(1) arg(2);return int/1 is#:return verify(arg(1),#)==0 isint:return datatype(arg(1),'W') lower:return translate(arg(1),@abc,@abcU) ly:arg _;if length(_)==2 then _=hyy||_;ly=_//4==0;if ly==0 then return 0;ly=((_//100\==0)|_//400==0);return ly na:if arg(1)\== then call erx 01,arg(2);parse var ops na ops;if na== then call erx 35,_o;return na nai:return int(na(),_o) nan:return numx(na(),_o) no:if arg(1)\== then call erx 01,arg(2);return left(_,2)\=='NO' num:procedure;parse arg x .,f,q;if x== then return x;if datatype(x,'N') then return x/1;x=space(translate(x,,','),0);if datatype(x,'N') then return x/1;return numnot() numnot:if q==1 then return x;if q== then call er 53,x f;call erx 53,x f numx:return num(arg(1),arg(2),1) p:return word(arg(1),1) 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),,"│║─═┤┐└┴┬├┼┘┌╔╗╚╝╟╢╞╡╫╪╤╧╥╨╠╣")</lang> output when using the input of: 1/1/1969 (noGrid smallest narrowest)
«Snoopy "picture" here» 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
Output when using the input of: 1/1/1969 (smallest narrowest width 156 calSpaces 5)
A width of 156 was used to illustrate showing a grid, otherwise it would fit in 132 columns.
┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐ │ January 1969 │ │ February 1969 │ │ March 1969 │ │ 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│ │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 1969 │ │ August 1969 │ │ September 1969 │ │ 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│ │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│ │ │ │ │ │ │ └──┴──┴──┴──┴──┴──┴──┘ └──┴──┴──┴──┴──┴──┴──┘ ,-~~-.___. / ()=(() \ ( ( 0 \._\, ,----' ##XXXxxxxxxx / ---'~; / /~|- =( ~~ | /~~~~~~~~~~~~~~~~~~~~~\ /_______________________\ /_________________________\ /___________________________\ |____________________| |____________________| |____________________| | |
Ruby
Date
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 Date
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.
- This program requires Ruby 1.8.7 because it calls Array#each_slice.
<lang ruby>require 'date'
- Creates a calendar of _year_. Returns this calendar as a multi-line
- string fit to _columns_.
def cal(year, columns)
# Start at January 1. # # Date::ENGLAND marks the switch from Julian calendar to Gregorian # calendar at 1752 September 14. This removes September 3 to 13 from # year 1752. (By fortune, it keeps January 1.) # date = Date.new(year, 1, 1, Date::ENGLAND)
# Collect calendars of all 12 months. months = (1..12).collect do |month| rows = [Date::MONTHNAMES[month].center(20), "Su Mo Tu We Th Fr Sa"]
# Make array of 42 days, starting with Sunday. days = [] date.wday.times { days.push " " } while date.month == month days.push("%2d" % date.mday) date += 1 end (42 - days.length).times { days.push " " }
days.each_slice(7) { |week| rows.push(week.join " ") } next rows end
# Calculate months per row (mpr). # 1. Divide columns by 22 columns per month, rounded down. (Pretend # to have 2 extra columns; last month uses only 20 columns.) # 2. Decrease mpr if 12 months would fit in the same months per # column (mpc). For example, if we can fit 5 mpr and 3 mpc, then # we use 4 mpr and 3 mpc. mpr = (columns + 2).div 22 mpr = 12.div((12 + mpr - 1).div mpr)
# Use 20 columns per month + 2 spaces between months. width = mpr * 22 - 2
# Join months into calendar. rows = ["[Snoopy]".center(width), "#{year}".center(width)] months.each_slice(mpr) do |slice| slice[0].each_index do |i| rows.push(slice.map {|a| a[i]}.join " ") end end return rows.join("\n")
end
ARGV.length == 1 or abort "usage: #{$0} year"
- Guess width of terminal.
- 1. Obey environment variable COLUMNS.
- 2. Try to require 'io/console' from Ruby 1.9.3.
- 3. Try to run `tput co`.
- 4. Assume 80 columns.
columns = begin Integer(ENV["COLUMNS"] || "")
rescue begin require 'io/console'; IO.console.winsize[1] rescue LoadError begin Integer(`tput co`) rescue 80; end; end; end
puts cal(Integer(ARGV[0]), columns)</lang>
Here is 1969 in 132 columns.
$ ruby cal.rb 1969 [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
The output in 80 columns is similar, except that there are only three months per row, and the "[Snoopy]" and "1969" are centered above February.
Scala
Scala Version 1
<lang Scala>import java.util.{ Calendar, GregorianCalendar } import language.postfixOps import collection.mutable.ListBuffer
object CalendarPrint extends App {
val locd = java.util.Locale.getDefault() val cal = new GregorianCalendar val monthsMax = cal.getMaximum(Calendar.MONTH)
def JDKweekDaysToISO(dn: Int) = { val nday = dn - Calendar.MONDAY if (nday < 0) (dn + Calendar.THURSDAY) else nday }
def daysInMonth(year: Int, monthMinusOne: Int): Int = { cal.set(year, monthMinusOne, 1) cal.getActualMaximum(Calendar.DAY_OF_MONTH) }
def namesOfMonths() = { def f1(i: Int): String = { cal.set(2013, i, 1) cal.getDisplayName(Calendar.MONTH, Calendar.LONG, locd) } (0 to monthsMax) map f1 }
def offsets(year: Int): List[Int] = { val months = cal.getMaximum(Calendar.MONTH) def get1stDayOfWeek(i: Int) = { cal.set(year, i, 1) cal.get(Calendar.DAY_OF_WEEK) } (0 to monthsMax).toList map get1stDayOfWeek map { i => JDKweekDaysToISO(i) } }
def headerNameOfDays() = { val mdow = cal.getDisplayNames(Calendar.DAY_OF_WEEK, Calendar.SHORT, locd) // map days of week val it = mdow.keySet.iterator val keySet = new ListBuffer[String] while (it.hasNext) keySet += it.next (keySet.map { key => (JDKweekDaysToISO(mdow.get(key)), key.take(2)) }.sortWith(_._1 < _._1) map (_._2)).mkString(" ") }
def getGregCal(year: Int) = { {
def dayOfMonth(month: Int) = new Iterator[(Int, Int)] { cal.set(year, month, 1) var ldom = 0
def next() = { val res = (cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH)) ldom = res._2 cal.roll(Calendar.DAY_OF_MONTH, true) res }
def hasNext() = (cal.get(Calendar.DAY_OF_MONTH) > ldom) } var ret: List[(Int, Int)] = Nil for (i <- 0 to monthsMax) ret = ret ++ (dayOfMonth(i).toSeq) (ret, offsets(year)) } }
def printCalendar(calendar: (List[(Int, Int)], List[Int]), headerList: List[String] = Nil, printerWidth: Int = 80) = { val mw = 20 // month width val gwf = 2 // gap width fixed val gwm = 2 // gap width minimum val fgw = true
val arr = Array.ofDim[String](6, 7)
def limits(printerWidth: Int): (Int, Int, Int, Int, Int) = { val pw = if (printerWidth < 20) 20 else if (printerWidth > 300) 300 else printerWidth
// months side by side, gaps sum minimum val (msbs, gsm) = { val x1 = { val c = if (pw / mw > 12) 12 else pw / mw val a = (c - 1) if (c * mw + a * gwm <= pw) c else a } match { case 5 => 4 case a if (a > 6 && a < 12) => 6 case other => other } (x1, (x1 - 1) * gwm) }
def getFGW(msbs: Int, gsm: Int) = { val r = (pw - msbs * mw - gsm) / 2; (r, gwf, r) } // fixed gap width def getVGW(msbs: Int, gsm: Int) = pw - msbs * mw - gsm match { // variable gap width case a if (a < 2 * gwm) => (a / 2, gwm, a / 2) case b => { val x = (b + gsm) / (msbs + 1); (x, x, x) } }
// left margin, gap width, right margin val (lm, gw, rm) = if (fgw) getFGW(msbs, gsm) else getVGW(msbs, gsm) (pw, msbs, lm, gw, rm) } // def limits(
val (pw, msbs, lm, gw, rm) = limits(printerWidth) val monthsList = (0 to monthsMax).map { m => calendar._1.filter { _._1 == m } } val nom = namesOfMonths() val hnod = headerNameOfDays
def fsplit(list: List[(Int, Int)]): List[String] = { def fap(p: Int) = (p / 7, p % 7) for (i <- 0 until 6) for (j <- 0 until 7) arr(i)(j) = " " for (i <- 0 until list.size) arr(fap(i + calendar._2(list(i)._1))._1)(fap(i + calendar._2(list(i)._1))._2) = f"${(list(i)._2)}%2d" arr.toList.map(_.foldRight("")(_ + " " + _)) } val monthsRows = monthsList.map(fsplit)
def center(s: String, l: Int): String = { (if (s.size >= l) s else " " * ((l - s.size) / 2) + s + " " * ((l - s.size) / 2) + " ").substring(0, l) }
val maxMonths = monthsMax + 1
val rowblocks = (1 to maxMonths / msbs).map { i => (0 to 5).map { j => val lb = new ListBuffer[String] val k = (i - 1) * msbs (k to k + msbs - 1).map { l => lb += monthsRows(l)(j) } lb } }
val mheaders = (1 to maxMonths / msbs). map { i => (0 to msbs - 1).map { j => center(nom(j + (i - 1) * msbs), 20) } } val dowheaders = (1 to maxMonths / msbs). map { i => (0 to msbs - 1).map { j => center(hnod, 20) } }
headerList.foreach(xs => println(center(xs + '\n', pw))) (1 to 12 / msbs).foreach { i => println(" " * lm + mheaders(i - 1).foldRight("")(_ + " " * gw + _)) println(" " * lm + dowheaders(i - 1).foldRight("")(_ + " " * gw + _)) rowblocks(i - 1).foreach { xs => println(" " * lm + xs.foldRight("")(_ + " " * (gw - 1) + _)) } println } } // def printCal(
printCalendar(getGregCal(1969), List("[Snoopy Picture]", "1969")) printCalendar(getGregCal(1582), List("[Snoopy Picture]", "1582"), printerWidth = 132)
}</lang>
- Output:
[Snoopy Picture] 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 [Snoopy Picture] 1582 January February March April May June 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 Su 1 2 3 4 5 6 7 1 2 3 4 1 2 3 4 1 1 2 3 4 5 6 1 2 3 8 9 10 11 12 13 14 5 6 7 8 9 10 11 5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13 4 5 6 7 8 9 10 15 16 17 18 19 20 21 12 13 14 15 16 17 18 12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20 11 12 13 14 15 16 17 22 23 24 25 26 27 28 19 20 21 22 23 24 25 19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27 18 19 20 21 22 23 24 29 30 31 26 27 28 26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31 25 26 27 28 29 30 30 July August September October November December 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 Su 1 1 2 3 4 5 1 2 1 2 3 4 15 16 17 1 2 3 4 5 6 7 1 2 3 4 5 2 3 4 5 6 7 8 6 7 8 9 10 11 12 3 4 5 6 7 8 9 18 19 20 21 22 23 24 8 9 10 11 12 13 14 6 7 8 9 10 11 12 9 10 11 12 13 14 15 13 14 15 16 17 18 19 10 11 12 13 14 15 16 25 26 27 28 29 30 31 15 16 17 18 19 20 21 13 14 15 16 17 18 19 16 17 18 19 20 21 22 20 21 22 23 24 25 26 17 18 19 20 21 22 23 22 23 24 25 26 27 28 20 21 22 23 24 25 26 23 24 25 26 27 28 29 27 28 29 30 31 24 25 26 27 28 29 30 29 30 27 28 29 30 31 30 31
Scala Version 2
<lang Scala>/**
* Loosely based on the Ruby implementation. * * Focuses on immutability and Scala idioms, * while trying to remain readable and clean. */
object YearCalendarApp extends App with Extras {
val defaultYear = 1752 val columns = 86
val year = args.headOption.map(_.toInt).getOrElse(defaultYear)
yearCalendarLines(year, columns).foreach(println)
def yearCalendarLines(year: Int, columns: Int): Seq[String] = { // At least one. Divide rest columns by width + 2 spaces (separator) val calendarsPerRow = 1 + (columns - 20) / (20 + 2)
// Use 20 columns per month + 2 spaces between months val width = calendarsPerRow * 22 - 2
List( "[Snoopy]".center(width), s"${year}".center(width)) ++ // Get, group, transpose and join calendar lines allMonthCalendarLines(year).grouped(calendarsPerRow).flatMap { calGroup => calGroup.transpose.map(stringsInRow => stringsInRow.mkString(" ")) } }
def allMonthCalendarLines(year: Int): Seq[Seq[String]] = { (1 to 12).map { monthNr => val date = MonthCalendar(monthInYear = monthNr, year)
// Make array of 42 days (7 * 6 weeks max.) starting with Sunday (which is 0) val daySlotsInMonth = { (Seq().padTo(date.dayOfWeek, " ") ++ date.daysInMonth.map { dayNr => "%2d".format(dayNr) }). padTo(42, " ") }
List( date.monthName.center(20), "Su Mo Tu We Th Fr Sa") ++ daySlotsInMonth.grouped(7).map { weekSlots => weekSlots.mkString(" ") } } }
}</lang>
<lang Scala>/**
* This provides extra classes needed for the main * algorithm. */
trait Extras {
import java.util.Calendar import java.util.GregorianCalendar import java.text.SimpleDateFormat import java.util.Locale
import scala.collection.mutable.Buffer
implicit class MyString(str: String) { def center(width: Int): String = { val leftSpaces = (width / 2) - (str.length() / 2) val rightSpaces = width - (leftSpaces + str.length) (" " * leftSpaces) + str + (" " * rightSpaces) } }
case class MonthCalendar(monthInYear: Int, year: Int) { private val javaCalendar = makeJavaCalendar(year, monthInYear) private def makeJavaCalendar(year: Int, monthInYear: Int): Calendar = { val calendar = new GregorianCalendar() // Actually, other countries changed already in 1582, // which is the JDK's default implementation. val gregorianDateChangeInEngland = { val d = Calendar.getInstance() d.set(1752, Calendar.SEPTEMBER, 14) d.getTime() } // For England we need to set this explicitly. calendar.setGregorianChange(gregorianDateChangeInEngland) calendar.set(Calendar.DAY_OF_MONTH, 1) calendar.set(Calendar.YEAR, year) calendar.set(Calendar.MONTH, monthInYear - 1) calendar } val monthName = javaCalendar.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.ENGLISH) val dayOfWeek = javaCalendar.get(Calendar.DAY_OF_WEEK) - 1 val daysInMonth = { val tempCal = makeJavaCalendar(year, monthInYear) val dayNumbers = Buffer[Int]() while (tempCal.get(Calendar.MONTH) == monthInYear - 1) { dayNumbers += tempCal.get(Calendar.DAY_OF_MONTH) tempCal.add(Calendar.DATE, 1) } dayNumbers } }
}</lang>
Sample output for 1792:
[Snoopy] 1752 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 2 3 4 5 6 7 1 2 3 4 5 6 7 8 9 10 11 2 3 4 5 6 7 8 8 9 10 11 12 13 14 5 6 7 8 9 10 11 12 13 14 15 16 17 18 9 10 11 12 13 14 15 15 16 17 18 19 20 21 12 13 14 15 16 17 18 19 20 21 22 23 24 25 16 17 18 19 20 21 22 22 23 24 25 26 27 28 19 20 21 22 23 24 25 26 27 28 29 30 31 23 24 25 26 27 28 29 29 30 31 26 27 28 29 30 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 1 2 3 4 5 6 1 2 3 4 1 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 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 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 24 25 26 27 28 29 30 28 29 30 26 27 28 29 30 31 23 24 25 26 27 28 29 31 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 14 15 16 1 2 3 4 5 6 7 1 2 3 4 1 2 17 18 19 20 21 22 23 8 9 10 11 12 13 14 5 6 7 8 9 10 11 3 4 5 6 7 8 9 24 25 26 27 28 29 30 15 16 17 18 19 20 21 12 13 14 15 16 17 18 10 11 12 13 14 15 16 22 23 24 25 26 27 28 19 20 21 22 23 24 25 17 18 19 20 21 22 23 29 30 31 26 27 28 29 30 24 25 26 27 28 29 30 31
Seed7
<lang seed7>$ include "seed7_05.s7i";
include "time.s7i";
const func string: center (in string: stri, in integer: length) is
return ("" lpad (length - length(stri)) div 2 <& stri) rpad length;
const proc: printCalendar (in integer: year, in integer: cols) is func
local var time: date is time.value; var integer: dayOfWeek is 0; const array string: monthNames is [] ("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"); var array array string: monthTable is 12 times 9 times ""; var string: str is ""; var integer: month is 0; var integer: position is 0; var integer: row is 0; var integer: column is 0; var integer: line is 0; begin for month range 1 to 12 do monthTable[month][1] := " " & center(monthNames[month], 20); monthTable[month][2] := " Mo Tu We Th Fr Sa Su"; date := date(year, month, 1); dayOfWeek := dayOfWeek(date); for position range 1 to 43 do if position >= dayOfWeek and position - dayOfWeek < daysInMonth(date.year, date.month) then str := succ(position - dayOfWeek) lpad 3; else str := "" lpad 3; end if; monthTable[month][3 + pred(position) div 7] &:= str; end for; end for; writeln(center("[Snoopy Picture]", cols * 24 + 4)); writeln(center(str(year),cols * 24 + 4)); writeln; for row range 1 to succ(11 div cols) do for line range 1 to 9 do for column range 1 to cols do if pred(row) * cols + column <= 12 then write(" " & monthTable[pred(row) * cols + column][line]); end if; end for; writeln; end for; end for; end func;
const proc: main is func
begin printCalendar(1969, 3); end func;</lang>
Original source: [1]
The output of this program is:
[Snoopy Picture] 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
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. <lang tcl>package require Tcl 8.5
- Produce information about the days in a month, without any assumptions about
- what those days actually are.
proc calMonthDays {timezone locale year month} {
set days {} set moment [clock scan [format "%04d-%02d-00 12:00" $year $month] \
-timezone $timezone -locale $locale -format "%Y-%m-%d %H:%M"]
while 1 {
set moment [clock add $moment 1 day] lassign [clock format $moment -timezone $timezone -locale $locale \ -format "%m %d %u"] m d dow if {[scan $m %d] != $month} { return $days } lappend days $moment [scan $d %d] $dow
}
}
proc calMonth {year month timezone locale} {
set dow 0 set line "" set lines {} foreach {t day dayofweek} [calMonthDays $timezone $locale $year $month] {
if {![llength $lines]} {lappend lines $t} if {$dow > $dayofweek} { lappend lines [string trimright $line] set line "" set dow 0 } while {$dow < $dayofweek-1} { append line " " incr dow } append line [format "%2d " $day] set dow $dayofweek
} lappend lines [string trimright $line]
}
proc cal3Month {year month timezone locale} {
# Extract the month data set d1 [lassign [calMonth $year $month $timezone $locale] t1]; incr month set d2 [lassign [calMonth $year $month $timezone $locale] t2]; incr month set d3 [lassign [calMonth $year $month $timezone $locale] t3] # Print the header line of month names foreach t [list $t1 $t2 $t3] {
set m [clock format $t -timezone $timezone -locale $locale -format "%B"] set l [expr {10 + [string length $m]/2}] puts -nonewline [format "%-25s" [format "%*s" $l $m]]
} puts "" # Print the month days foreach l1 $d1 l2 $d2 l3 $d3 {
puts [format "%-25s%-25s%s" $l1 $l2 $l3]
}
}
proc cal {{year ""} {timezone :localtime} {locale en}} {
if {$year eq ""} {
set year [clock format [clock seconds] -format %Y]
} puts [format "%40s" "-- $year --"] foreach m {1 4 7 10} {
puts "" cal3Month $year $m $timezone $locale
}
}
proc snoopy {} {
puts [format "%43s\n" {[Snoopy Picture]}]
}
snoopy cal</lang> Which produces this output:
[Snoopy Picture] -- 2011 -- January February March 1 2 1 2 3 4 5 6 1 2 3 4 5 6 3 4 5 6 7 8 9 7 8 9 10 11 12 13 7 8 9 10 11 12 13 10 11 12 13 14 15 16 14 15 16 17 18 19 20 14 15 16 17 18 19 20 17 18 19 20 21 22 23 21 22 23 24 25 26 27 21 22 23 24 25 26 27 24 25 26 27 28 29 30 28 28 29 30 31 31 April May June 1 2 3 1 1 2 3 4 5 4 5 6 7 8 9 10 2 3 4 5 6 7 8 6 7 8 9 10 11 12 11 12 13 14 15 16 17 9 10 11 12 13 14 15 13 14 15 16 17 18 19 18 19 20 21 22 23 24 16 17 18 19 20 21 22 20 21 22 23 24 25 26 25 26 27 28 29 30 23 24 25 26 27 28 29 27 28 29 30 30 31 July August September 1 2 3 1 2 3 4 5 6 7 1 2 3 4 4 5 6 7 8 9 10 8 9 10 11 12 13 14 5 6 7 8 9 10 11 11 12 13 14 15 16 17 15 16 17 18 19 20 21 12 13 14 15 16 17 18 18 19 20 21 22 23 24 22 23 24 25 26 27 28 19 20 21 22 23 24 25 25 26 27 28 29 30 31 29 30 31 26 27 28 29 30 October November December 1 2 1 2 3 4 5 6 1 2 3 4 3 4 5 6 7 8 9 7 8 9 10 11 12 13 5 6 7 8 9 10 11 10 11 12 13 14 15 16 14 15 16 17 18 19 20 12 13 14 15 16 17 18 17 18 19 20 21 22 23 21 22 23 24 25 26 27 19 20 21 22 23 24 25 24 25 26 27 28 29 30 28 29 30 26 27 28 29 30 31 31
If a different year is chosen, it's printed… <lang tcl>snoopy cal 1969</lang>
[Snoopy Picture] -- 1969 -- January February March 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 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 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 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
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: <lang tcl>snoopy cal 1582 :Europe/Madrid es_ES</lang>
[Snoopy Picture] -- 1582 -- enero febrero marzo 1 2 3 4 5 6 7 1 2 3 4 1 2 3 4 8 9 10 11 12 13 14 5 6 7 8 9 10 11 5 6 7 8 9 10 11 15 16 17 18 19 20 21 12 13 14 15 16 17 18 12 13 14 15 16 17 18 22 23 24 25 26 27 28 19 20 21 22 23 24 25 19 20 21 22 23 24 25 29 30 31 26 27 28 26 27 28 29 30 31 abril mayo junio 1 1 2 3 4 5 6 1 2 3 2 3 4 5 6 7 8 7 8 9 10 11 12 13 4 5 6 7 8 9 10 9 10 11 12 13 14 15 14 15 16 17 18 19 20 11 12 13 14 15 16 17 16 17 18 19 20 21 22 21 22 23 24 25 26 27 18 19 20 21 22 23 24 23 24 25 26 27 28 29 28 29 30 31 25 26 27 28 29 30 30 julio agosto septiembre 1 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 30 31 octubre noviembre diciembre 1 2 3 4 15 16 17 1 2 3 4 5 6 7 1 2 3 4 5 18 19 20 21 22 23 24 8 9 10 11 12 13 14 6 7 8 9 10 11 12 25 26 27 28 29 30 31 15 16 17 18 19 20 21 13 14 15 16 17 18 19 22 23 24 25 26 27 28 20 21 22 23 24 25 26 29 30 27 28 29 30 31
As can be seen, a Real Programmer has many intricacies to deal with!
UNIX Shell
All Unix variations come with the cal command which makes the task very easy. <lang bash>
- !/bin/sh
echo "Snoopy goes here" cal 1969 </lang>
Output produced:
Snoopy goes here 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
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.)
See CALENDAR task for a stand-alone version.
Calendar.vdm draws one month calendar. That is then copied as columnar block and pasted to the 1969 calendar.
<lang vedit>Buf_Switch(Buf_Free) Config_Tab(5,30,55)
- 9 = 1 // first day of week: 0=Su, 1=Mo
- 3 = 3 // number of months per line
- 2 = 1969 // year
- 1 = 1 // starting month
Repeat(12/#3) {
Repeat (#3) { Buf_Switch(Buf_Free) Call_File(122, "calendar.vdm", "DRAW_CALENDAR") Reg_Copy_Block(10, 1, EOB_Pos, COLSET, 1, 21) Buf_Quit(OK) EOL Ins_Char(9) #5 = Cur_Pos Reg_Ins(10) Goto_Pos(#5) #1++ } EOF Ins_Newline(2)
} </lang>
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. <lang vedit>Config_Tab(22)</lang>
Output:
January 1969 February 1969 March 1969 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 1969 May 1969 June 1969 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 1969 August 1969 September 1969 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 1969 November 1969 December 1969 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
XPL0
<lang XPL0>include c:\cxpl\codes; \intrinsic 'code' declarations
func WeekDay(Year, Month, Day); \Return day of week (0=Sun 1=Mon..6=Sat) int Year, Month, Day; \Works for years from 1583 onward [if Month<=2 then [Month:= Month+12; Year:= Year-1]; return rem((Day-1 + (Month+1)*26/10 + Year + Year/4 + Year/100*6 + Year/400)/7); ];
proc Space(N); \Display N space characters int N; while N do [ChOut(0, ^ ); N:= N-1];
proc Calendar(Year); \Display calendar for specified year int Year; int Month, Col, C, Line, MoName, Days, DayMax, Day(3); [MoName:= [
" January ", " February", " March ", " April ", " May ", " June ", " July ", " August ", "September", " October", " November", " December"];
Space(35); Text(0, "[Snoopy]"); CrLf(0); Space(37); IntOut(0, Year); CrLf(0); CrLf(0); for Month:= 1 to 12 do
[for Col:= 0 to 3-1 do [Space(5); Text(0, MoName(Month+Col-1)); Space(7); if Col<2 then Space(8); ]; CrLf(0); for Col:= 0 to 3-1 do [Text(0, "Su Mo Tu We Th Fr Sa"); if Col<2 then Space(9); ]; CrLf(0); for Col:= 0 to 3-1 do \day of first Sunday of month (can be negative) Day(Col):= 1 - WeekDay(Year, Month+Col, 1); for Line:= 0 to 6-1 do [for Col:= 0 to 3-1 do [Days:= [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; DayMax:= Days(Month+Col); if Month+Col=2 & (rem(Year/4)=0 & rem(Year/100)#0 ! rem(Year/400)=0) then DayMax:= DayMax+1; \if February and leap year then add a day for C:= 0 to 7-1 do [if Day(Col)>=1 & Day(Col)<=DayMax then [IntOut(0, Day(Col)); if Day(Col)<10 then Space(1); \left justify ] else Space(2); \suppress out of range days Space(1); Day(Col):= Day(Col)+1; ]; if Col<2 then Space(8); ]; CrLf(0); ]; CrLf(0); Month:= Month+2; \2+1 months per Col(umn) ];
];
Calendar(1969)</lang>
- Output:
[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
- Programming Tasks
- Date and time
- Ada
- ALGOL 68
- AutoHotkey
- AutoIt
- AWK
- BBC BASIC
- C
- C++
- C sharp
- COBOL
- D
- Icon
- Unicon
- Icon Programming Library
- J
- Mathematica
- Perl
- Perl 6
- PicoLisp
- Pike
- Examples needing attention
- PL/I
- Python
- Racket
- REXX
- Ruby
- Scala
- Scala Implementations
- Scala examples needing attention
- Seed7
- Tcl
- UNIX Shell
- Vedit macro language
- XPL0