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