# -*- encoding: utf-8; indent-tabs-mode: nil -*-

=begin pod

=head1 Designer's Notes

=head2 Preliminary

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
  Abib 7, 1735
  Hamle 7, 2011
  13.0.6.11.16, 8 Cib, 4 Xul

=head2 Purposes

The various calendar module should obey the following contradictory
purposes:

=item A user can use as many or as few calendar as he wants. He can
use none or all of them.

=item Limit code duplication. Prefer DRY (Don't Repeat Yourself) over WET
(Write Everything Twice).

=item No alteration to the core modules, including C<Date>.

=head2 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 C<Date>, all others are roles
to C<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 C<Tammuz>, C<Dhu al-Qada> or C<Messidor>?
Granted, after reading pages 226 and following of I<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 C<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.

=head2 Taking a look at C<Date>

I did not bother to deal with times, so I will look at the 
C<Date> core module instead of C<DateTime>.

=head3 Day-Only Counting

The first difference with Perl 5's C<DateTime> is that Perl 6's C<Date>
uses the MJD or Modified Julian Day Number instead of I<Rata Die>.
Fine with me.

=head3 Immutability

A second difference with Perl 5's C<DateTime>
is that dates are immutable. Why not? It does not bother me.
Therefore dates in a C<Date::Calendar::>R<Whatever> module will be
immutable too (but see below for multilingual distributions).

=head3 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 CPAN6 module
C<Date::Names>.

=head2 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.

=head3 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
C<Date::Calendar::Hebrew> distribution will include both the
C<Date::Calendar::Hebrew> module and the
C<Date::Calendar::Hebrew::Names> module.

So we will have:

  class    Date::Calendar::Hebrew
  routines Date::Calendar::Hebrew::Names

=head3 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
C<Date::Calendar::>R<Whatever>C<::Names>  module,  or I  may  separate
them with  the mechanisms  in C<Date::Calendar::>R<Whatever>C<::Names>
and    the   data    in   C<Date::Calendar::>R<Whatever>C<::Names::en>
C<Date::Calendar::>R<Whatever>C<::Names::fr>,
C<Date::Calendar::>R<Whatever>C<::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
C<Date::Calendar::>R<Whatever> objects will have a C<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.

=head2 Calendars with variants

=head3 French Revolutionary Calendar

There are two ways of computing the change of a year to the
next in the  French Revolutionary Calendar: either the first day
of the year is the autumn equinox, or the length of each year is 365
or 366 and computed with an algorithm similar to the Gregorian
algorithm. Historically, the  French Revolutionary Calendar began
with the astronomical rule and a reform to adopt the arithmetic rule
was scheduled for year XX (Gregorian year 1811).

So we can define three variants.

=item the astronomical variant, where the first day is always on
the autumn equinox, even after year XX,

=item the arithmetic variant, where the year length is computed
with Gregorian-like moduloes, event before year XX,

=item and the historical variant, which takes into account
the year XX reform and the change of rule.

How does this translate in Perl 6?

A first idea is to define three different functions or methods to
translate an other date into French Revolutionary Calendar
and also three  different functions or methods to
translate an French Revolutionary date into another calendar.

This is a bad idea. What happens if the other calendar has also three
variants, like the Mayan calendar? Should we define 9 functions/ methods
for each direction?

A second idea is defining only one function or method in each direction,
using a parameter giving which variant to use. In the case of the
French Revolutionary → Mayan conversion, we would have two parameters,
the C<from_variant> parameter and the C<to_variant> parameter. These
parameters would be optional and, in the cas of variantless calendars,
ignored.

This does not work either. Suppose we want to translate 22 Septembre 1795
to French Revolutionary using the astronomical variant and then back
to Gregorian using the arithmetic variant. The first step would result in
"sextidi 6 sans-culottide III" (sixth additional day, which means that
this is a leap year), and the second step would fail because according
to the arithmetic rule, year III is a normal year, with only 5 additional
days.

A third possibility is adding a  C<variant> attribute to the  French Revolutionary Calendar
class to keep track of the variant used when creating the date object.
In this cas, the "here and back again" conversion will no longer be able
to use two different variants. It will just add some code in the module
to dispatch between variants of the "French Revolutionary Calendar to
other" conversion functions. Not a problem to the module user, just some
more code to write for the module author / maintainer (me).

A fourth  possibility consists  in storing this  information not  in a
attribute,  but directly  in the  object's  metadata, I  mean, in  the
class. In other words, I define three different classes for the French
Revolutionary Calendar, one  per variant. With that, the  burden is no
longer  on  the  module  writer  / maintainer,  but  on  the  dispatch
mechanism  coded in  the Perl  6 interpreter.  Yet, the  three classes
would contain much duplicated code.  To prevent code duplication, this
code will  be written  in a role  used by the  three classes.  Thus we
have:

=item1 Three classes

=item2  Date::Calendar::FrenchRevolutionary
=item2  Date::Calendar::FrenchRevolutionary::Astronomical
=item2  Date::Calendar::FrenchRevolutionary::Arithmetic

=item1 One role

=item2  Date::Calendar::FrenchRevolutionary::Common

=item1 One procedural module

=item2  Date::Calendar::FrenchRevolutionary::Names

This is the possibility I have adopted.

Note that the shortest name is given to the main variant, which will
certainly be the most often used variant.

Actually, there is even a fifth possibility, which merges possibilities 3 and
4. Each one of the three classes has a C<algorithm> method which returns
a constant result, which will be  C<"historic">, C<"astronomical">
or C<"arithmetic"> depending on the class. If I think it can be useful,
I will switch to this possibility.

=head3 Coptic and Ethiopic Calendars

The Coptic and Ethiopic calendars are very simple calendars, sharing a
common structure:

=item1 12 months of 30 days each
=item1 followed by 5 or 6 additional days, called I<epagomenal days>.

Leap years are years  multiple of 4, no matter if they  are at the end
of a century or not.

There are two differences between these calendars:

=item1 Obviously, months and days have different names.

=item1 The conversion  with other calendars is not the  same. In other
words, the Gregorian date for Coptic 0001-01-01 is not the same as the
Gregorian date for Ethiopic 0001-01-01.

But there  are still  many common points,  which suggest  code sharing
between the two modules. So we will have:

=item1 Two classes

=item2  Date::Calendar::Coptic
=item2  Date::Calendar::Ethiopic

=item1 One role

=item2  Date::Calendar::CopticEthiopic (no need to add C<"::Common">)

=item1 Two procedural modules

=item2  Date::Calendar::Coptic::Names
=item2  Date::Calendar::Ethiopic::Names

The only remaining point is the  name of the distribution. There is no
reason  to call  it after  the Coptic  calendar while  belittleing the
Ethiopic calendar.  And vice-versa. So  the distribution name  will be
C<Date::Calendar::CopticEthiopic>.

=head3 Mayan Calendar and Aztec Calendar

The case of the Mayan Calendar  is similar to the French Revolutionary
calendar, because there  are several ways to convert  dates between it
and the Gregorian calendar. It is also similar to the Coptic calendar,
because it shares  many mechanisms with the Aztec  calendar, just like
the Coptic calendar shares manu mechanisms with the Ethiopic calendar.

Pedants  will argue  that  there  is not  I<one>  Mayan calendar,  but
I<three>:

=item the  long count, using  embedded cycles  of length 20  (with one
exception)  and   usually  displayed   in  a  dotted   notation,  e.g.
13.0.6.11.16

=item the clerical calendar, or Tzolkin,  which combines a cycle of 13
numbers with a cycle of 20 names, e.g. 8 Cib

=item the  common calendar,  or Haab, consisting  of 18  named months,
each with 20 numbered days, plus 5 additional days. E.g. 4 Xul

So the various date converters deal with the "Mayan calendars system",
with an  "s" to  "calendars", but to  streamline the  explanations, we
will talk about the Mayan calendar (with no "s").

It  is the  same, only  simpler, with  the Aztec  calendar. This  is a
two-calendar system,  with a  clerical calendar,  or I<tonalpohualli>,
similar to Tzolkin, and a  common calendar, or I<xiupohualli>, similar
to Haab. Aztecs had nothing ressembling the Mayans' long count.

For the conversion from Gregorian (or  other) to Mayan or Aztec, there
are three opinions from the specialists: the Alfonso Caso method, with
or without H.B. Nicholson's adjustment, or Francisco Cortes's method.

To be continued

=head1 License

This  text is  licensed  under  the terms  of  Creative Commons,  with
attribution and share-alike (CC-BY-SA).

=end pod
