Gregorian

NAME

Date::Calendar::Gregorian - Extending the core class 'Date' with strftime and conversions with other calendars

SYNOPSIS

Here are two ways of printing the date 2020-04-05 in French.

First, without Date::Calendar::Gregorian


use Date::Names;
use Date::Calendar::Strftime;

my Date        $date   .= new('2020-04-05');
my Date::Names $locale .= new(lang => 'fr');

my $day   = $locale.dow($date.day-of-week);
my $month = $locale.mon($date.month);
$date does Date::Calendar::Strftime;

say $date.strftime("$day %d $month %Y");
# --> dimanche 05 avril 2020

Second, with Date::Calendar::Gregorian


use Date::Calendar::Gregorian;
my  Date::Calendar::Gregorian $date .= new('2020-04-05', locale => 'fr');
say $date.strftime("%A %d %B %Y");
# --> dimanche 05 avril 2020

Another topic, conversion with a calendar, in this case, a calendar which defines days as sunset-to-sunset


use Date::Calendar::Strftime;
use Date::Calendar::Gregorian;
use Date::Calendar::Hebrew;
my  Date::Calendar::Gregorian $d-gr;
my  Date::Calendar::Hebrew    $d-he;

$d-gr .= new(year => 2024, month => 11, day => 13, daypart => before-sunrise());
$d-he .= new-from-date($d-gr);
say $d-he.strftime("%A %d %B %Y");
# ---> "Yom Reviʻi 12 Heshvan 5785"

$d-gr .= new(year => 2024, month => 11, day => 13, daypart => daylight());
$d-he .= new-from-date($d-gr);
say $d-he.strftime("%A %d %B %Y");
# ---> "Yom Reviʻi 12 Heshvan 5785" again

$d-gr .= new(year => 2024, month => 11, day => 13, daypart => after-sunset());
$d-he .= new-from-date($d-gr);
say $d-he.strftime("%A %d %B %Y");
# ---> "Yom Chamishi 13 Heshvan 5785" instead of "Yom Reviʻi 12 Heshvan 5785"

DESCRIPTION

Date::Calendar::Gregorian is a child class to the core class 'Date', to extend it with the string-generation method strftime and with the conversion methods new-from-date and to-date.

The core class Date is very good at number crunching and date computations, but it lacks facilities with string generation. This module, which invokes the Date::Calendar::Strftime, glues together the core class Date and the utility module Date::Names.

In addition, this class declares methods to convert dates from / to other Date::Calendar::xxx classes.

For the documentation of most methods and functions, see the documentation of Date. Here are the new ones.

Constructors

new-from-date

Build a Gregorian date by cloning an object from another class. This other class can be the core class Date (but why would you convert a Gregorian date into Gregorian?) or any Date::Calendar::xxx class with a daycount method and hopefully a daypart method.

This method does not allow a locale build parameter. The object is built with the default locale, 'en'.

new

Actually, new is the constructor for the parent core class Date. Yet, every form of this multi-method accepts a locale parameter. All the variants below gives the same date, with different locales:


use Date::Calendar::Gregorian;
my Date::Calendar::Gregorian $d1 .= new('2020-02-02'                        , locale => 'fr');
my Date::Calendar::Gregorian $d2 .= new( 2020, 2, 2                         , locale => 'es');
my Date::Calendar::Gregorian $d3 .= new(year => 2020, month => 2, day => 2  , locale => 'de');
my Date::Calendar::Gregorian $d4 .= new(Instant.from-posix(1580602000)      , locale => 'it');
my Date::Calendar::Gregorian $d5 .= new(DateTime.new('2020-02-02T12:00:00Z'), locale => 'nl');

The new method accepts also a daypart parameter, in case the date would be converted to a calendar in which the days are defined as sunset-to-sunset. All five variants of the new method accept this daypart parameter.


use Date::Calendar::Strftime;
use Date::Calendar::Gregorian;
my Date::Calendar::Gregorian $d1 .= new('2020-02-02'                        , daypart => before-sunrise);
my Date::Calendar::Gregorian $d2 .= new( 2020, 2, 2                         , daypart => daylight()    );
my Date::Calendar::Gregorian $d3 .= new(year => 2020, month => 2, day => 2  , daypart => after-sunset());
my Date::Calendar::Gregorian $d4 .= new(Instant.from-posix(1580602000)      , daypart => before-sunrise);
my Date::Calendar::Gregorian $d5 .= new(DateTime.new('2020-02-02T22:00:00Z'), daypart => daylight()    );

Please note that in the last two variants, the module ignores the timepart from the Instant instance and the substring "T22:00:00Z" from the DateTime.new parameter.

Accessors

daycount

The MJD (Modified Julian Date) number for the date.

daypart

A number indicating which part of the day. This number should be filled and compared with the following subroutines, with self-documenting names:

  • before-sunrise()

  • daylight()

  • after-sunset()

