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

=begin pod

=head1 Notes du concepteur

=head2 Préliminaire

Ce texte détaille les notes de conception pour le module de calendrier
hébraïque. Une  version complète  figure dans  la distribution  Perl 6
pour le module de calendrier républicain.

Il  est  préférable de  faire  référence  à  des exemples  plutôt  que
d'utiliser  des données  génériques. Pour  ce faire,  j'utiliserai les
dates suivantes (le 14 juillet de cette année) :

  Dimanche 14 juillet 2019
  Sunday 14 July 2019
  11 Tammuz 5779
  11 Dhu al-Qada 1440
  Sextidi 26 Messidor 227
  13.0.6.11.16, 8 Cib, 4 Xul

=head2 Buts

Les modules de calendrier doivent tendre vers ces buts contradictoires :

=item Un utilisateur peut décider de charger autant de modules qu'il
souhaite. Il peut tous les utiliser ou n'utiliser aucun module outre
le module central C<Date>.

=item Limiter autant que possible la duplication de code. Plutôt DRY
(I<Don't Repeat Yourself>, Ne vous répétez pas) que WET
(I<Write Everything Twice>, Tout écrire deux fois).

=item Ne pas toucher aux modules standards, y compris C<Date>.

=head2 Première idée : des rôles partout

Ma première idée était d'utiliser de manière intensive la nouveauté
de Perl 6 en programmation objet, les rôles. Seul le calendrier grégorien
serait implémenté en tant que classe, les autres calendriers seraient
des rôles accolés à la classe C<Date>. Par exemple :

  my Date $quatorze-juillet does Date::Calendar::Hebrew
                            does Date::Calendar::Hijri
                            does Date::Calendar::FrenchRevolutionary
                            does Date::Calendar::Mayan
            .= new(year => 2019, month => 7, day => 14);

Le premier problème est le conflit de nom entre les méthodes des
divers rôles. Si nous codons :

  say $quatorze-juillet.month-name

obtiendrons-nous C<Tammuz>, C<Dhu al-Qada> ou C<Messidor> ?
D'accord, il suffit de lire la page 226 et les suivantes de 
I<Learning Perl 6> et l'on apprend que l'on peut écrire :

  say $quatorze-juillet.month-name( Date::Calendar::FrenchRevolutionary );
  # → Messidor
  say $quatorze-juillet.month-name( Date::Calendar::Hebrew );
  # → Tammuz

Mais c'est laborieux.

Le second problème est que le concept  de date n'est pas le même d'une
civilisation  à  l'autre. Le  calendrier  grégorien  et le  calendrier
républicain  utilisent des  dates de  minuit  à minuit,  alors que  le
calendrier  hébraïque, le  calendrier  islamique  et plusieurs  autres
utilisent  des dates  du  coucher  du soleil  au  coucher suivant.  Le
I<Julian Day Number> (à ne pas confondre avec le calendrier julien) se
base sur des dates de midi à  midi. Et il n'est pas exclu que d'autres
calendriers définissent les dates comme  s'étendant du lever du soleil
au lever suivant du soleil. On  peut donc assimiler le 14 juillet 2019
au 26  Messidor 227, mais pas  au 11 Tammuz 5579.  Habituellement, les
programmes de conversion s'en tirent en écrivant dans la documentation
utilisateur que  la conversion 14  juillet 2019  → 11 Tammuz  5779 est
valide  avant le  coucher  du  soleil. Mais  il  pourrait  y avoir  un
programmeur  un peu  plus  aventureux qui  coderait  deux routines  de
conversion ou qui  ajouterait un paramètre « moment de  la journée » à
sa routine de conversion pour obtenir soit :

  14 juillet 2019 → 11 Tammuz 5779

soit :

  14 juillet 2019 → 12 Tammuz 5779

En implémentant  le calendrier hébraïque  en tant que rôle  affecté au
calendrier   grégorien,  cette   possibilité  n'existerait   plus.  En
implémentant le  calendrier hébraïque en  tant que classe  séparée, la
possibilité reste ouverte.  Il reste des problèmes à  résoudre dans ce
cas, mais au moins nous ne sommes pas bloqués.

Pendant  que  j'écrivais le  module  de  calendrier républicain,  j'ai
trouvé  un argument  supplémentaire. L'utilisation  d'années négatives
(ou av J.C.) est justifiée pour  le calendrier julien et le calendrier
grégorien  (même en  considérant que  le calendrier  grégorien a  pris
effet  le 15  octobre  1582), ce  n'est  pas le  cas  pour les  autres
calendriers. Ainsi, le calendrier républicain a pour origine des temps
le  22 septembre  1792 et  il n'y  a alors  aucune raison  d'autoriser
l'objet 21 septembre 1792 à utiliser les méthodes du rôle « calendrier
républicain ».

La solution est donc : un calendrier = une classe.

=head2 Examen du module standard C<Date>

Je  n'avais  pas  l'intention  de traiter  les  heures  (décimales  ou
24×60×60) donc j'ai seulement regardé C<Date>, pas C<DateTime>.

=head3 Échelle de temps en jours

La première différence entre le module  C<Date> de Perl 6 et le module
C<DateTime> de Perl 5 est que Perl 6 utilise le MJD (I<Modified Julian
Day Number>) au lieu d'utiliser le I<Rata Die>. Cela me va très bien.

=head3 Immutabilité

Une deuxième  différence avec le  module C<DateTime> de Perl  5, c'est
que les dates  ne sont pas modifiables.  Et pourquoi pas ?  Cela ne me
dérange pas.  Donc les dates dans  C<Date::Calendar::>R<xxx> ne seront
pas modifiables. Voir cependant ci-dessous le cas d'un calendrier avec
plusieurs langues.

=head3 Affichage en langage naturel

Une autre différence avec  Perl 5, c'est qu'il n'y a  rien de prévu en
standard pour  afficher du  langage naturel, essentiellement  les noms
des  jours  et  les  noms   des  mois.  Peut-être  a-t-on  estimé  que
l'utilisation  principale du  module  C<Date>  serait la  constitution
d'horaires ou la planification de tâches,  ce qui ne nécessite que les
valeurs numériques des jours et des mois, pas les noms en clair.

Et  si vous  avez quand  même besoin  des noms  en clair,  vous pouvez
installer et utiliser C<Date::Names> disponible sur CPAN6.

=head2 Calendrier simple

Comme  exemple  de  calendrier   simple,  je  prendrai  le  calendrier
hébraïque. La  simplicité concerne  l'architecture du module,  pas les
algorithmes de conversion. Il n'y a pas de variante pour le calendrier
hébraïque, donc de ce point de vue c'est un calendrier simple.

=head3 Calendrier avec une seule langue

À mon  avis, si quelqu'un  utilise un  module de calendrier  autre que
grégorien, c'est pour  afficher la date convertie, pas  pour faire des
calculs de  délai ou planifier  des tâches.  Les noms en  clair seront
dans un module séparé, mais ce module séparé fera partie intégrante de
la  distribution.  Ainsi,  la  distribution  C<Date::Calendar::Hebrew>
incluera à  la fois le  module C<Date::Calendar::Hebrew> et  le module
C<Date::Calendar::Hebrew::Names>.

En résumé, nous avons dans ce cas :

  classe   Date::Calendar::Hebrew
  routines Date::Calendar::Hebrew::Names

=head3  Calendrier avec plusieurs langues

Si les noms sont disponibles dans plusieurs langages pour un même
calendrier, je peux dans certains cas tout mettre dans un même module
C<Date::Calendar::>R<xxx>C<::Names>, mécanisme et données, ou bien je peux
scinder cela en mettant le mécanisme dans
C<Date::Calendar::>R<xxx>C<::Names> et les données dans
C<Date::Calendar::>R<xxx>C<::Names::en>, C<Date::Calendar::>R<xxx>C<::Names::fr>,
C<Date::Calendar::>R<xxx>C<::Names::it> et ainsi de suite. Tout dépendra
de la taille.

Pour le calendrier hébraïque, avec  l'hébreu, le yiddish et l'araméen,
cela donnerait :

  classe   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

(Désolé, l'araméen n'a pas de code  ISO 639 à deux caractères, j'ai dû
me rabattre sur le code à trois caractères.)

Un  autre  point est  que  dans  le  cas  où plusieurs  langages  sont
disponibles,  l'objet   C<Date::Calendar::>R<xxx>  aura   un  attribut
C<locale> et l'utilisateur pourra alors faire varier cet attribut pour
afficher une même  date dans plusieurs langues. Même  si les attributs
année,  mois  et  jour  sont  invariants,  l'attribut  C<locale>  sera
modifiable.  Et l'objet  ne sera  plus  totalement «  immutable ».  En
prenant un exemple  tiré du calendrier républicain,  changer « Sextidi
26 Messidor 227, jour  de la sauge » en « Sixday  26 Reapidor 227, day
of  sage  »  est  une  modification  cosmétique  et  superficielle  de
l'instance de  date, changer «  Sextidi 26 Messidor  227 , jour  de la
sauge»  en  «  Septidi 27  Messidor  227,  jour  de  l'ail »  est  une
modification profonde et essentielle de l'instance.


=head2 Calendriers avec variantes

Dans le but de rester simple, le présent texte n'ira pas plus loin
et laissera de côté le cas plus compliqué des calendriers avec
variantes. Veuillez vous référer à la distribution
C<Date::Calendar::FrenchRevolutionary> qui contient la version
complète du présent texte.

=head1 Licence

Texte  diffusé  sous  la  licence CC-BY-SA  :  Creative  Commons  avec
attribution, partage dans les mêmes conditions.

=end pod
