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).

Date::Calendar::Hebrew v0.1.0

Conversions from / to the Hebrew calendar

Authors

  • Jean Forget

License

Artistic-2.0

Dependencies

List::MoreUtilsDate::Calendar::Strftime

Test Dependencies

Provides

  • Date::Calendar::Hebrew
  • Date::Calendar::Hebrew::Names

The Camelia image is copyright 2009 by Larry Wall. "Raku" is trademark of the Yet Another Society. All rights reserved.