File Coverage

blib/lib/DateTime/Calendar/FrenchRevolutionary.pm
Criterion Covered Total %
statement 258 280 92.1
branch 61 68 89.7
condition 23 27 85.1
subroutine 76 80 95.0
pod 42 51 82.3
total 460 506 90.9


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