From 715bf6068f98089a03ca2beb38facbe568ac07ff Mon Sep 17 00:00:00 2001 From: Greg Reagle Date: Thu, 8 Jan 2015 17:16:19 -0500 Subject: [PATCH 1/2] Julian when month is Sep 1752 or before. Gregorian when month is Oct 1752 or after. --- cal.1 | 1 + cal.c | 22 +++++++++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/cal.1 b/cal.1 index c215340..659d46a 100644 --- a/cal.1 +++ b/cal.1 @@ -28,6 +28,7 @@ of calendars side by side. Each row of calendars contains at most .IR columns number of calendars. The defaults are obtained using .IR localtime (3). +The Julian calendar is used for Septmeber 1752 and before. Starting with October 1752, the Gregorian calendar is used. .SH OPTIONS .TP .B \-1 diff --git a/cal.c b/cal.c index 53c6022..a000843 100644 --- a/cal.c +++ b/cal.c @@ -5,6 +5,9 @@ #include "util.h" +enum caltype {Julian, Gregorian}; +enum {Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec}; + static int isleap(int year) { @@ -19,27 +22,36 @@ static int monthlength(int year, int month) { int mdays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - return (month==1 && isleap(year)) ? 29 : mdays[month]; + return (month==Feb && isleap(year)) ? 29 : mdays[month]; } /* From http://www.tondering.dk/claus/cal/chrweek.php#calcdow */ static int -dayofweek(int year, int month, int dom) +dayofweek(int year, int month, int dom, enum caltype cal) { int m, y, a; month += 1; /* in this formula, 1 <= month <= 12 */ a = (14 - month) / 12; y = year - a; m = month + 12*a - 2; - return (dom + y + y/4 - y/100 + y/400 +((31*m)/12)) % 7; + + if (cal == Gregorian) + return (dom + y + y/4 - y/100 + y/400 + (31*m)/12) % 7; + else /* cal == Julian */ + return (5 + dom + y + y/4 + (31*m)/12) % 7; } static void printgrid(int year, int month, int fday, int line) { - int dom, offset, d=0; + enum caltype cal, offset, dom, d=0; + + if (year < 1752 || (year == 1752 && month <= Sep)) + cal = Julian; + else + cal = Gregorian; + offset = dayofweek(year, month, 1, cal) - fday; - offset = dayofweek(year, month, 1) - fday; if (offset < 0) offset += 7; if (line==1) { -- 2.2.1 From 3520c5cccb9958a056e4885108060bdf8ed03526 Mon Sep 17 00:00:00 2001 From: Greg Reagle Date: Tue, 13 Jan 2015 12:37:30 -0500 Subject: [PATCH 2/2] Using the Julian calendar for dates through September 2, 1752 and the Gregorian calendar for dates from September 14, 1752. --- cal.1 | 4 +++- cal.c | 39 ++++++++++++++++++++++++++------------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/cal.1 b/cal.1 index 659d46a..8619460 100644 --- a/cal.1 +++ b/cal.1 @@ -28,7 +28,7 @@ of calendars side by side. Each row of calendars contains at most .IR columns number of calendars. The defaults are obtained using .IR localtime (3). -The Julian calendar is used for Septmeber 1752 and before. Starting with October 1752, the Gregorian calendar is used. +The Julian calendar is used through Sep 2, 1752, and the Gregorian calendar is used starting the next day with Sep 14, 1752. .SH OPTIONS .TP .B \-1 @@ -58,3 +58,5 @@ Specify the first day of the week. 0 is Sunday and 6 is Saturday. Specify the number months to print. The default is 1. .SH SEE ALSO .IR localtime (3) +.SH STANDARDS +This program tries to conform to IEEE Std 1003.1, 2013 Edition, q.v. http://pubs.opengroup.org/onlinepubs/9699919799/utilities/cal.html. diff --git a/cal.c b/cal.c index a000843..a493ec9 100644 --- a/cal.c +++ b/cal.c @@ -5,24 +5,30 @@ #include "util.h" -enum caltype {Julian, Gregorian}; enum {Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec}; +enum caltype {Julian, Gregorian}; +enum {TRANS_YEAR = 1752, TRANS_MONTH = Sep, TRANS_DAY = 2}; static int -isleap(int year) +isleap(int year, enum caltype cal) { - if (year % 400 == 0) - return 1; - if (year % 100 == 0) - return 0; - return (year % 4 == 0); + if (cal == Gregorian) { + if (year % 400 == 0) + return 1; + if (year % 100 == 0) + return 0; + return (year % 4 == 0); + } + else { /* cal == Julian */ + return (year % 4 == 0); + } } static int -monthlength(int year, int month) +monthlength(int year, int month, enum caltype cal) { int mdays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - return (month==Feb && isleap(year)) ? 29 : mdays[month]; + return (month==Feb && isleap(year,cal)) ? 29 : mdays[month]; } /* From http://www.tondering.dk/claus/cal/chrweek.php#calcdow */ @@ -44,14 +50,16 @@ dayofweek(int year, int month, int dom, enum caltype cal) static void printgrid(int year, int month, int fday, int line) { - enum caltype cal, offset, dom, d=0; + enum caltype cal; + int trans; /* are we in the transition from Julian to Gregorian? */ + int offset, dom, d=0; - if (year < 1752 || (year == 1752 && month <= Sep)) + if (year < TRANS_YEAR || (year == TRANS_YEAR && month <= TRANS_MONTH)) cal = Julian; else cal = Gregorian; + trans = (year == TRANS_YEAR && month == TRANS_MONTH); offset = dayofweek(year, month, 1, cal) - fday; - if (offset < 0) offset += 7; if (line==1) { @@ -60,9 +68,14 @@ printgrid(int year, int month, int fday, int line) dom = 1; } else { dom = 8-offset + (line-2)*7; + if (trans && !(line==2 && fday==3)) + dom += 11; } - for ( ; d < 7 && dom <= monthlength(year, month); ++d, ++dom) + for ( ; d < 7 && dom <= monthlength(year, month, cal); ++d, ++dom) { printf("%2d ", dom); + if (trans && dom==TRANS_DAY) + dom += 11; + } for ( ; d < 7; ++d) printf(" "); } -- 2.2.1