1# -*- encoding: utf-8; indent-tabs-mode: nil -*-
2#
3# Perl DateTime extension for converting to/from the French Revolutionary calendar
4# Copyright (c) 2003, 2004, 2010, 2011, 2012, 2014, 2016, 2019, 2021 Jean Forget. All rights reserved.
5#
6# See the license in the embedded documentation below.
7#
8
9package DateTime::Calendar::FrenchRevolutionary;
10
11use utf8;
12use strict;
13use warnings;
14
15use vars qw($VERSION);
16$VERSION = '0.17';
17
18use Params::Validate qw(validate SCALAR BOOLEAN OBJECT);
19use Roman;
20use DateTime;
21use DateTime::Calendar::FrenchRevolutionary::Locale;
22
23my $BasicValidate =
24    { year   => { type => SCALAR },
25      month  => { type => SCALAR, default => 1,
26                  callbacks =>
27                  { 'is between 1 and 13' =>
28                    sub { $_[0] >= 1 && $_[0] <= 13 }
29                  },
30                },
31      day    => { type => SCALAR, default => 1,
32                  callbacks =>
33                  { 'is between 1 and 30' =>
34                    sub { $_[0] >= 1 && $_[0] <= 30 },
35                  },
36                },
37      hour   => { type => SCALAR, default => 0,
38                  callbacks =>
39                  { 'is between 0 and 9' =>
40                    sub { $_[0] >= 0 && $_[0] <= 9 },
41                  },
42                },
43      minute => { type => SCALAR, default => 0,
44                  callbacks =>
45                  { 'is between 0 and 99' =>
46                    sub { $_[0] >= 0 && $_[0] <= 99 },
47                  },
48                },
49      second => { type => SCALAR, default => 0,
50                  callbacks =>
51                  { 'is between 0 and 99' =>
52                    sub { $_[0] >= 0 && $_[0] <= 99 },
53                  },
54                },
55      abt_hour   => { type => SCALAR, default => 0,
56                  callbacks =>
57                  { 'is between 0 and 23' =>
58                    sub { $_[0] >= 0 && $_[0] <= 23 },
59                  },
60                },
61      abt_minute => { type => SCALAR, default => 0,
62                  callbacks =>
63                  { 'is between 0 and 59' =>
64                    sub { $_[0] >= 0 && $_[0] <= 59 },
65                  },
66                },
67      abt_second => { type => SCALAR, default => 0,
68                  callbacks =>
69                  { 'is between 0 and 61' =>
70                    sub { $_[0] >= 0 && $_[0] <= 61 },
71                  },
72                },
73      nanosecond => { type => SCALAR, default => 0,
74                      callbacks =>
75                      { 'cannot be negative' =>
76                        sub { $_[0] >= 0 },
77                      }
78                    },
79      locale    => { type => SCALAR | OBJECT,
80                      callbacks =>
81                      { "only 'fr', 'en', 'es' and 'it' possible" =>
82                        sub { ($_[0] eq 'fr') or ($_[0] eq 'en')
83                                              or ($_[0] eq 'es')
84                                              or ($_[0] eq 'it')
85                                              or ref($_[0]) =~ /(?:en|es|fr|it)$/ },
86                      },
87                     default => DefaultLocale() },
88    };
89
90my $NewValidate =
91    { %$BasicValidate,
92      time_zone => { type => SCALAR | OBJECT,
93                      callbacks =>
94                      { "only 'floating' possible" =>
95                        sub { ($_[0] eq 'floating') or ref($_[0]) and $_[0]->is_floating },
96                      },
97                     default => 'floating' },
98    };
99my $Lastday_validate = { %$BasicValidate };
100delete $Lastday_validate->{day};
101
102# Constructors
103sub new {
104    my $class = shift;
105    my %args = validate( @_, $NewValidate );
106
107    my $self = {};
108
109    $self->{tz} = DateTime::TimeZone->new(name => 'floating');
110    if ( ref $args{locale} )
111      { $self->{locale} = $args{locale} }
112    else
113      { $self->{locale} = DateTime::Calendar::FrenchRevolutionary::Locale->load( $args{locale} ) }
114
115    $self->{local_rd_days} = $class->_ymd2rd(@args{qw(year month day)});
116    my $abtsecs = $class->_time_as_abt_seconds(@args{qw(abt_hour abt_minute abt_second)});
117    my $decsecs = $class->_time_as_seconds(@args{qw(hour minute second)});
118    warn("You cannot specify both 24x60x60 time and 10x100x100 time when initializing a date")
119        if $^W && $abtsecs && $decsecs;
120    # We prefer decimal time over Anglo-Babylonian time when initializing a date
121    $self->{local_rd_secs} = $decsecs ? $decsecs : $abtsecs;
122    $self->{rd_nano} =  $args{nanosecond};
123
124    bless $self, $class;
125    $self->_calc_local_components;
126    $self->_calc_utc_rd;
127
128    return $self;
129}
130
131sub from_epoch {
132  my $class = shift;
133  my %args = validate( @_,
134                         { epoch => { type => SCALAR },
135                          locale => { type => SCALAR | OBJECT,
136                                      default => $class->DefaultLocale },
137
138                         }
139                       );
140
141  my $date = DateTime->from_epoch(%args);
142  return $class->from_object(object => $date);
143}
144
145# use scalar time in case someone's loaded Time::Piece
146sub now { shift->from_epoch(epoch => (scalar time), @_) }
147
148sub from_object {
149  my $class = shift;
150  my %args = validate(@_,
151                         { object => { type => OBJECT,
152                                       can => 'utc_rd_values',
153                                     },
154                           locale => { type => SCALAR | OBJECT,
155                                      default => $class->DefaultLocale },
156                         },
157                       );
158
159  my $object = delete $args{object};
160  $object = $object->clone->set_time_zone('floating')
161      if $object->can('set_time_zone');
162
163  my ($rd_days, $rd_secs, $rd_nano) = $object->utc_rd_values;
164
165  my %p;
166  @p{ qw(year  month   day) }     = $class->_rd2ymd($rd_days);
167  # ABT seconds preferred over decimal seconds, because of precision loss
168  @p{ qw(abt_hour  abt_minute  abt_second) }  = $class->_abt_seconds_as_components($rd_secs);
169  # nanoseconds are copied, never converted ABT to decimal or reverse
170  $p{nanosecond} = $rd_nano || 0;
171  #@p{ qw(hour minute second) } = $class->_seconds_as_components($rd_secs);
172
173  my $new = $class->new(%p, %args, time_zone => 'floating');
174
175  return $new;
176}
177
178sub last_day_of_month {
179    my $class = shift;
180    my %p = validate( @_, $Lastday_validate);
181    my $day = $p{month} <= 12 ? 30 : $class->_is_leap_year($p{year}) ? 6 : 5;
182    return $class->new(%p, day => $day);
183}
184
185sub clone { bless { %{ $_[0] } }, ref $_[0] }
186
187# Many of the same parameters as new() but all of them are optional,
188# and there are no defaults.
189my $SetValidate =
190    { map { my %copy = %{ $BasicValidate->{$_} };
191            delete $copy{default};
192            $copy{optional} = 1;
193            $_ => \%copy }
194      keys %$BasicValidate };
195sub set
196{
197    my $self = shift;
198    my %p = validate( @_, $SetValidate );
199
200    my %old_p =
201        ( map { $_ => $self->$_() }
202          qw( year month day hour minute second nanosecond locale )
203        );
204
205    my $new_dt = (ref $self)->new( %old_p, %p );
206
207    %$self = %$new_dt;
208
209    return $self;
210}
211
212sub set_time_zone { } # do nothing, only 'floating' allowed
213
214# Internal functions
215use constant REV_BEGINNING  => 654415; # RD value for 1 Vendémiaire I in the Revolutionary calendar
216use constant NORMAL_YEAR    => 365;
217use constant LEAP_YEAR      => 366;
218use constant FOUR_YEARS     =>  4 * NORMAL_YEAR + 1; # one leap year every four years
219use constant CENTURY        => 25 * FOUR_YEARS - 1;  # centuries aren't leap years...
220use constant FOUR_CENTURIES =>  4 * CENTURY + 1;     # ...except every four centuries that are.
221use constant FOUR_MILLENIA  => 10 * FOUR_CENTURIES - 1; # ...except every four millenia that are not.
222
223# number of days between the start of the revolutionary calendar, and the
224# beginning of year n - 1 as long as the equinox rule is in effect
225my @YEARS_BEGINS=    (0, 365, 730, 1096, 1461, 1826, 2191, 2557, 2922, 3287, 3652,
226                   4018, 4383, 4748, 5113, 5479, 5844);
227sub _is_leap_year {
228    my ($self, $year) = @_;
229
230    # Autumn equinox from I to XIX
231    return 1 if ($year == 3) or ($year == 7) or ($year == 11) or ($year == 15);
232    return 0 if ($year < 20);
233
234    # Romme rule from XX on
235    return 0 if $year %    4; # not a multiple of 4 -> normal year
236    return 1 if $year %  100; # a multiple of 4 but not of 100 is a leap year
237    return 0 if $year %  400; # a multiple of 100 but not of 400 is a normal year
238    return 1 if $year % 4000; # a multiple of 400 but not of 4000 is leap
239    return 0; # a multiple of 4000 is a normal year
240}
241
242sub _calc_utc_rd {
243  my $self = shift;
244
245  delete $self->{utc_c};
246
247  if ($self->{tz}->is_utc)
248    {
249      $self->{utc_rd_days} = $self->{local_rd_days};
250      $self->{utc_rd_secs} = $self->{local_rd_secs};
251      return;
252    }
253
254  $self->{utc_rd_days} = $self->{local_rd_days};
255  $self->{utc_rd_secs} = $self->{local_rd_secs} - $self->_offset_from_local_time;
256  _normalize_seconds($self->{utc_rd_days}, $self->{utc_rd_secs}, $self->{rd_nano});
257}
258
259sub _calc_local_rd {
260  my $self = shift;
261
262  delete $self->{local_c};
263
264  # We must short circuit for UTC times or else we could end up with
265  # loops between DateTime.pm and DateTime::TimeZone
266  if ($self->{tz}->is_utc)
267    {
268      $self->{local_rd_days} = $self->{utc_rd_days};
269      $self->{local_rd_secs} = $self->{utc_rd_secs};
270    }
271   else
272    {
273      $self->{local_rd_days} = $self->{utc_rd_days};
274      $self->{local_rd_secs} = $self->{utc_rd_secs} + $self->offset;
275      _normalize_seconds($self->{local_rd_days}, $self->{local_rd_secs});
276    }
277
278    $self->_calc_local_components;
279}
280
281sub _normalize_seconds {
282  my ($d, $s) = @_;
283  my $adj;
284  if ($s < 0)
285    { $adj = int(($s - 86399) / 86400) }
286  else
287    { $adj = int($s / 86400) }
288  $_[0] += $adj;
289  $_[1] -= $adj * 86400;
290}
291
292sub _calc_local_components {
293  my $self = shift;
294  @{ $self->{local_c} }{ qw(year month day day_of_decade day_of_year) }
295        = $self->_rd2ymd($self->{local_rd_days}, 1);
296  @{ $self->{local_c} }{ qw(abt_hour abt_minute abt_second) }
297        = $self->_abt_seconds_as_components($self->{local_rd_secs});
298  @{ $self->{local_c} }{ qw(hour minute second) }
299        = $self->_seconds_as_components($self->{local_rd_secs});
300}
301
302sub _calc_utc_components {
303  my $self = shift;
304  @{ $self->{utc_c} }{ qw(year month day) } = $self->_rd2ymd($self->{utc_rd_days});
305  @{ $self->{utc_c} }{ qw(abt_hour abt_minute abt_second) }
306          = $self->_abt_seconds_as_components($self->{utc_rd_secs});
307  @{ $self->{utc_c} }{ qw(hour minute second) }
308          = $self->_seconds_as_components($self->{utc_rd_secs});
309}
310
311sub _ymd2rd {
312    my ($self, $y, $m, $d) = @_;
313    my $rd = REV_BEGINNING - 1; # minus 1 for the zeroth Vendémiaire
314    $y --;  #get years *before* this year.  Makes math easier.  :)
315    # first, convert year into days. . .
316    if ($y < 0 || $y >= 16) {
317      # Romme rule in effect, or nearly so
318      my $x = int($y/4000);
319      --$x if $y <= 0;
320      $rd += $x * FOUR_MILLENIA;
321      $y  %= 4000;
322      $rd += int($y/400)* FOUR_CENTURIES;
323      $y  %= 400;
324      $rd += int($y/100)* CENTURY;
325      $y  %= 100;
326      $rd += int($y/4)* FOUR_YEARS;
327      $y  %= 4;
328      $rd += $y * NORMAL_YEAR;
329    }
330    else {
331      # table look-up for the programmer-hostile equinox rule
332      $rd += $YEARS_BEGINS[$y];
333    }
334
335    # now, month into days.
336    $rd += 30 * ($m - 1) + $d;
337    return $rd;
338}
339
340sub _rd2ymd {
341    my ($self, $rd, $extra) = @_;
342
343    my $doy;
344    my $y;
345    # note:  years and days are initially days *before* today, rather than
346    # today's date.  This is because of fenceposts.  :)
347    $doy =  $rd - REV_BEGINNING;
348    if ($doy >= 0 && $doy < $YEARS_BEGINS[16]) {
349      $y = scalar grep { $_ <= $doy } @YEARS_BEGINS;
350      $doy -= $YEARS_BEGINS[$y - 1];
351      $doy++;
352    }
353    else {
354      #$doy --;
355      my $x;
356      $x    = int ($doy / FOUR_MILLENIA);
357      --$x  if $doy < 0; # So pre-1792 dates will give something that look about right
358      $y   += $x * 4000;
359      $doy -= $x * FOUR_MILLENIA;
360
361      $x    = int ($doy / FOUR_CENTURIES);
362      $y   += $x * 400;
363      $doy -= $x * FOUR_CENTURIES;
364
365      $x    = int ($doy / CENTURY);
366      $x    = 3 if $x == 4; # last day of the 400-year period; see comment below
367      $y   += $x * 100;
368      $doy -= $x * CENTURY;
369
370      $x    = int ($doy / FOUR_YEARS);
371      $y   += $x * 4;
372      $doy -= $x * FOUR_YEARS;
373
374      $x    = int ($doy / NORMAL_YEAR);
375      # The integer division above divides the 4-year period, 1461 days,
376      # into 5 parts: 365, 365, 365, 365 and 1. This mathematically sound operation
377      # is wrong with respect to the calendar, which needs to divide
378      # into 4 parts: 365, 365, 365 and 366. Therefore the adjustment below.
379      $x    = 3 if $x == 4; # last day of the 4-year period
380      $y   += $x;
381      $doy -= $x * NORMAL_YEAR;
382
383      ++$y; # because of 0-based mathematics vs 1-based chronology
384      ++$doy;
385    }
386    my $d  = $doy % 30 || 30;
387    my $m = ($doy - $d) / 30 + 1;
388    if ($extra)
389      {
390        # day_of_decade, day_of_year
391        my $dod = ($d % 10) || 10;
392        return $y, $m, $d, $dod, $doy;
393      }
394    return $y, $m, $d;
395}
396
397# Aliases provided for compatibility with DateTime; if DateTime switches
398# over to _ymd2rd and _rd2ymd, these will be removed eventually.
399*_greg2rd = \&_ymd2rd;
400*_rd2greg = \&_rd2ymd;
401
402#
403# Accessors
404#
405sub year    { $_[0]->{local_c}{year} }
406
407sub month   { $_[0]->{local_c}{month} }
408*mon = \&month;
409
410sub month_0 { $_[0]->{local_c}{month} - 1 };
411*mon_0 = \&month_0;
412
413sub month_name {
414    my $self = shift;
415    return $self->{locale}->month_name($self);
416    #return $months[$self->month_0]
417}
418
419sub month_abbr {
420    my $self = shift;
421    return $self->{locale}->month_abbreviation($self);
422    #return $months_short[$self->month_0]
423}
424
425sub day_of_month { $_[0]->{local_c}{day} }
426*day  = \&day_of_month;
427*mday = \&day_of_month;
428
429sub day_of_month_0 { $_[0]->{local_c}{day} - 1 }
430*day_0  = \&day_of_month_0;
431*mday_0 = \&day_of_month_0;
432
433sub day_of_decade { $_[0]->{local_c}{day} % 10 || 10 }
434*dod         = \&day_of_decade;
435*dow         = \&day_of_decade;
436*wday        = \&day_of_decade;
437*day_of_week = \&day_of_decade;
438
439sub day_of_decade_0 { ($_[0]->{local_c}{day} - 1) % 10 }
440*dod_0         = \&day_of_decade_0;
441*dow_0         = \&day_of_decade_0;
442*wday_0        = \&day_of_decade_0;
443*day_of_week_0 = \&day_of_decade_0;
444
445sub day_name {
446    my $self = shift;
447    return $self->{locale}->day_name($self);
448    #return $decade_days[$self->day_of_decade_0];
449}
450
451sub day_abbr {
452    my $self = shift;
453    return $self->{locale}->day_abbreviation($self);
454    #return $decade_days_short[$self->day_of_decade_0];
455}
456
457sub day_of_year { $_[0]->{local_c}{day_of_year} }
458*doy = \&day_of_year;
459
460sub day_of_year_0 { $_[0]->{local_c}{day_of_year} - 1 }
461*doy_0 = \&day_of_year_0;
462
463sub feast_short {
464  my ($dt) = @_;
465  return $dt->{locale}->feast_short($dt);
466}
467*feast = \&feast_short;
468
469sub _raw_feast {
470  my ($dt) = @_;
471  return $dt->{locale}->_raw_feast($dt);
472}
473
474sub feast_long {
475  my ($dt) = @_;
476  return $dt->{locale}->feast_long($dt);
477}
478
479sub feast_caps {
480  my ($dt) = @_;
481  return $dt->{locale}->feast_caps($dt);
482}
483
484sub ymd {
485    my ($self, $sep) = @_;
486    $sep = '-' unless defined $sep;
487    return sprintf("%0.4d%s%0.2d%s%0.2d",
488                   $self->year, $sep,
489                   $self->{local_c}{month}, $sep,
490                   $self->{local_c}{day});
491}
492*date = \&ymd;
493
494sub mdy {
495    my ($self, $sep) = @_;
496    $sep = '-' unless defined $sep;
497    return sprintf("%0.2d%s%0.2d%s%0.4d",
498                   $self->{local_c}{month}, $sep,
499                   $self->{local_c}{day},   $sep,
500                   $self->year);
501}
502
503sub dmy {
504  my ($self, $sep) = @_;
505  $sep = '-' unless defined $sep;
506  return sprintf("%0.2d%s%0.2d%s%0.4d",
507                 $self->{local_c}{day},   $sep,
508                 $self->{local_c}{month}, $sep,
509                 $self->year);
510}
511
512# Anglo-Babylonian (or sexagesimal) time
513sub abt_hour   { $_[0]->{local_c}{abt_hour} }
514sub abt_minute { $_[0]->{local_c}{abt_minute} } *abt_min = \&abt_minute;
515sub abt_second { $_[0]->{local_c}{abt_second} } *abt_sec = \&abt_second;
516sub abt_hms {
517  my ($self, $sep) = @_;
518  $sep = ':' unless defined $sep;
519  return sprintf("%0.2d%s%0.2d%s%0.2d",
520                    $self->{local_c}{abt_hour},   $sep,
521                    $self->{local_c}{abt_minute}, $sep,
522                    $self->{local_c}{abt_second});
523}
524
525sub nanosecond { $_[0]->{rd_nano} }
526
527# Decimal time
528sub hour   { $_[0]->{local_c}{hour} }
529sub minute { $_[0]->{local_c}{minute} } *min = \&minute;
530sub second { $_[0]->{local_c}{second} } *sec = \&second;
531
532sub hms {
533    my ($self, $sep) = @_;
534    $sep = ':' unless defined $sep;
535    return sprintf("%0.1d%s%0.2d%s%0.2d",
536                    $self->{local_c}{hour},   $sep,
537                    $self->{local_c}{minute}, $sep,
538                    $self->{local_c}{second} );
539}
540# don't want to override CORE::time()
541*DateTime::Calendar::FrenchRevolutionary::time = \&hms;
542
543sub iso8601 {
544  my $self = shift;
545  return join 'T', $self->ymd, $self->hms(':');
546}
547*datetime = \&iso8601;
548
549sub is_leap_year { $_[0]->_is_leap_year($_[0]->year) }
550
551sub decade_number {
552  my $self = shift;
553  return 3 * $self->month + int(($self->day - 1) / 10) - 2;
554}
555*week_number = \&decade_number;
556
557sub decade {
558  my $self = shift;
559  return ($self->year, $self->decade_number);
560}
561*week = \&decade;
562
563#sub time_zone { $_[0]->{tz} }
564
565sub offset { $_[0]->{tz}->offset_for_datetime($_[0]) }
566sub _offset_from_local_time { $_[0]->{tz}->offset_for_local_datetime($_[0]) }
567
568#sub is_dst { $_[0]->{tz}->is_dst_for_datetime($_[0]) }
569
570#sub time_zone_short_name { $_[0]->{tz}->short_name_for_datetime($_[0]) }
571
572sub locale { $_[0]->{locale} }
573
574sub utc_rd_values { @{ $_[0] }{ 'utc_rd_days', 'utc_rd_secs', 'rd_nano' } }
575
576# Anglo-Babylonian time
577sub   utc_rd_as_abt_seconds    { ($_[0]->{utc_rd_days}   * 86400) + $_[0]->{utc_rd_secs} }
578sub local_rd_as_abt_seconds    { ($_[0]->{local_rd_days} * 86400) + $_[0]->{local_rd_secs} }
579sub    _time_as_abt_seconds    { $_[1] * 3600 + $_[2] * 60 + $_[3] }
580sub _abt_seconds_as_components { int($_[1] / 3600), int($_[1] % 3600 / 60), $_[1] % 60 }
581
582# Decimal time
583sub _time_as_seconds { .864 * ($_[1] * 10000 + $_[2] * 100 + $_[3]) }
584sub _seconds_as_components {
585  my $sec = int(.5 + $_[1] / .864);
586  int($sec / 10000), int($sec % 10000 / 100), $sec % 100
587}
588
589# RD 1 is JD 1,721,424.5 - a simple offset
590sub jd {
591  my $self = shift;
592  my $jd = $self->{utc_rd_days} + 1_721_424.5;
593  return $jd + ($self->{utc_rd_secs} / 86400);
594}
595
596sub mjd { $_[0]->jd - 2_400_000.5 }
597
598my %formats = (
599        'a' => sub { $_[0]->day_abbr }
600      , 'A' => sub { $_[0]->day_name }
601      , 'b' => sub { $_[0]->month_abbr }
602      , 'B' => sub { $_[0]->month_name }
603      , 'c' => sub { $_[0]->strftime( $_[0]->{locale}->default_datetime_format ) }
604      , 'C' => sub { int($_[0]->year / 100) }
605      , 'd' => sub { sprintf '%02d', $_[0]->day_of_month }
606      , 'D' => sub { $_[0]->strftime('%m/%d/%y') }
607      , 'e' => sub { sprintf('%2d', $_[0]->day_of_month) }
608      , 'f' => sub { sprintf('%2d', $_[0]->month) }
609      , 'F' => sub { $_[0]->ymd('-') }
610      , 'g' => sub { substr($_[0]->year, -2) }
611      , 'G' => sub { sprintf '%04d', $_[0]->year }
612      , 'h' => sub { $_[0]->month_abbr }
613      , 'H' => sub { sprintf('%d', $_[0]->hour) }
614      , 'I' => sub { my $h = $_[0]->hour || 10; sprintf('%d', $h) }
615      , 'j' => sub { sprintf '%03d', $_[0]->day_of_year }
616      , 'k' => sub { sprintf('%2d', $_[0]->hour) }
617      , 'l' => sub { my $h = $_[0]->hour || 10; sprintf('%2d', $h) }
618      , 'L' => sub { sprintf '%04d', $_[0]->year }
619      , 'm' => sub { sprintf '%02d', $_[0]->month }
620      , 'M' => sub { sprintf '%02d', $_[0]->minute }
621      , 'n' => sub { "\n" } # should this be OS-sensitive?
622      , 'p' => sub {    $_[0]->{locale}->am_pm($_[0]) }
623      , 'P' => sub { lc $_[0]->{locale}->am_pm($_[0]) }
624      , 'r' => sub { $_[0]->strftime('%I:%M:%S %p') }
625      , 'R' => sub { $_[0]->strftime('%H:%M') }
626      , 's' => sub { $_[0]->epoch }
627      , 'S' => sub { sprintf('%02d', $_[0]->second) }
628      , 't' => sub { "\t" }
629      , 'T' => sub { $_[0]->strftime('%H:%M:%S') }
630      , 'u' => sub { sprintf '%2d', $_[0]->day_of_decade },
631      , 'U' => sub { $_[0]->decade_number }
632      , 'V' => sub { $_[0]->decade_number }
633      , 'w' => sub { $_[0]->day_of_decade % 10 }
634      , 'W' => sub { $_[0]->decade_number }
635      , 'y' => sub { sprintf('%02d', substr( $_[0]->year, -2 )) }
636      , 'Y' => sub { sprintf '%04d', $_[0]->year }
637      , 'z' => sub { DateTime::TimeZone::offset_as_string( $_[0]->offset ) }
638      , 'Z' => sub { $_[0]->{tz}->short_name_for_datetime($_[0]) }
639      , '+' => sub { '+' }
640      , '%' => sub { '%' }
641      , 'EY' => sub { Roman $_[0]->year || $_[0]->year }
642      , 'Ey' => sub { roman $_[0]->year || $_[0]->year }
643      , '*'  => sub { $_[0]->feast_long }
644      , 'Ej' => sub { $_[0]->feast_long }
645      , 'EJ' => sub { $_[0]->feast_caps }
646      , 'Oj' => sub { $_[0]->feast_short }
647
648    );
649
650$formats{h} = $formats{b};
651
652sub strftime {
653  my $self = shift;
654  # make a copy or caller's scalars get munged
655  my @formats = @_;
656
657  my @r;
658  foreach my $f (@formats)
659    {
660      # regex from DateTime from Date::Format - thanks Graham and Dave!
661      # but there is a twist: 3-char format specifiers such as '%Ey' are
662      # allowed. All 3-char specifiers begin with a '%E' or '%O' prefix.
663      # At the same time, if the user wants %Em or %Om, which do not exist, it defaults to %m
664      # And if the user asks for %E!,
665      # it defaults to E! because neither %E! nor %! exist.
666      $f =~ s/
667                \%([EO]?([*%a-zA-Z]))
668              | \%\{(\w+)\}
669             /
670              $3 ? ($self->can($3) ? $self->$3() : "\%{$3}")
671                 : ($formats{$1} ? $formats{$1}->($self)
672                             : $formats{$2} ? $formats{$2}->($self) : $1)
673             /sgex;
674      return $f unless wantarray;
675      push @r, $f;
676    }
677  return @r;
678}
679
680sub epoch {
681  my $self = shift;
682  my $greg = DateTime->from_object(object => $self);
683  return $greg->epoch;
684}
685
686sub DefaultLocale {
687  'fr'
688}
689
690#my %events = ();
691sub on_date {
692  my ($dt, $lan) = @_;
693  my $locale;
694
695  if (defined $lan)
696    { $locale = DateTime::Calendar::FrenchRevolutionary::Locale->load( $lan )}
697  else
698    { $locale = $dt->{locale} }
699  return $locale->on_date($dt);
700
701}
702
703# A module must return a true value. Traditionally, a module returns 1.
704# But this module is a revolutionary one, so it discards all old traditions.
705"Liberté, égalité, fraternité
706ou la mort !";
707
708__END__
709
710=encoding utf8
711
712=head1 NAME
713
714DateTime::Calendar::FrenchRevolutionary - Dates in the French Revolutionary Calendar
715
716=head1 SYNOPSIS
717
718  use DateTime::Calendar::FrenchRevolutionary;
719
720  # Use the date "18 Brumaire VIII" (Brumaire being the second month)
721  $dt = DateTime::Calendar::FrenchRevolutionary->new( year  =>  8,
722                                                      month =>  2,
723                                                      day   => 18,
724                                       );
725
726  # convert from French Revolutionary to Gregorian...
727  $dtgreg = DateTime->from_object( object => $dt );
728
729  # ... and back again
730  $dtrev = DateTime::Calendar::FrenchRevolutionary->from_object( object => $dtgreg );
731
732=head1 DESCRIPTION
733
734DateTime::Calendar::FrenchRevolutionary    implements    the    French
735Revolutionary  Calendar.   This  module  implements  most  methods  of
736DateTime; see the DateTime(3) manpage for all methods.
737
738=head1 HISTORICAL NOTES
739
740=head2 Preliminary Note
741
742The documentation  uses the  word I<décade> (the  first "e"  having an
743acute  accent). This  French word  is  I<not> the  translation of  the
744English  word  "decade"  (ten-year  period).  It  means  a  ten-I<day>
745period.
746
747For  your  information, the  French  word  for  a ten-year  period  is
748I<décennie>.
749
750=head2 Description
751
752The Revolutionary calendar was in  use in France from 24 November 1793
753(4 Frimaire  II) to 31  December 1805 (10  Nivôse XIV). An  attempt to
754apply  the  decimal rule  (the  basis of  the  metric  system) to  the
755calendar. Therefore, the week  disappeared, replaced by the décade. In
756addition, all months have exactly 3 décades, no more, no less.
757
758At first,  the year was  beginning on the  equinox of autumn,  for two
759reasons.  First, the  republic had  been established  on  22 September
7601792, which  happened to be the  equinox, and second,  the equinox was
761the symbol of equality, the day and the night lasting exactly 12 hours
762each. It  was therefore  in tune with  the republic's  motto "Liberty,
763Equality, Fraternity". But  it was not practical, so  Romme proposed a
764leap year rule similar to the Gregorian calendar rule.
765
766In his book I<The French Revolution>, the XIXth century writer Thomas
767Carlyle proposes these translations for the month names:
768
769=over 4
770
771=item Vendémiaire -> Vintagearious
772
773=item Brumaire -> Fogarious
774
775=item Frimaire -> Frostarious
776
777=item Nivôse -> Snowous
778
779=item Pluviôse -> Rainous
780
781=item Ventôse -> Windous
782
783=item Germinal -> Buddal
784
785=item Floréal -> Floweral
786
787=item Prairial -> Meadowal
788
789=item Messidor -> Reapidor
790
791=item Thermidor -> Heatidor
792
793=item Fructidor -> Fruitidor
794
795=back
796
797Each month has  a duration of 30 days. Since a  year lasts 365.25 days
798(or so), five  additional days (or six on leap  years) are added after
799Fructidor. These days  are called I<Sans-Culottides>.  For programming
800purposes, they are  considered as a 13th month  (much shorter than the
80112 others).
802
803There was also an attempt to decimalize the day's subunits, with 1 day
804= 10 hours, 1 hour = 100 minutes and 1 minute = 100 seconds.  But this
805reform was put on hold after two years or so and it never reappeared.
806
807Other reforms to decimalize the time has been proposed during the last
808part of  the XIXth  Century, but these  reforms were not  applied too.
809And they are irrelevant for this French Revolutionary calendar module.
810
811=head1 METHODS
812
813Since  the week  has been  replaced by  the décade,  the corresponding
814method  names  still   are  C<decade_number>,  C<day_of_decade>,  etc.
815English  speakers, please  note that  this has  nothing to  do  with a
81610-year period.
817
818The module supports both  Anglo-Babylonian time (24x60x60) and decimal
819time.    The  accessors  for   ABT  are   C<abt_hour>,  C<abt_minute>,
820C<abt_second>  and  C<abt_hms>, the  accessors  for  decimal time  are
821C<hour>,  C<minute>,   C<second>  and  C<hms>.   The  C<strftime>  and
822C<iso8601>  methods use  only  decimal time.   The  ABT accessors  are
823provided to be historically correct, since the decimal time reform was
824never put  in force. Yet,  emphasis is on  decimal time because  it is
825more fun than sexagesimal time,  which anyhow can be obtained with the
826standard Gregorian C<DateTime.pm> module.
827
828=head2 Constructors
829
830=over 4
831
832=item * new(...)
833
834Creates a new date object. This class accepts the following parameters:
835
836=over 4
837
838=item * C<year>
839
840Year  number, mandatory. Year  1 corresponds  to Gregorian  years late
8411792 and early 1793.
842
843=item * C<month>
844
845Month  number, in the  range 1..12,  plus number  13 to  designate the
846end-of-year additional days.
847
848=item * C<day>
849
850Day number,  in the range 1..30.  In the case of  additional days, the
851range is 1..5 or 1..6 depending on the year (leap year or normal).
852
853=item * C<hour>, C<minute>, C<second>
854
855Decimal hour number, decimal  minute number and decimal second number.
856The hour is in the 0..9  range, both other parameters are in the 0..99
857range. These parameters cannot  be specified with the sexagesimal time
858parameters C<abt_>I<xxx> (see below).
859
860=item * C<abt_hour>, C<abt_minute>, C<abt_second>
861
862Sexagesimal  hour number,  sexagesimal minute  number  and sexagesimal
863second number.  The hour is  in the 0..23 range, both other parameters
864are in the 0..59 range.  These parameters cannot be specified with the
865decimal time parameters (see above).
866
867=item * C<locale>
868
869Only the values  C<fr> (French), C<en> (English),  C<es> (Spanish) and
870C<it> (Italian)  are allowed. Default  is French. No other  values are
871possible, even territory variants such as C<fr_BE> or C<en_US>.
872
873=back
874
875=item * from_epoch( epoch => $epoch )
876
877Creates a  date object from a  timestamp value. This  timestamp is the
878number of seconds since the computer epoch, not the calendar epoch.
879
880=item * now( )
881
882Creates  a date  object that  corresponds to  the precise  instant the
883method is called.
884
885=item * from_object( object => $object, ... )
886
887Creates a date  object by converting another object  from the DateTime
888suite.  The preferred way for calendar to calendar conversion.
889
890=item * last_day_of_month( ... )
891
892Same as C<new>,  except that the C<day> parameter  is forbidden and is
893automatically set to  the end of the month.  If the C<month> parameter
894is 13 for the additional days, the  day is set to the end of the year,
895either the 5th or the 6th additional day.
896
897=item * clone
898
899Creates a replica of the original date object.
900
901=item * set( .. )
902
903This method can be used to change the local components of a date time,
904or  its locale.   This method  accepts  any parameter  allowed by  the
905C<new()> method.
906
907This  method performs  parameters validation  just as  is done  in the
908C<new()> method.
909
910=back
911
912=head2 Accessors
913
914=over 4
915
916=item * year
917
918Returns the year. C<%Y> or C<%G> in C<strftime>.
919
920=item * month
921
922Returns the month in the 1..12 range. If the date is an additional day
923at  the end  of the  year, returns  13, which  is not  really  a month
924number. C<%m> or C<%f> in C<strftime>.
925
926=item * month_0
927
928Returns the month in the 0..11 range. If the date is an additional day
929at the end of the year, returns 12, which is not really a month number.
930
931=item * month_name
932
933Returns the  French name of the  month or its  English translation. No
934other language is  supported yet.  For the additional  days at the end
935of  the  year,  returns  "jour  complémentaire",  the  translation  of
936"additional day". C<%B> in C<strftime>.
937
938Note: The  English translations for  the month names come  from Thomas
939Carlyle's book.
940
941=item * month_abbr
942
943Returns a 3-letter abbreviation of  the month name. For the additional
944days at the  end of the year, returns  "S-C", because these additional
945days  were also  known as  the I<Sans-culottides>.  C<%b> or  C<%h> in
946C<strftime>.
947
948=item * day_of_month, day, mday
949
950Returns the day of the month, from 1..30. C<%d> or C<%e> in C<strftime>.
951
952=item * day_of_decade, dod, day_of_week, dow, wday
953
954Returns the day of the I<décade>,  from 1..10. The C<dow>, C<wday> and
955C<day_of_week>  names   are  there   for  compatibility's   sake  with
956C<DateTime>,  even   if  the  word   "week"  is  improper.   C<%u>  in
957C<strftime>, but not C<%w> (because the value differs on I<décadi>).
958
959=item * day_name
960
961Returns  the  name of  the  current day  of  the  I<décade>. C<%A>  in
962C<strftime>.
963
964=item * day_abbr
965
966Returns   the   abbreviated  name   of   the   current   day  of   the
967I<décade>. C<%a> in C<strftime>.
968
969=item * day_of_year, doy
970
971Returns the day of the year. C<%j> in C<strftime>.
972
973=item * feast, feast_short, feast_long, feast_caps
974
975Returns the  plant, animal, mineral  or tool associated with  the day.
976The  default format is  C<short>. If  requested, you  can ask  for the
977C<long> format,  with a C<jour  de...> prefix, or the  C<caps> format,
978with the first  letter of the prefix and  feast capitalized.  Example:
979for 11 Vendémiaire, we have:
980
981   feast, feast_short  pomme de terre
982   feast_long          jour de la pomme de terre
983   feast_caps          Jour de la Pomme de terre
984
985C<%Ej>, C<%EJ>, C<%Oj> or C<%*> in C<strftime>.
986
987Note: the  English translation for  the feasts comes mainly  from Alan
988Taylor's website "Preserving the French Republican Calendar".
989
990=item * ymd, dmy, mdy
991
992Returns the  date in the  corresponding composite format.  An optional
993parameter  allows  you  to  choose  the  separator  between  the  date
994elements. C<%F> in C<strftime>.
995
996=item * abt_hour, abt_minute, abt_min, abt_second, abt_sec
997
998Return  the corresponding  time elements,  using a  sexagesimal scale.
999This is also sometimes known as the I<Anglo-Babylonian Time>.
1000
1001=item * hour, minute, min, second, sec
1002
1003Return the corresponding time elements, using a decimal scale, with 10
1004hours per day, 100 minutes per hour and 100 seconds per minute. C<%H>,
1005C<%M> and C<%S> in C<strftime>.
1006
1007=item * abt_hms
1008
1009Returns  a composite  string with  the three  time elements.  Uses the
1010I<Anglo-Babylonian Time>.  An optional  parameter allows you to choose
1011the separator (C<:> by default).
1012
1013=item * hms
1014
1015Returns  a composite  string with  the three  time elements.  Uses the
1016decimal  time.   An  optional  parameter  allows  you  to  choose  the
1017separator (C<:> by default).
1018
1019=item * iso8601
1020
1021Returns the  date and time  is a format  similar to what  ISO-8601 has
1022specified for the Gregorian calendar.
1023
1024=item * is_leap_year
1025
1026Returns a true value if the year is a leap year, false else.
1027
1028=item * decade_number, week_number
1029
1030Returns the I<décade> number. C<%U>, C<%V> or C<%W> in C<strftime>.
1031
1032=item * decade, week
1033
1034Returns a 2-element list, with  the year number and the décade number.
1035Since the  I<décade> is always  aligned with a  month and then  with a
1036year, the year element is always the same as the date's year.  Anyhow,
1037this is done for compatibility with DateTime's C<week> method.
1038
1039=item * utc_rd_values
1040
1041Returns the  current UTC Rata Die  days, seconds and  nanoseconds as a
10423-element list.  This exists primarily to allow other calendar modules
1043to create objects based on the values provided by this object.
1044
1045=item * jd, mjd
1046
1047These  return the Julian  Day and  Modified Julian  Day, respectively.
1048The value returned is a floating point number.  The fractional portion
1049of the number represents the time portion of the datetime.
1050
1051=item * utc_rd_as_seconds
1052
1053Returns the current UTC Rata Die days and seconds purely as seconds.
1054This is useful when you need a single number to represent a date.
1055
1056=item * local_rd_as_seconds
1057
1058Returns the current local Rata Die days and seconds purely as seconds.
1059
1060=item * strftime( $format, ... )
1061
1062This  method  implements functionality  similar  to the  C<strftime()>
1063method in C.  However, if  given multiple format strings, then it will
1064return multiple elements, one for each format string.
1065
1066See the L<strftime Specifiers|/strftime Specifiers> section for a list
1067of all possible format specifiers.
1068
1069=item * epoch
1070
1071Return the UTC epoch value  for the datetime object.  Internally, this
1072is  implemented  C<epoch>  from   C<DateTime>,  which  in  turn  calls
1073C<Time::Local>,  which uses  the Unix  epoch even  on machines  with a
1074different epoch (such  as Mac OS).  Datetimes before  the start of the
1075epoch will be returned as a negative number.
1076
1077Since epoch times cannot represent  many dates on most platforms, this
1078method may simply return undef in some cases.
1079
1080Using your system's  epoch time may be error-prone,  since epoch times
1081have such a limited range  on 32-bit machines.  Additionally, the fact
1082that different  operating systems  have different epoch  beginnings is
1083another source of bugs.
1084
1085=item * on_date
1086
1087Gives  a  few historical  events  that took  place  on  the same  date
1088(day+month, irrespective of the  year).  These events occur during the
1089period of use  of the calendar, that is, no  later than Gregorian year
10901805. The  related  events either  were  located  in  France, or  were
1091battles in which a French army was involved.
1092
1093This  method accepts  one  optional argument,  the  language. For  the
1094moment, only  "en" for English and  "fr" for French  are available. If
1095not given, the method will use the date object's current locale.
1096
1097Not all eligible events are portrayed there. The events database will
1098be expanded in future versions.
1099
1100Most  military events  are extracted  from I<Calendrier  Militaire>, a
1101book written by an anonymous author in VII (1798) or so. I guess there
1102is  no longer  any  copyright attached.  Please  note that  this is  a
1103propaganda  book, which  therefore gives  a  very biased  view of  the
1104events.
1105
1106=back
1107
1108=head2 strftime Specifiers
1109
1110The following specifiers are allowed in the format string given to the
1111C<strftime()> method:
1112
1113=over 4
1114
1115=item * %a
1116
1117The abbreviated day of I<décade> name.
1118
1119=item * %A
1120
1121The full day of I<décade> name.
1122
1123=item * %b
1124
1125The abbreviated month name, or 'S-C' for additional days (abbreviation
1126of I<Sans-culottide>, another name for these days).
1127
1128=item * %B
1129
1130The full month name.
1131
1132=item * %c
1133
1134The date-time,  using the  default format, as  defined by  the current
1135locale.
1136
1137=item * %C
1138
1139The century number (year/100) as a 2-digit integer.
1140
1141=item * %d
1142
1143The day of the month as a decimal number (range 01 to 30).
1144
1145=item * %D
1146
1147Equivalent to  %m/%d/%y.  This  is not a  good standard format  if you
1148have want both Americans and  Europeans (and others) to understand the
1149date!
1150
1151=item * %e
1152
1153Like %d, the day of the month  as a decimal number, but a leading zero
1154is replaced by a space.
1155
1156=item * %f
1157
1158The month as a decimal number (1  to 13). Unlike %m, a leading zero is
1159replaced by a space.
1160
1161=item * %F
1162
1163Equivalent to %Y-%m-%d (the ISO 8601 date format)
1164
1165=item * %g
1166
1167Strictly similar to  %y, since I<décades> are always  aligned with the
1168beginning of the year in this calendar.
1169
1170=item * %G
1171
1172Strictly similar to  %Y, since I<décades> are always  aligned with the
1173beginning of the year in this calendar.
1174
1175=item * %h
1176
1177Equivalent to %b.
1178
1179=item * %H
1180
1181The hour as a decimal number using a 10-hour clock (range 0 to 9).
1182The result is a single-char string.
1183
1184=item * %I
1185
1186The hour  as a decimal number  using the numbers on  a clockface, that
1187is, range 1 to 10. The result is a single-char string, except for 10.
1188
1189=item * %j
1190
1191The day of the year as a decimal number (range 001 to 366).
1192
1193=item * %Ej
1194
1195The feast for  the day, in long format ("jour de  la pomme de terre").
1196Also available as %*.
1197
1198=item * %EJ
1199
1200The feast for  the day, in capitalised long format  ("Jour de la Pomme
1201de terre").
1202
1203=item * %Oj
1204
1205The feast for the day, in short format ("pomme de terre").
1206
1207=item * %k
1208
1209The  hour (10-hour  clock) as  a decimal  number (range  0 to  9); the
1210result is a 2-char string, the digit is preceded by a blank. (See also
1211%H.)
1212
1213=item * %l
1214
1215The hour  as read from a  clockface (range 1  to 10). The result  is a
12162-char string, the digit is preceded  by a blank, except of course for
121710. (See also %I.)
1218
1219=item * %L
1220
1221The year as  a decimal number including the  century. Strictly similar
1222to %Y and %G.
1223
1224=item * %m
1225
1226The month as a decimal number (range 01 to 13).
1227
1228=item * %M
1229
1230The minute as a decimal number (range 00 to 99).
1231
1232=item * %n
1233
1234A newline character.
1235
1236=item * %p
1237
1238Either  `AM'  or  `PM' according  to  the  given  time value,  or  the
1239corresponding strings for the current locale.  Noon is treated as `pm'
1240and midnight as `am'.
1241
1242=item * %P
1243
1244Like %p but in lowercase: `am' or `pm' or a corresponding string for
1245the current locale.
1246
1247=item * %r
1248
1249The decimal time in a.m.  or  p.m. notation.  In the POSIX locale this
1250is equivalent to `%I:%M:%S %p'.
1251
1252=item * %R
1253
1254The  decimal time  in 10-hour  notation  (%H:%M). (SU)  For a  version
1255including the seconds, see %T below.
1256
1257=item * %s
1258
1259The number of seconds since the epoch.
1260
1261=item * %S
1262
1263The second as a decimal number (range 00 to 99).
1264
1265=item * %t
1266
1267A tab character.
1268
1269=item * %T
1270
1271The decimal time in 10-hour notation (%H:%M:%S).
1272
1273=item * %u
1274
1275The day of the I<décade> as a  decimal, range 1 to 10, Primidi being 1
1276and Décadi being 10.  See also %w.
1277
1278=item * %U
1279
1280The I<décade> number of the current year as a decimal number, range 01
1281to 37.
1282
1283=item * %V
1284
1285The  I<décade>  number (French  Revolutionary  equivalent  to the  ISO
12868601:1988 week number) of the current  year as a decimal number, range
128701 to  37. Identical to C<%U>,  since I<décades> are aligned  with the
1288beginning of the year.
1289
1290=item * %w
1291
1292The day of the  I<décade> as a decimal, range 0 to  9, Décadi being 0.
1293See also %u.
1294
1295=item * %W
1296
1297The I<décade> number of the current year as a decimal number, range 00
1298to 37. Strictly similar to %U and %V.
1299
1300=item * %y
1301
1302The year as a decimal number without a century (range 00 to 99).
1303
1304=item * %Y
1305
1306The year as a decimal number including the century.
1307
1308=item * %Ey
1309
1310The year as a lowercase Roman number.
1311
1312=item * %EY
1313
1314The year as a uppercase Roman  number, which is the traditional way to
1315write years when using the French Revolutionary calendar.
1316
1317=item * %z
1318
1319The   time-zone  as   hour  offset   from  UTC.    Required   to  emit
1320RFC822-conformant dates (using "%a, %d %b %Y %H:%M:%S %z").  Since the
1321module does not  support time zones, this gives  silly results and you
1322cannot  be RFC822-conformant.  Anyway,  RFC822 requires  the Gregorian
1323calendar, doesn't it?
1324
1325=item * %Z
1326
1327The  time  zone  or  name  or abbreviation,  should  the  module  have
1328supported them.
1329
1330=item * %*
1331
1332The feast for the day, in long format ("jour de la pomme de terre").
1333Also available as %Ej.
1334
1335=item * %%
1336
1337A literal `%' character.
1338
1339=back
1340
1341=head1 PROBLEMS AND KNOWN BUGS
1342
1343=head2 Time Zones
1344
1345Only the I<floating> time zone  is supported.  Time zones were created
1346in  the  late  XIXth  century,  at  a  time  when  fast  communication
1347(railroads)  and instant  communication (electric  telegraph)  made it
1348necessary.  But at this time, the French Revolutionary calendar was no
1349longer in use.
1350
1351=head2 Leap Seconds
1352
1353They are not supported.
1354
1355=head2 I18N
1356
1357For  the  moment,  only  French,  English,  Spanish  and  Italian  are
1358available. For the  English translation, I have  used Thomas Carlyle's
1359book and Alan  Taylor's web site at kokogiak.com (see  below). Then, I
1360have checked  some translations  with Wikipedia and  Jonathan Badger's
1361French Revolutionary Calendar module written in Ruby.
1362
1363Some feast names are not translated, other's translations are doubtful
1364(they are flagged with a question mark).  Remarks are welcome.
1365
1366=head2 Feasts
1367
1368The various  sources for  the feasts  are somewhat  contradictory. The
1369most obvious  example if  the 4th  additional day,  which is  "Jour de
1370l'opinion" (day of opinion) in some  documents and "Jour de la raison"
1371(day of reason) in others.
1372
1373In addition, the sources have several slight differences between them.
1374All of  them obviously include some  typos. [Annexe] is chosen  as the
1375reference since it is the  definitive legislative text that officially
1376defines names of days in  the French revolutionary calendar. This text
1377introduces  amendments  to  the  original calendar  set  up  by  Fabre
1378d'Églantine in [Fabre], and gives  in annex the amended calendar. When
1379there is  a difference between  the amended calendar and  [Fabre] with
1380amendments  (yes it  can happen!),  [Fabre] version  prevails. Obvious
1381typos  in  [Annexe] (yes  it  can  happen!)  are preserved,  with  the
1382exception  of accented  letters  because they  are  fuzzy rendered  in
1383original prints, or  cannot be printed at all at  that time on letters
1384in uppercase.
1385
1386The bracket  references refer  to entries in  the "SEE  ALSO" section,
1387"Internet" subsection below.
1388
1389=head1 SUPPORT
1390
1391Support for this module is provided via the datetime@perl.org email
1392list. See L<https://lists.perl.org/> for more details.
1393
1394Please   report  any   bugs   or  feature   requests   to  Github   at
1395L<https://github.com/jforget/DateTime-Calendar-FrenchRevolutionary>,
1396and create an issue or submit a pull request.
1397
1398If you have no  feedback after a week or so, try to  reach me by email
1399at JFORGET  at cpan  dot org.  The notification  from Github  may have
1400failed to reach  me. In your message, please  mention the distribution
1401name in the subject, so my spam  filter and I will easily dispatch the
1402email to the proper folder.
1403
1404On the other  hand, I may be  on vacation or away from  Internet for a
1405good  reason. Do  not be  upset if  I do  not answer  immediately. You
1406should write  me at a leisurely  rythm, about once per  month, until I
1407react.
1408
1409If after about six  months or a year, there is  still no reaction from
1410me, you can worry and start the CPAN procedure for module adoption.
1411See L<https://groups.google.com/g/perl.module-authors/c/IPWjASwuLNs>
1412L<https://www.cpan.org/misc/cpan-faq.html#How_maintain_module>
1413and L<https://www.cpan.org/misc/cpan-faq.html#How_adopt_module>.
1414
1415
1416=head1 AUTHOR
1417
1418Jean Forget <JFORGET@cpan.org>
1419
1420based  on  Dave  Rolsky's  DateTime  module, Eugene  van  der  Pijll's
1421DateTime::Calendar::Pataphysical      module     and      my     prior
1422Date::Convert::French_Rev module.
1423
1424The development of this module is hosted by I<Les Mongueurs de Perl>,
1425L<http://www.mongueurs.net/>.
1426
1427=head2 THANKS
1428
1429Many thanks to those who sent me a RT ticket or a pull request:
1430
1431=over 4
1432
1433=item * The late Iain Truskett,
1434
1435=item * Philippe Bruhat (BooK)
1436
1437=item * Slaven Rezić
1438
1439=item * and  especially Gérald Sédrati-Dinet (GIBUS at  cpan dot org),
1440for  his thorough  documentation  research  and for  his  work on  the
1441Spanish and Italian locales.
1442
1443=back
1444
1445Also,  many thanks  to all  the  persons who  gave me  advices on  the
1446DateTime mailing list. I will not mention them, because I might forget
1447some of them.
1448
1449=head1 SEE ALSO
1450
1451=head2 Perl Software
1452
1453date(1), strftime(3), perl(1)
1454
1455L<DateTime>
1456
1457L<DateTime::Calendar::Pataphysical>
1458
1459L<Date::Convert::French_Rev> or L<https://github.com/jforget/Date-Convert-French_Rev>
1460
1461L<Date::Converter>
1462
1463=head2 Other Software
1464
1465F<calendar/cal-french.el>  in emacs-21.2  or later  or xemacs  21.1.8,
1466forked in L<https://github.com/jforget/emacs-lisp-cal-french>
1467
1468=head2 Books
1469
1470Quid 2001, M and D Frémy, publ. Robert Laffont
1471
1472Agenda Républicain 197 (1988/89), publ. Syros Alternatives
1473
1474Any French schoolbook about the French Revolution
1475
1476The French Revolution, Thomas Carlyle, Oxford University Press
1477
1478Calendrier Militaire, anonymous
1479
1480Histoire de l'heure en France, Jacques Gapaillard, publ. Vuibert -- ADAPT
1481
1482=head2 Internet
1483
1484L<https://github.com/houseabsolute/DateTime.pm/wiki>
1485
1486L<http://www.faqs.org/faqs/calendars/faq/part3/>
1487
1488L<https://zapatopi.net/metrictime/>
1489
1490L<http://datetime.mongueurs.net/>
1491
1492L<https://www.allhotelscalifornia.com/kokogiakcom/frc/default.asp>
1493
1494L<https://github.com/jhbadger/FrenchRevCal-ruby>
1495
1496L<https://en.wikipedia.org/wiki/French_Republican_Calendar>
1497
1498L<https://fr.wikipedia.org/wiki/Calendrier_républicain>
1499
1500L<https://archive.org/details/decretdelaconven00fran_40>
1501
1502"Décret  du  4 frimaire,  an  II  (24  novembre  1793) sur  l'ère,  le
1503commencement et l'organisation de l'année et sur les noms des jours et
1504des mois"
1505
1506L<https://archive.org/details/decretdelaconven00fran_41>
1507
1508Same text, with a slightly different typography.
1509
1510L<https://purl.stanford.edu/dx068ky1531>
1511
1512"Archives parlementaires  de 1789 à  1860: recueil complet  des débats
1513législatifs & politiques  des Chambres françaises", J.  Madival and E.
1514Laurent, et. al.,  eds, Librairie administrative de  P. Dupont, Paris,
15151912.
1516
1517Starting with  page 6,  this document  includes the  same text  as the
1518previous links, with  a much improved typography.  Especially, all the
1519"long s"  letters have been replaced  by short s. Also  interesting is
1520the text  following the  decree, page 21  and following:  "Annuaire ou
1521calendrier pour la seconde année de la République française, annexe du
1522décret  du  4  frimaire,  an  II (24  novembre  1793)  sur  l'ère,  le
1523commencement et l'organisation de l'année et sur les noms des jours et
1524des mois". In the remarks above, it is refered as [Annexe].
1525
1526L<https://gallica.bnf.fr/ark:/12148/bpt6k48746z>
1527
1528[Fabre] "Rapport fait à la Convention nationale dans la séance du 3 du
1529second mois de la seconde année  de la République française, au nom de
1530la   Commission    chargée   de   la   confection    du   calendrier",
1531Philippe-François-Nazaire  Fabre  d'Églantine,  Imprimerie  nationale,
1532Paris, 1793
1533
1534L<https://gallica.bnf.fr/ark:/12148/bpt6k49016b>
1535
1536[Annuaire] "Annuaire  du cultivateur,  pour la  troisième année  de la
1537République  : présenté  le  30 pluviôse  de l'an  II  à la  Convention
1538nationale, qui en  a décrété l'impression et l'envoi,  pour servir aux
1539écoles  de la  République",  Gilbert Romme,  Imprimerie nationale  des
1540lois, Paris, 1794-1795
1541
1542L<https://gallica.bnf.fr/ark:/12148/bpt6k43978x>
1543
1544"Calendrier militaire,  ou tableau  sommaire des  victoires remportées
1545par les  Armées de  la République française,  depuis sa  fondation (22
1546septembre 1792),  jusqu'au 9  floréal an  7, époque  de la  rupture du
1547Congrès de Rastadt et de la reprise des hostilités" Moutardier, Paris,
1548An  VIII de  la République  française.  The source  of the  C<on_date>
1549method.
1550
1551=head1 LICENSE STUFF
1552
1553Copyright  (c) 2003,  2004, 2010,  2012, 2014,  2016, 2019,  2021 Jean
1554Forget. All  rights reserved. This  program is free software.  You can
1555distribute,    adapt,    modify,     and    otherwise    mangle    the
1556DateTime::Calendar::FrenchRevolutionary module under the same terms as
1557perl 5.16.3.
1558
1559This program is  distributed under the same terms  as Perl 5.16.3: GNU
1560Public License version 1 or later and Perl Artistic License
1561
1562You can find the text of the licenses in the F<LICENSE> file or at
1563L<https://dev.perl.org/licenses/artistic.html>
1564and L<https://www.gnu.org/licenses/gpl-1.0.html>.
1565
1566Here is the summary of GPL:
1567
1568This program is  free software; you can redistribute  it and/or modify
1569it under the  terms of the GNU General Public  License as published by
1570the Free  Software Foundation; either  version 1, or (at  your option)
1571any later version.
1572
1573This program  is distributed in the  hope that it will  be useful, but
1574WITHOUT   ANY  WARRANTY;   without  even   the  implied   warranty  of
1575MERCHANTABILITY  or FITNESS  FOR A  PARTICULAR PURPOSE.   See  the GNU
1576General Public License for more details.
1577
1578You should  have received  a copy  of the  GNU General  Public License
1579along with this program;  if not, see L<https://www.gnu.org/licenses/>
1580or contact the Free Software Foundation, Inc., L<https://www.fsf.org>.
1581
1582=cut
1583