locale

The two-char string defining the locale used for the date. Use any value allowed by the module Date::Names.

This attribute can be updated after build time.

month-name

The month of the date, as a string. This depends on the date's current locale.

month-abbr

The abbreviated month of the date.

Depending on the locale, it may be a 3-char string, a 2-char string or a short string of variable length. Please refer to the documentation of Date::Names for the availability of mon3, mon2 and mona.

day-name

The name of the day within the week. It depends on the date's current locale.

day-abbr

The abbreviated day name of the date.

Depending on the locale, it may be a 3-char string, a 2-char string or a short code of variable length. Please refer to the documentation of Date::Names for the availability of dow3, dow2 and dowa.

Other Methods

to-date

Clones the date into a Date::Calendar::xxx compatible calendar class. The target class name is given as a positional parameter. This parameter is optional, the default value is "Date" for the Gregorian calendar, which is not very useful in the present case, but which at least does not depend on which modules are installed on your system and is sure to be available.

To convert a date from a calendar to another, you have two conversion styles, a "push" conversion and a "pull" conversion. For example, while converting "1st February 2020" to the French Revolutionary calendar, you can code:


use Date::Calendar::Gregorian;
use Date::Calendar::FrenchRevolutionary;

my  Date::Calendar::Gregorian           $d-orig;
my  Date::Calendar::FrenchRevolutionary $d-dest-push;
my  Date::Calendar::FrenchRevolutionary $d-dest-pull;

$d-orig .= new(year  => 2020
             , month =>    2
             , day   =>    1);
$d-dest-push  = $d-orig.to-date("Date::Calendar::FrenchRevolutionary");
$d-dest-pull .= new-from-date($d-orig);
say $d-orig, ' ', $d-dest-push, ' ', $d-dest-pull;
# --> "2020-02-01 0228-05-13 0228-05-13"

Even if both calendars use a locale attribute, when a date is created by the conversion of another date, it is created with the default locale. If you want the locale to be transmitted in the conversion, you should add a line such as:


$d-dest-pull.locale = $d-orig.locale;

strftime

This method is very similar to the homonymous functions you can find in several languages (C, shell, etc). It also takes some ideas from printf-similar functions. For example


$df.strftime("%04d blah blah blah %-25B")

will give the day number padded on the left with 2 or 3 zeroes to produce a 4-digit substring, plus the substring " blah blah blah ", plus the month name, padded on the right with enough spaces to produce a 25-char substring. Thus, the whole string will be at least 42 chars long.

A strftime specifier consists of:

  • A percent sign,

  • An optional minus sign, to indicate on which side the padding occurs. If the minus sign is present, the value is aligned to the left and the padding spaces are added to the right. If it is not there, the value is aligned to the right and the padding chars (spaces or zeroes) are added to the left.

  • An optional zero digit, to choose the padding char for right-aligned values. If the zero char is present, padding is done with zeroes. Else, it is done wih spaces.

  • An optional length, which specifies the minimum length of the result substring.

  • An optional "E" or "O" modifier. On some older UNIX system, these were used to give the extended or localized version of the date attribute. Here, they rather give alternate variants of the date attribute. Not used with the Gregorian calendar.

  • A mandatory type code.

The allowed type codes are:

%a

The day of week name, abbreviated to 2 or 3 chars.

%A

The full day of week name.

%b

The abbreviated month name.

%B

The full month name.

%d

The day of the month as a decimal number (range 01 to 31).

%e

Like %d, the day of the month as a decimal number, but a leading zero is replaced by a space.

%f

The month as a decimal number (1 to 12). Unlike %m, a leading zero is replaced by a space.

%F

Equivalent to %Y-%m-%d (the ISO 8601 date format)

%G

The "week year" as a decimal number for the so-called "ISO date" format.

%j

The day of the year as a decimal number (range 001 to 366).

%m

The month as a two-digit decimal number (range 01 to 12), including a leading zero if necessary.

%n

A newline character.

%Ep

Gives a 1-char string representing the day part:

  • ☾ or U+263E before sunrise,

  • ☼ or U+263C during daylight,

  • ☽ or U+263D after sunset.

Rationale: in C or in other programming languages, when strftime deals with a date-time object, the day is split into two parts, before noon and after noon. The %p specifier reflects this by giving a "AM" or "PM" string.

The 3-part splitting in the Date::Calendar::xxx may be considered as an alternate splitting of a day. To reflect this in strftime, we use an alternate version of %p, therefore %Ep.

%t

A tab character.

%u

The day of week as a 1..7 number.

%V

The week number in the so-called "ISO date" format.

%Y

The year as a decimal number.

%%

