* v2.32 cal(1)
@ 2017-12-19 13:29 Karel Zak
2017-12-20 2:32 ` [PATCH] cal: add --iso and --1782-reform format options J William Piggott
2017-12-20 16:29 ` v2.32 cal(1) Adam Sampson
0 siblings, 2 replies; 7+ messages in thread
From: Karel Zak @ 2017-12-19 13:29 UTC (permalink / raw)
To: util-linux
I'd like to do some changes to the command cal(1). The current
implementation provides extra care about year 1752 -- calendar
reformation -- switch from Julian to Gregorian calendar.
The problem is that year 1752 is very specific to British Empire and
for example Catholic Europe moved to the Gregorian calendar in year
1582.
And another countries in another years... for details see
https://en.wikipedia.org/wiki/Gregorian_calendar.
cal(1) is not compatible with another tools (e.g. date(1)) for old
dates, and it's painful to use cal(1) for old dates as you have no
control about the calculations.
My suggestion:
* keep the current default "British Empire" behavior (Gregorian since
September 1752)
* add option --gregorian to strictly use Gregorian calendar for all
dates with no exceptions (it means dates from year 0 to now, no
exceptions for 1582 or 1752, or so...)
* for --gregorian also use ISO leap years calculation for all dates
Now we use for years < 1752 simple "year/4" calculation.
* add to the man page section about Gregorian and Julian calendars and
explain where and when Gregorian calendar went into effect, years 1582,
1752 etc. (just to avoid discussions:-)
* add option --1752-reform to enable the current "British Empire" behavior
(default now)
* later (after warning in release notes) we can make --gregorian as
the default
Comments? Volunteers?
Karel
--
Karel Zak <kzak@redhat.com>
http://karelzak.blogspot.com
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH] cal: add --iso and --1782-reform format options 2017-12-19 13:29 v2.32 cal(1) Karel Zak @ 2017-12-20 2:32 ` J William Piggott 2017-12-21 14:13 ` Karel Zak 2017-12-20 16:29 ` v2.32 cal(1) Adam Sampson 1 sibling, 1 reply; 7+ messages in thread From: J William Piggott @ 2017-12-20 2:32 UTC (permalink / raw) To: Karel Zak; +Cc: util-linux Signed-off-by: J William Piggott <elseifthen@gmx.com> --- misc-utils/cal.1 | 20 +++++++++++++++----- misc-utils/cal.c | 39 +++++++++++++++++++++++++++------------ 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/misc-utils/cal.1 b/misc-utils/cal.1 index f1084edba..4ef86913f 100644 --- a/misc-utils/cal.1 +++ b/misc-utils/cal.1 @@ -55,12 +55,20 @@ abbreviated month name according to the current locales. .SH OPTIONS .TP \fB\-1\fR, \fB\-\-one\fR -Display single month output. -(This is the default.) +Display single month output (default). .TP \fB\-3\fR, \fB\-\-three\fR Display three months spanning the date. .TP +.B \-\-1752-reform +Display calendars based upon the Chesterfield's Act format (default). +.RB See \ BUGS \ below. +.TP +.B \-\-iso +Display calendars based upon the ISO 8601 proleptic Gregorian format. +This means that dates previous to calendar reform use extrapolated Gregorian +dates instead of Julian dates. +.TP \fB\-n , \-\-months\fR \fInumber\fR Display \fInumber\fR of months, starting from the month containing the date. .TP @@ -148,14 +156,16 @@ See for more details about colorization configuration. .SH BUGS .PP -The +The default .B cal -program uses the 3rd of September 1752 as the date of the Gregorian calendar +format uses the 3rd of September 1752 as the date of the Gregorian calendar reformation -- that is when it happened in Great Britain and its colonies (including what is now the USA). Starting at that date, eleven days were eliminated by this reformation, so the calendar for that month is rather unusual. The actual historical dates at which the calendar reform happened in all the -different countries (locales) are ignored. +different countries (locales), including its introduction by Pope Gregory XIII +in October 1582, are ignored. The Gregorian calendar is a refinement to the +Julian calendar improving its synchronization with solar cycles. .PP Alternative calendars, such as the Umm al-Qura, the Solar Hijri, the Ge'ez, or the lunisolar Hindu, are not supported. diff --git a/misc-utils/cal.c b/misc-utils/cal.c index 39f2bdcba..df1286170 100644 --- a/misc-utils/cal.c +++ b/misc-utils/cal.c @@ -160,7 +160,10 @@ enum { DECEMBER }; -#define REFORMATION_YEAR 1752 /* Signed-off-by: Lord Chesterfield */ +/* Dec 19 2017 - After an appropriate mourning period change 1752 to -1 making + * the default output format the proleptic Gregorian calendar + */ +int reformation_year = 1752; #define REFORMATION_MONTH SEPTEMBER #define NUMBER_MISSING_DAYS 11 /* 11 day correction */ #define YDAY_AFTER_MISSING 258 /* 14th in Sep 1752 */ @@ -265,7 +268,9 @@ int main(int argc, char **argv) }; enum { - OPT_COLOR = CHAR_MAX + 1 + OPT_COLOR = CHAR_MAX + 1, + OPT_ISO, + OPT_1752_REFORM }; static const struct option longopts[] = { @@ -279,6 +284,8 @@ int main(int argc, char **argv) {"year", no_argument, NULL, 'y'}, {"week", optional_argument, NULL, 'w'}, {"color", optional_argument, NULL, OPT_COLOR}, + {"iso", no_argument, NULL, OPT_ISO}, + {"1752-reform", no_argument, NULL, OPT_1752_REFORM}, {"version", no_argument, NULL, 'V'}, {"twelve", no_argument, NULL, 'Y'}, {"help", no_argument, NULL, 'h'}, @@ -390,6 +397,12 @@ int main(int argc, char **argv) ctl.colormode = colormode_or_err(optarg, _("unsupported color mode")); break; + case OPT_1752_REFORM: + reformation_year = 1782; + break; + case OPT_ISO: + reformation_year = -1; + break; case 'V': printf(UTIL_LINUX_VERSION); return EXIT_SUCCESS; @@ -534,7 +547,7 @@ int main(int argc, char **argv) /* leap year -- account for gregorian reformation in 1752 */ static int leap_year(int32_t year) { - if (year <= REFORMATION_YEAR) + if (year <= reformation_year) return !(year % 4); else return ( !(year % 4) && (year % 100) ) || !(year % 400); @@ -644,7 +657,7 @@ static void cal_fill_month(struct cal_month *month, const struct cal_control *ct continue; } if (j < month_days) { - if (month->year == REFORMATION_YEAR && month->month == REFORMATION_MONTH && (j == 3 || j == 247)) + if (month->year == reformation_year && month->month == REFORMATION_MONTH && (j == 3 || j == 247)) j += NUMBER_MISSING_DAYS; month->days[i] = j; j++; @@ -886,20 +899,20 @@ static int day_in_week(int day, int month, int32_t year) static const int reform[] = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 }; static const int old[] = { 5, 1, 0, 3, 5, 1, 3, 6, 2, 4, 0, 2 }; - if (year != REFORMATION_YEAR + 1) + if (year != reformation_year + 1) year -= month < MARCH; else year -= (month < MARCH) + 14; - if (REFORMATION_YEAR < year - || (year == REFORMATION_YEAR && REFORMATION_MONTH < month) - || (year == REFORMATION_YEAR && month == REFORMATION_MONTH && 13 < day)) { + if (reformation_year < year + || (year == reformation_year && REFORMATION_MONTH < month) + || (year == reformation_year && month == REFORMATION_MONTH && 13 < day)) { int64_t long_year = year; return (long_year + (year / 4) - (year / 100) + (year / 400) + reform[month - 1] + day) % DAYS_IN_WEEK; } - if (year < REFORMATION_YEAR - || (year == REFORMATION_YEAR && month < REFORMATION_MONTH) - || (year == REFORMATION_YEAR && month == REFORMATION_MONTH && day < 3)) + if (year < reformation_year + || (year == reformation_year && month < REFORMATION_MONTH) + || (year == reformation_year && month == REFORMATION_MONTH && day < 3)) return (year + year / 4 + old[month - 1] + day) % DAYS_IN_WEEK; return NONEDAY; } @@ -931,7 +944,7 @@ static int week_number(int day, int month, int32_t year, const struct cal_contro month = JANUARY; yday = day_in_year(day,month,year); - if (year == REFORMATION_YEAR && yday >= YDAY_AFTER_MISSING) + if (year == reformation_year && yday >= YDAY_AFTER_MISSING) fday -= NUMBER_MISSING_DAYS; /* Last year is last year */ @@ -1022,6 +1035,8 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -y, --year show the whole year\n"), out); fputs(_(" -Y, --twelve show the next twelve months\n"), out); fputs(_(" -w, --week[=<num>] show US or ISO-8601 week numbers\n"), out); + fputs(_(" --1752-reform use Chesterfield's Act format\n"), out); + fputs(_(" --iso use ISO 8601 proleptic Gregorian format\n"), out); fputs(_(" --color[=<when>] colorize messages (auto, always or never)\n"), out); fprintf(out, " %s\n", USAGE_COLORS_DEFAULT); ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH] cal: add --iso and --1782-reform format options 2017-12-20 2:32 ` [PATCH] cal: add --iso and --1782-reform format options J William Piggott @ 2017-12-21 14:13 ` Karel Zak 2017-12-21 17:33 ` J William Piggott 0 siblings, 1 reply; 7+ messages in thread From: Karel Zak @ 2017-12-21 14:13 UTC (permalink / raw) To: J William Piggott; +Cc: util-linux On Tue, Dec 19, 2017 at 09:32:49PM -0500, J William Piggott wrote: > -#define REFORMATION_YEAR 1752 /* Signed-off-by: Lord Chesterfield */ > +/* Dec 19 2017 - After an appropriate mourning period change 1752 to -1 making > + * the default output format the proleptic Gregorian calendar > + */ > +int reformation_year = 1752; Wow, I have to appreciate this really nice hack, it's way how to keep the change as small as possible ;-) ... but I'm not sure this way is elegant from code consistence, extendability, and for readers. We have control struct where is "julian" flag. It would be probably better to use the control struct for all the things around calendars. * add enum CAL_TYPE_{JULIAN,GREGORIAN,GB1752,...} * use the enum in cal_control (and remove julian flag) * set calendar type in getopt code block * use the same prefix (e.g. GB1752_*) for all the "British Empire" specific reform macros (including NUMBER_MISSING_DAYS and YDAY_AFTER_MISSING) * in code use switch(ctl->calendar) { case CAL_TYPE .... } to keep is readable ;-) * yes, it will require to use cal_control in small functions like leap_year(), but IMHO it's better than hide all in magic reformation_year global variable BTW, in theory it would be possible to support more reforms, for example Greece 1923 (16-Feb -> 1-Mar), etc. Maybe the region of the reform should be somehow within the command line option --reform-1752-GB --reform-1923-GR, etc. > @@ -279,6 +284,8 @@ int main(int argc, char **argv) > {"year", no_argument, NULL, 'y'}, > {"week", optional_argument, NULL, 'w'}, > {"color", optional_argument, NULL, OPT_COLOR}, > + {"iso", no_argument, NULL, OPT_ISO}, --iso seems like good idea, but --gregorian alias would be also nice as we already have --julian. Karel -- Karel Zak <kzak@redhat.com> http://karelzak.blogspot.com ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] cal: add --iso and --1782-reform format options 2017-12-21 14:13 ` Karel Zak @ 2017-12-21 17:33 ` J William Piggott 0 siblings, 0 replies; 7+ messages in thread From: J William Piggott @ 2017-12-21 17:33 UTC (permalink / raw) To: Karel Zak; +Cc: util-linux On 12/21/2017 09:13 AM, Karel Zak wrote: > On Tue, Dec 19, 2017 at 09:32:49PM -0500, J William Piggott wrote: >> -#define REFORMATION_YEAR 1752 /* Signed-off-by: Lord Chesterfield */ >> +/* Dec 19 2017 - After an appropriate mourning period change 1752 to -1 making >> + * the default output format the proleptic Gregorian calendar >> + */ >> +int reformation_year = 1752; > > Wow, I have to appreciate this really nice hack, it's way how to keep > the change as small as possible ;-) > > ... but I'm not sure this way is elegant from code consistence, > extendability, and for readers. > > We have control struct where is "julian" flag. It would be probably > better to use the control struct for all the things around calendars. It's your call, but it seems unnecessary to me. The reformation_year doesn't need to be passed around that much. The Julian flag has nothing to do with the Julian calendar output. See below. > > * add enum CAL_TYPE_{JULIAN,GREGORIAN,GB1752,...} > * use the enum in cal_control (and remove julian flag) > * set calendar type in getopt code block See below Julian option > > * use the same prefix (e.g. GB1752_*) for all the "British Empire" > specific reform macros (including NUMBER_MISSING_DAYS and YDAY_AFTER_MISSING) > > * in code use switch(ctl->calendar) { case CAL_TYPE .... } to keep is > readable ;-) > > * yes, it will require to use cal_control in small functions like > leap_year(), but IMHO it's better than hide all in magic reformation_year > global variable > > BTW, in theory it would be possible to support more reforms, for > example Greece 1923 (16-Feb -> 1-Mar), etc. Maybe the region of the > reform should be somehow within the command line option --reform-1752-GB > --reform-1923-GR, etc. Possible, but it would mean a lot of changes. There are hardcoded checks for the current Gregorian epoch. It would be much simpler if the epoch was set to a full year I think. It would eliminate checking month and day of the epoch and dropping of days out of the calendar. Then if someone wanted to compare the calendars for the month of the change they just print one with -1 --epoch-reform=1751 and one with -1 --epoch-reform=1753 and look at the difference. Or there could be an option to automagically display the month in Julian and Gregorian side-by-side. I think this would simplify the algorithm for using multiple Gregorian epochs (and would probably look better than the mess that gets printed for the months around the epoch now). > >> @@ -279,6 +284,8 @@ int main(int argc, char **argv) >> {"year", no_argument, NULL, 'y'}, >> {"week", optional_argument, NULL, 'w'}, >> {"color", optional_argument, NULL, OPT_COLOR}, >> + {"iso", no_argument, NULL, OPT_ISO}, > > --iso seems like good idea, but --gregorian alias would be also nice > as we already have --julian. That would be confusing because the Julian option has nothing to do with the Julian calendar output; There is no option for a Julian calendar, that is controlled strictly by the reform epoch. Julian is a terrible name for that option. It should have been called ordinal dates or day-of-year. The option applies to both Julian and Gregorian calendar output. Although Julian is used as synonym for ordinal dates, for example in the posix TZ definition, it's ambiguous. There is Julian (calendar) date, (astronomical) Julian date, (modified) Julia date, (ordinal) Julian date, and more; all completely different things. They should have stopped at Julian calendar IMO, and named the rest something else. --iso and --1752-reform are not choosing between a Gregorian or Julian calendar output; they are choosing Gregorian epoch or no Gregorian epoch. There is no option for users to choose Gregorian vs Julian calendar output. Using --gregorian implies a legitimate Gregorian calendar using an epoch. It would need to be --proleptic-gregorian which is a bit long; ISO 8601 requires using proleptic Gregorian dates so it is a nice alternate. I originally implemented this patch using --chesterfield instead of --1752-reform; I really wanted to keep it ;) But, I knew you'd object. Anyway, I want to work on hwclock so I'll have to bow out on anymore work on cal(1) for now ((kicking self for being distracted by this waste of time)). > > Karel > ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: v2.32 cal(1) 2017-12-19 13:29 v2.32 cal(1) Karel Zak 2017-12-20 2:32 ` [PATCH] cal: add --iso and --1782-reform format options J William Piggott @ 2017-12-20 16:29 ` Adam Sampson 2017-12-20 17:42 ` Karel Zak 1 sibling, 1 reply; 7+ messages in thread From: Adam Sampson @ 2017-12-20 16:29 UTC (permalink / raw) To: util-linux Karel Zak <kzak@redhat.com> writes: > The problem is that year 1752 is very specific to British Empire and > for example Catholic Europe moved to the Gregorian calendar in year > 1582. ... > * later (after warning in release notes) we can make --gregorian as > the default The date of cal's switch is specified in POSIX as 1752, though: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/cal.html (with a note that future versions may make this depend on the locale). So if the default is changed, it would be worth noting the deviation from POSIX in the man page, and maybe even defaulting to the old behaviour if POSIXLY_CORRECT is defined, as, e.g., coreutils does for other bits of dubious but mandated behaviour. I wonder if it might be more helpful just to report an error if cal is run for a year prior to 1926 without explicitly specifying which calendar to use? Thanks, -- Adam Sampson <ats@offog.org> <http://offog.org/> ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: v2.32 cal(1) 2017-12-20 16:29 ` v2.32 cal(1) Adam Sampson @ 2017-12-20 17:42 ` Karel Zak 2017-12-21 2:43 ` J William Piggott 0 siblings, 1 reply; 7+ messages in thread From: Karel Zak @ 2017-12-20 17:42 UTC (permalink / raw) To: Adam Sampson; +Cc: util-linux On Wed, Dec 20, 2017 at 04:29:43PM +0000, Adam Sampson wrote: > Karel Zak <kzak@redhat.com> writes: > > > The problem is that year 1752 is very specific to British Empire and > > for example Catholic Europe moved to the Gregorian calendar in year > > 1582. > ... > > * later (after warning in release notes) we can make --gregorian as > > the default > > The date of cal's switch is specified in POSIX as 1752, though: > http://pubs.opengroup.org/onlinepubs/9699919799/utilities/cal.html > (with a note that future versions may make this depend on the locale). It sounds like too complicated semantic to depend on locale. Don't also forget that switch from one calendar to another means extra calculation (for example skip 11 days for British Empire way, etc). > So if the default is changed, it would be worth noting the deviation > from POSIX in the man page, and maybe even defaulting to the old Good point. > behaviour if POSIXLY_CORRECT is defined, as, e.g., coreutils does for > other bits of dubious but mandated behaviour. > > I wonder if it might be more helpful just to report an error if cal is > run for a year prior to 1926 without explicitly specifying which > calendar to use? I think we can follow the current default behavior for ever, and just add --iso/--gregorian for people who care. Karel -- Karel Zak <kzak@redhat.com> http://karelzak.blogspot.com ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: v2.32 cal(1) 2017-12-20 17:42 ` Karel Zak @ 2017-12-21 2:43 ` J William Piggott 0 siblings, 0 replies; 7+ messages in thread From: J William Piggott @ 2017-12-21 2:43 UTC (permalink / raw) To: Karel Zak, Adam Sampson; +Cc: util-linux On 12/20/2017 12:42 PM, Karel Zak wrote: > On Wed, Dec 20, 2017 at 04:29:43PM +0000, Adam Sampson wrote: >> Karel Zak <kzak@redhat.com> writes: >> >>> The problem is that year 1752 is very specific to British Empire and >>> for example Catholic Europe moved to the Gregorian calendar in year >>> 1582. >> ... >>> * later (after warning in release notes) we can make --gregorian as >>> the default >> >> The date of cal's switch is specified in POSIX as 1752, though: >> http://pubs.opengroup.org/onlinepubs/9699919799/utilities/cal.html >> (with a note that future versions may make this depend on the locale). > > It sounds like too complicated semantic to depend on locale. Don't > also forget that switch from one calendar to another means extra > calculation (for example skip 11 days for British Empire way, etc). > >> So if the default is changed, it would be worth noting the deviation >> from POSIX in the man page, and maybe even defaulting to the old > > Good point. > >> behaviour if POSIXLY_CORRECT is defined, as, e.g., coreutils does for >> other bits of dubious but mandated behaviour. >> >> I wonder if it might be more helpful just to report an error if cal is >> run for a year prior to 1926 without explicitly specifying which >> calendar to use? > > I think we can follow the current default behavior for ever, and just > add --iso/--gregorian for people who care. I think the standard is being misunderstood. Issue 2 required the Gregorian format: _____________________________ http://pubs.opengroup.org/onlinepubs/007908799/xcu/cal.html DESCRIPTION The cal utility writes a Gregorian calendar to standard output. If the year operand is specified, a calendar for that year is written. If no operands are specified, a calendar for the current month is written. _____________________________ The reason for the change in issue 6 was to *allow* Julian: _____________________________ http://pubs.opengroup.org/onlinepubs/9699919799/utilities/cal.html Issue 6 The DESCRIPTION is updated to allow for traditional behavior for years before the adoption of the Gregorian calendar. _____________________________ There is no default format specified, only what cal(1) shall be capable of. There is a similar requirement for Julian placed on date(1). Coreutils date command not only defaults to proleptic Gregorian, but doesn't have any Julian capability. So I think having cal(1) default to proleptic Gregorian is not only allowed by POSIX, but it should be expected to correlate with date(1). > > Karel > ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2017-12-21 17:33 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2017-12-19 13:29 v2.32 cal(1) Karel Zak 2017-12-20 2:32 ` [PATCH] cal: add --iso and --1782-reform format options J William Piggott 2017-12-21 14:13 ` Karel Zak 2017-12-21 17:33 ` J William Piggott 2017-12-20 16:29 ` v2.32 cal(1) Adam Sampson 2017-12-20 17:42 ` Karel Zak 2017-12-21 2:43 ` J William Piggott
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.