notes-en
# -*- encoding: utf-8; indent-tabs-mode: nil -*-
Designer's Notes
Preliminary
This text presents the designer's notes for the Hebrew calendar module. A more complete text is available in the distribution for the French Revolutionary calendar.
It is better to work with actual examples rather than generic values. So in the text below, I will use the following dates (Bastille day this year):
Sunday 14 July 2019
11 Tammuz 5779
11 Dhu al-Qada 1440
Sextdi 26 Messidor 227
13.0.6.11.16, 8 Cib, 4 Xul
Purposes
The various calendar module should obey the following contradictory purposes:
A user can use as many or as few calendar as he wants. He can use none or all of them.
Limit code duplication. Prefer DRY (Don't Repeat Yourself) over WET (Write Everything Twice).
No alteration to the core modules, including
Date.
First Idea: Roles Everywhere
My first idea was to make intensive use of the novelty in Perl 6 POO, roles.
Only the Gregorian calendar is implemented as a class Date, all others are roles
to Date. Example:
my Date $bastille-day does Date::Calendar::Hebrew
does Date::Calendar::Hijri
does Date::Calendar::FrenchRevolutionary
does Date::Calendar::Mayan
.= new(year => 2019, month => 7, day => 14);
The first problem is the conflict between the methods of the various roles. If we use
say $bastille-day.month-name
should we get Tammuz, Dhu al-Qada or Messidor?
Granted, after reading pages 226 and following of Learning Perl 6,
you can write;
say $bastille-day.month-name( Date::Calendar::FrenchRevolutionary );
# β Messidor
say $bastille-day.month-name( Date::Calendar::Hebrew );
# β Tammuz
but it is cumbersome.
The second problem is that the concept of date is not the same across different
civilizations. The Gregorian and French Revolutionary calendars use midnight-to-midnight
dates, while the Hijri and Hebrew calendars (and others) use sunset-to-sunset dates.
The Julian Day Number calendar (not to be confused with the Julian calendar) uses
noon-to-noon dates.
And it is possible that some other calendars use sunrise-to-sunrise dates. So, while
you can equate 14 July 2019 to 26 Messidor 227, you cannot equate it to 11 Tammuz
5779. Usually, date conversion programs take the lazy path and mention in their documentation that
the correspondance 14 July 2019 β 11 Tammuz 5779 is valid only until sunset,
but we can imagine a hubristic programmer who would use two conversion routines
or add a time-of-day parameter to the conversion routine to get either
14 July 2019 β 11 Tammuz 5779
or
14 July 2019 β 12 Tammuz 5779
With the Hebrew calendar as a role, that would not be possible, with the Hebrew calendar as a class, that would be possible. There are still a few problems, but at least we are not painted out in a corner.
I found another reason when writing the French Revolutionary module. While there are reasons to allow negative years (or BC years) for the Julian and Gregorian calendars (even when considering that the Gregorian calendar took effect on 15 October 1582), there is no reason to take into account dates before the epochs of the other calendars. For example, the French Revolutionary calendar's epoch is 22 September 1792, so the 21 September 1792 object should not be allowed to use the FrenchRevolutionary role's methods.
So the solution is: one calendar = one class.
Taking a look at Date
I did not bother to deal with times, so I will look at the
Date core module instead of DateTime.
Day-Only Counting
The first difference with Perl 5's DateTime is that Perl 6's Date
uses the MJD or Modified Julian Day Number instead of Rata Die.
Fine with me.
Immutability
A second difference with Perl 5's DateTime
is that dates are immutable. Why not? It does not bother me.
Therefore dates in a Date::Calendar::Whatever module will be
immutable too (but see below for multilingual distributions).
Localization
Another difference with Perl 5 is that there is no provision for localized string values: month names and the like. Maybe it was thought that the main purpose of this module would be to manage schedules, timetables and the like, for which we need the numerical values of the days and months but not their string localized values.
For those interested in localized values, there is the zef / CPAN6
module Date::Names.
Simple Calendars
As a simple calendar example, I will consider the Hebrew Calendar. In this discussion, simplicity is about the module architecture, not the conversion algorithms. So, with this point of view, the Hebrew calendar, with no variants, is a simple calendar.
Calendar with one Locale
In my opinion, calendar modules will be used to display dates, not to
build schedules with them. I will keep the names in a separate module,
but this module will be within the distribution. For example, the
Date::Calendar::Hebrew distribution will include both the
Date::Calendar::Hebrew module and the
Date::Calendar::Hebrew::Names module.
So we will have:
class Date::Calendar::Hebrew
routines Date::Calendar::Hebrew::Names
Calendar with Several Locales
If there are different languages and different localizations for a
given calendar, I may put the mechanisms and all the data in the same
Date::Calendar::Whatever::Names module, or I may separate
them with the mechanisms in Date::Calendar::Whatever::Names
and the data in Date::Calendar::Whatever::Names::en
Date::Calendar::Whatever::Names::fr,
Date::Calendar::Whatever::Names::it and others. It will
depend on the size.
In the case of the Hebrew calendar and the Hebrew, Yiddish and Aramaic languages, we would have:
class Date::Calendar::Hebrew
routines Date::Calendar::Hebrew::Names
routines Date::Calendar::Hebrew::Names::he
routines Date::Calendar::Hebrew::Names::yi
routines Date::Calendar::Hebrew::Names::arc
(Sorry, there is no 2-char ISO 639 code for Aramaic, so I have to fall back to the 3-char code.)
Another point with multi-localization is that the
Date::Calendar::Whatever objects will have a locale attribute
and this attribute will be read-write. The year, month and day
attributes will still be readonly, but the locale will be read-write.
So the object is not fully immutable. Using the French Revolutionary
calendar as an example, changing "Sextidi 26 Messidor 227, jour de la
sauge" into "Sixday 26 Reapidor 227, day of sage" is just a skin-deep
cosmetic modification, while changing "Sextidi 26 Messidor 227, jour
de la sauge" into "Septidi 27 Messidor 227, jour de l'ail" is a deep
modification of the date's inner self.
Calendars with variants
Please refer to the Date::Calendar::FrenchRevolutionary distribution,
which contains the full version of the present text.
License
This text is licensed under the terms of Creative Commons, with attribution and share-alike (CC-BY-SA).