A literal `%' character.

ISSUES

Mutability

In the parent class, objects are immutable. You cannot change a "Sunday 5 April 2020" Date object into "Monday 6 April 2020". In this class, objects are no longer completely immutable. You still cannot change a "Sunday 5 April 2020" object into "Monday 6 April 2020", but you can change this "Sunday 5 April 2020" object into "dimanche 5 avril 2020" or "domingo 5 abril 2020".

This may seem no big deal, but in some cases it may prevent some optimisations from being applied or it may enable thread-related bugs. I am no expert on this but I think you cannot blindly change all your uses of Date into uses of Date::Calendar::Gregorian.

Security issues

Another issue, as explained in the Date::Calendar::Strftime documentation. Please ensure that format-string passed to strftime comes from a trusted source. Failing that, the mailcious source could include an outrageous length in a strftime specifier, which would drain your PC's RAM very fast.

Relations with :ver<0.0.x> classes

Version 0.1.0 (and API 1) was introduced to ease the conversions with other calendars in which the day is defined as sunset-to-sunset. If all Date::Calendar::xxx classes use version 0.1.x and API 1, the conversions will be correct. But if some Date::Calendar::xxx classes use version 0.0.x and API 0, there might be problems.

A date from a 0.0.x class has no daypart attribute. But when "seen" from a 0.1.x class, the 0.0.x date seems to have a daypart attribute equal to daylight. When converted from a 0.1.x class to a 0.0.x class, the date may just shift from after-sunset (or before-sunrise) to daylight, or it may shift to the daylight part of the prior (or next) date. This means that a roundtrip with cascade conversions may give the starting date, or it may give the date prior or after the starting date.

Time

This module and the Date::Calendar::xxx associated modules are still date modules, they are not date-time modules. The user has to give the daypart attribute as a value among before-sunrise, daylight or after-sunset. There is no provision to give a HHMMSS time and convert it to a daypart parameter.

SEE ALSO

Raku Software

Date::Names or https://github.com/tbrowder/Date-Names

Date::Calendar::Strftime or https://github.com/jforget/raku-Date-Calendar-Strftime

Date::Calendar::Julian or https://github.com/jforget/raku-Date-Calendar-Julian

Date::Calendar::Hebrew or https://github.com/jforget/raku-Date-Calendar-Hebrew

Date::Calendar::Hijri or https://github.com/jforget/raku-Date-Calendar-Hijri

Date::Calendar::CopticEthiopic or https://github.com/jforget/raku-Date-Calendar-CopticEthiopic

Date::Calendar::FrenchRevolutionary or https://github.com/jforget/raku-Date-Calendar-FrenchRevolutionary

Date::Calendar::MayaAztec or https://github.com/jforget/raku-Date-Calendar-MayaAztec

Date::Calendar::Persian or https://github.com/jforget/raku-Date-Calendar-Persian

Date::Calendar::Bahai or https://github.com/jforget/raku-Date-Calendar-Bahai

Perl 5 Software

DateTime

Date::Convert

Date::Converter

Other Software

date(1), strftime(3)

calendar/calendar.el in emacs or xemacs.

CALENDRICA 4.0 -- Common Lisp, which can be download in the "Resources" section of https://www.cambridge.org/us/academic/subjects/computer-science/computing-general-interest/calendrical-calculations-ultimate-edition-4th-edition?format=PB&isbn=9781107683167 (Actually, I have used the 3.0 version which is not longer available)

Books

Calendrical Calculations (Third or Fourth Edition) by Nachum Dershowitz and Edward M. Reingold, Cambridge University Press, see http://www.calendarists.com or https://www.cambridge.org/us/academic/subjects/computer-science/computing-general-interest/calendrical-calculations-ultimate-edition-4th-edition?format=PB&isbn=9781107683167.

La saga des calendriers, by Jean Lefort, published by Belin (Pour la Science), ISBN 2-90929-003-5 See https://www.belin-editeur.com/la-saga-des-calendriers (the website seems to no longer respond).

Le Calendrier, by Paul Couderc, published by Presses universitaires de France (Que sais-je ?), ISBN 2-13-036266-4 See https://catalogue.bnf.fr/ark:/12148/cb329699661.

Internet

https://www.tondering.dk/claus/calendar.html - Claus Tøndering's calendar FAQ, especially the page https://www.tondering.dk/claus/cal/gregorian.php.

AUTHOR

Jean Forget <J2N-FORGET at orange dot fr>

COPYRIGHT AND LICENSE

Copyright (c) 2020, 2021, 2024 Jean Forget

This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.

Date::Calendar::Gregorian v0.1.0

Extending the core class 'Date' with strftime and conversions with other calendars

Authors

  • Jean Forget

License

Artistic-2.0

Dependencies

Date::NamesDate::Calendar::Strftime

Test Dependencies

Provides

  • Date::Calendar::Gregorian

Documentation

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

Built with Podlite — the markup and publishing tools behind this site.