All of lore.kernel.org
 help / color / mirror / Atom feed
* 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: 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

* 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

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.