DateTime-Fiction-JRRTolkien-Shire

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

    Pull static data out of subroutines.

    Add author tests.

    Bring code up to my usual level of  Perl::Critic compliance.

    Merge branch 'manwar-add-abstract-to-pod'.  This pull request added
    the one-line abstract that is supposed to appear on the NAME line of
    the POD. Thanks to Mohammad S Anwar for the patch.

    Add method calendar_name() (returns 'Shire')

    Replace die() with Carp::croak().

    Ditch 'use vars'. Add 'use warnings'.

0.20		2017-01-25	T. R. Wyant
    Replace LICENSE file with LICENSES/ dir. The new directory contains
    the licenses as individual files.

    Synch on_date() text with Date::Tolkien::Shire

README  view on Meta::CPAN

DateTime-Fiction-JRRTolkien-Shire is Copyright (C) 2003 by Tom Braun,
Copyright (C) 2017-2022, 2025 by Thomas R. Wyant, III

DESCRIPTION

This is a DateTime implementation of the Shire Calendar as described in
The Lord of the Rings by J. R. R. Tolkien. It is a follow-on to the
Date::Tolkien::Shire module.

The Shire Calendar is a rationalized calendar consisting of 12 months of
30 days each, plus 5 holidays (6 in leap years) that are not part of any
month. One of the holidays (two in leap years) are also not part of any
week. This causes every year to start on the same day of the week.

INSTALLATION

This pure-Perl module is installable using any of the usual
incantations.

LICENSING INFORMATION

eg/README  view on Meta::CPAN

This directory contains example scripts. Specifically:

README - This file

date-convert - This Perl script converts between calendars using the
    appropriate DateTime modules. By default it converts from Gregorian
    to Shire Reckoning, but any pair of DateTime modules can be used.

on-date - This Perl script displays the 'on_date()' text for the
    specified date, which can be either Gregorian (year month day) or,
    with the --shire option, the given Shire date (year month day or
    year holiday).

# ex: set filetype=text textwidth=72 autoindent :

eg/date-convert  view on Meta::CPAN

foreach my $key ( qw{ from to } ) {
    local $@ = undef;
    eval "require $opt{$key}; 1"
	or die $@;
}

my $from = $opt{from}->$instantiater( @ARGV );

my $to = $opt{to}->from_object( object => $from );

my $calendar;
if ( my $code = $to->can( 'calendar_name' ) ) {
    $calendar = $code->( $to );
} else {
    ( $calendar = $opt{to} ) =~ s/ .* :: //smx
	or $calendar = 'Gregorian';
}

if ( $serializer ) {
    print $to->$serializer(), " $calendar\n";
} else {
    print "$to $calendar\n";
}

__END__

=head1 TITLE

date-convert - Convert dates from one calendar to another.

=head1 SYNOPSIS

 date-convert year 2016 month 4 day 1
 date-convert -reverse year 1419 holiday 3
 date-convert -help
 date-convert -version

=head1 OPTIONS

eg/date-convert  view on Meta::CPAN


The default is C<-to=DateTime::Fiction::JRRTolkien::Shire>.

=head2 -version

This option displays the version of this script. The script then exits.

=head1 DETAILS

This Perl script uses L<DateTime|DateTime> modules to convert from one
calendar to another.

The command-line arguments are passed verbatim to the C<-from> class'
C<new()> method. The resultant object is passed to the C<-to> class'
C<from_object()> method, and the result of that method is stringified.

By default, this script converts from C<DateTime> to
C<DateTime::Fiction::JRRTolkien::Shire>, thus converting the given date
from Gregorian to Shire Reckoning.

=head1 AUTHOR

eg/on-date  view on Meta::CPAN

C<on_date()>.

=head2 --help

This option displays the documentation for this script. The script then
exits.

=head2 --shire

If this Boolean option is asserted, the arguments are dates in the Shire
calendar: either year, month, and day numbers, or year and holiday
numbers.

The default is C<--no-shire>, which causes the arguments to be
interpreted as Gregorian year, month and day numbers.

=head2 --version

This option displays the version of this script. The script then exits.

=head1 DETAILS

lib/DateTime/Fiction/JRRTolkien/Shire.pm  view on Meta::CPAN


    my $shire_rd = __year_day_to_rata_die(
	$self->{year},
	__date_to_day_of_year(
	    $self->{year},
	    $self->{month},
	    $self->{day} || $self->{holiday},
	),
    );

    # Because the leap year algorithm is the same in both calendars, I
    # can use __rata_die_to_year_day() on the Gregorian Rata Die day.
    ( $dt_args{year}, $dt_args{day_of_year} ) = __rata_die_to_year_day(
	$shire_rd - GREGORIAN_RATA_DIE_TO_SHIRE );

    # We may be calling this because we have fiddled with the Shire date
    # and need to preserve stuff that is maintained by the embedded
    # DateTime object. So if we actually have said object, preserve
    # everything not explicitly specified.
    if ( $self->{dt} ) {
	foreach my $name ( @delegate_to_dt ) {

lib/DateTime/Fiction/JRRTolkien/Shire.pm  view on Meta::CPAN

	    recalc	=> 1,
	    %my_arg,
	}, $class;

	return $self;
    }
}

sub last_day_of_month {
    my ( $class, %arg ) = @_;
    $arg{day} = 30; # The shire calendar is nice this way
    return $class->new( %arg );
}

{
    my $validator = Params::ValidationCompiler::validation_for(
	name			=> '_validation_for_from_day_of_year',
	name_is_optional	=> 1,
	params			=> {
	    year		=> {
		type		=> __t( 'Year' ),

lib/DateTime/Fiction/JRRTolkien/Shire.pm  view on Meta::CPAN


sub now_local {
    my ( $class, %arg ) = @_;
    my %dt_arg;
    @dt_arg{ qw< second minute hour day month year > } = localtime;
    $dt_arg{month} += 1;
    $dt_arg{year}  += 1900;
    return $class->from_object( %arg, object => DateTime->new( %dt_arg ) );
}

sub calendar_name {
    return 'Shire';
}

sub clone {
    my ( $self ) = @_;
    my $clone = { %{ $self } };
    $clone->{dt} = $self->{dt}->clone();
    return bless $clone, ref $self;
}

lib/DateTime/Fiction/JRRTolkien/Shire.pm  view on Meta::CPAN

	$self->{year},
	$self->{month},
	$self->{day} || $self->{holiday},
    );
}

*doy  = \&day_of_year;	# sub doy

sub week { return ($_[0]->week_year, $_[0]->week_number); }

*week_year  = \&year;	# sub week_year; the shire calendar is nice this way

sub week_number {
    my $self = shift;
    # TODO re-implement in terms of __week_of_year
    my $yday = $self->day_of_year;

    DAY_NUMBER_MIDYEARS_DAY == $yday
	and return 0;
    DAY_NUMBER_MIDYEARS_DAY < $yday
	and --$yday;

lib/DateTime/Fiction/JRRTolkien/Shire.pm  view on Meta::CPAN


    my %handler = (
	year	=> sub {
	    $_[0]->set(
		holiday	=> 1,
		@midnight,
	    );
	},
	quarter	=> sub {
	    my ( $self ) = @_;
	    # This is an extension to the Shire calendar by Tom Wyant.
	    # It has no textual justification whatsoever. Feel free to
	    # pretend it does not exist.
	    if ( my $quarter = $self->quarter() ) {
		# The start of a quarter is tricky since quarters 1 and
		# 3 start on holidays, so we just do a table lookup.
		$self->set(
		    @{ $quarter_start[ $quarter ] },
		    @midnight,
		);
	    } else {

lib/DateTime/Fiction/JRRTolkien/Shire.pm  view on Meta::CPAN

# 0) and the use of POSIX::floor() rather than int() or use integer;
sub weekday_of_month {
    my ( $self ) = @_;
    $self->month()
	or return 0;
    return POSIX::floor( ( ( $_[0]->day - 1 ) / 7 ) + 1 );
}
# ISO says that the first week of a year is the first week containing
# a Thursday. Extending that says that the first week of the month is
# the first week containing a Thursday. ICU agrees.
# ISO does not really apply to the Shire calendar. This method is
# algorithmically the same as the DateTime method, which amounts to
# taking the first week of the year to be the first week containing a
# Hevensday. We return nothing (undef in scalar context) on a holiday
# because zero is a valid return (e.g. for 1 Rethe). -- TRW
sub week_of_month {
    my ( $self ) = @_;
    $self->month()
	or return;
    my $hev  = $self->day() + 4 - $self->day_of_week();
    return POSIX::floor( ( $hev + 6 ) / 7 );

lib/DateTime/Fiction/JRRTolkien/Shire.pm  view on Meta::CPAN

}

sub _isa { return Scalar::Util::blessed( $_[0] ) && $_[0]->isa( $_[1] ) }

1;

__END__

=head1 NAME

DateTime::Fiction::JRRTolkien::Shire - DateTime implementation of the Shire calendar.

=head1 SYNOPSIS

    use DateTime::Fiction::JRRTolkien::Shire;

    # Constructors
    my $shire = DateTime::Fiction::JRRTolkien::Shire->new(year => 1419,
                                                          month => 'Rethe',
                                                          day => 25);
    my $shire = DateTime::Fiction::JRRTolkien::Shire->new(year => 1419,

lib/DateTime/Fiction/JRRTolkien/Shire.pm  view on Meta::CPAN

    $shire == $shire2;

    # Strings
    print "$shire1\n"; # Prints Sunday 25 Rethe 1419

    # On this date in history
    print $shire->on_date;

=head1 DESCRIPTION

Implementation of the calendar used by the hobbits in J.R.R. Tolkien's
exceptional novel The Lord of The Rings, as described in Appendix D of
that book (except where noted).  The calendar has 12 months, each with
30 days, and 5 holidays that are not part of any month.  A sixth
holiday, Overlithe, is added on leap years.  The holiday Midyear's Day
(and the Overlithe on a leap year) is not part of any week, which means
that the year always starts on Sterday.

This module is a follow-on to the
L<Date::Tolkien::Shire|Date::Tolkien::Shire> module, and is rewritten to
support Dave Rolsky and company's L<DateTime|DateTime> module. The
DateTime module must be installed for this module to work.

lib/DateTime/Fiction/JRRTolkien/Shire.pm  view on Meta::CPAN

C<traditional> (see L<new()|/new>).

=head3 from_object

    $dts = DateTime::Fiction::JRRTolkien::Shire->from_object(
        object  => $object,
        ...
    );

Same as in DateTime, but you can also specify parameters C<accented> and
C<traditional> (see L<new()|/new>). Takes any other DateTime calendar
object and converts it to a DateTime::Fiction::JRRTolkien::Shire object.

=head3 last_day_of_month

    $dts = DateTime::Fiction::JRRTolkien::Shire->last_day_of_month(
        year    => 1419,
        month   => 3,
        ...
    );

Same as in DateTime.  Like the C<new()> constructor, but it does not
take a day parameter.  Instead, the day is set to 30, which is the last
day of any month in the shire calendar. A holiday parameter should not
be used with this method.  Use L<new()|/new> instead.

=head3 from_day_of_year

    $dts = DateTime::Fiction::JRRTolkien::Shire->from_day_of_year(
        year           => 1419,
        day_of_year    => 86,
        ...
    );

lib/DateTime/Fiction/JRRTolkien/Shire.pm  view on Meta::CPAN


=head3 clone

    $dts2 = $dts->clone();

Creates a new Shire object that is the same date (and underlying time)
as the calling object.

=head2 "Get" Methods

=head3 calendar_name

    print $dts->calendar_name(), "\n";

Returns C<'Shire'>.

=head3 year

    print 'Year: ', $dts->year(), "\n";

Returns the year.

=head3 month

lib/DateTime/Fiction/JRRTolkien/Shire.pm  view on Meta::CPAN

empty string is returned.

=head3 is_leap_year

    my @ly = ( 'is not', 'is' );
    printf "%d %s a leap year\n", $dts->year(),
        $ly[ $dts->is_leap_year() ];

Returns 1 if the year is a leap year, and 0 otherwise.

Leap years are given the same rule as the Gregorian calendar.  Every
four years is a leap year, except the first year of the century, which
is not a leap year.  However, every fourth century (400 years), the
first year of the century is a leap year (every 4, except every 100,
except every 400).  This is a slight change from the calendar described
in Appendix D, which uses the rule of once every 4 years, except every
100 years (the same as in the Julian calendar).  Given some uncertainty
about how many years have passed since the time in Lord of the Rings
(see note below), and the expectations of most people that the years
match up with what they're used to, I have changed this rule for this
implementation.  However, this does mean that this calendar
implementation is not strictly that described in Appendix D.

=head3 week_year

    print 'The week year is ', $dts->week_year(), "\n";

This is always the same as the year in the shire calendar, but is
present for compatibility with other DateTime objects.

=head3 week_number

    print 'The week number is ', $dts->week_number(), "\n";

Returns the week of the year, or C<0> for days that are not part of any
week: Midyear's day and the Overlithe.

=head3 week

lib/DateTime/Fiction/JRRTolkien/Shire.pm  view on Meta::CPAN

portion for fractional seconds.  Functions the same as in DateTime.

=head3 quarter

Returns the number of the quarter the day is in, in the range 1 to 4. If
the day is part of no quarter (Midyear's day and the Overlithe), returns
0.

There is no textual justification for quarters, but they are in the
L<DateTime|DateTime> interface, so I rationalized the concept the same
way the Shire calendar rationalizes weeks. If you are not interested in
non-canonical functionality, please ignore anything involving quarters.

=head3 quarter_0

Returns the number of the quarter the day is in, in the range 0 to 3. If
the day is part of no quarter (Midyear's day and the Overlithe), returns
-1.

=head3 quarter_name

lib/DateTime/Fiction/JRRTolkien/Shire.pm  view on Meta::CPAN


Returns either C<'Shire Reckoning'> if the year is positive, or
C<'Before Shire Reckoning'> otherwise.

=head3 era_abbr

Returns either C<'SR'> if the year is positive, or C<'BSR'> otherwise.

=head3 christian_era

This really does not apply to the Shire calendar, but it is part of the
L<DateTime|DateTime> interface. Despite its name, it returns the same
thing that L<era_abbr()|/era_abbr> does.

=head3 secular_era

Returns the same thing L<era_abbr()|/era_abbr> does.

=head3 utc_rd_values

Returns the UTC rata die days, seconds, and nanoseconds. Ignores
fractional seconds.  This is the standard method used by other methods
to convert the shire calendar to other calendars.  See the DateTime
documentation for more information.

=head3 utc_rd_as_seconds

Returns the UTC rata die days entirely as seconds.

=head3 on_date

Returns the current day, with day of week if present, and with all names
in full.  If the day has some events that transpired

lib/DateTime/Fiction/JRRTolkien/Shire.pm  view on Meta::CPAN

C<'S'>, not C<'T'>.

=head3 strftime

    print $dts->strftime( '%Ex%n' );

This is a re-implementation imported from
L<Date::Tolkien::Shire::Data|Date::Tolkien::Shire::Data>. It is intended
to be reasonably compatible with the same-named L<DateTime|DateTime>
method, but has some additions to deal with the peculiarities of the
Shire calendar.

See L<__format()|Date::Tolkien::Shire::Data/__format> in
L<Date::Tolkien::Shire::Data|Date::Tolkien::Shire::Data> for the
documentation, since that is the code that does the heavy lifting for
us.

=head3 accented

This method returns a true value if the event descriptions returned by
L<on_date()|/on_date> and L<strftime()|/strftime> are to be accented.

lib/DateTime/Fiction/JRRTolkien/Shire.pm  view on Meta::CPAN


Allows the day, month, and year to be changed.  It takes any parameters
allowed by the L<new()|/new> constructor, including all those supported
by DateTime and the holiday parameter, except for time_zone. Any
parameters not given will be left as is.  However, with holidays not
falling in any month, it is recommended that a day and month always be
given together.  Otherwise, unanticipated results may occur.

As in the L<new()|/new> constructor, time parameters have no effect on
the Shire dates returned.  However, they are maintained in case the
object is converted to another calendar which supports time.

All C<set_*()> methods from L<DateTime|DateTime> are provided. In
addition, you get the following:

=head3 set_holiday

This convenience method is implemented in terms of

    $dts->set( holiday => ... );

lib/DateTime/Fiction/JRRTolkien/Shire.pm  view on Meta::CPAN

exceptions:

If the date is a holiday, truncation to C<'month'> is equivalent to
truncation to C<'day'>, since holidays are not part of any month.

Similarly, if the date is Midyear's day or the Overlithe, truncation to
C<'week'>, C<'local_week'>, or C<'quarter'> is equivalent to truncation
to C<'day'>, since these holidays are not part of any week (or, by
extension, quarter).

The week in the Shire calendar begins on Sterday, so both C<'week'> and
C<'local_week'> truncate to that day.

There is no textual justification for quarters, but they are in the
L<DateTime|DateTime> interface, so I rationalized the concept the same
way the Shire calendar rationalizes weeks. If you are not interested in
non-canonical functionality, please ignore anything involving quarters.

=head3 set_time_zone

    $dts->set_time_zone( 'UTC' );

Just like in DateTime. This method has no effect on the shire calendar,
but be stored with the date if it is ever converted to another calendar
with time support.

=head2 Comparisons and Stringification

All comparison operators should work, just as in DateTime.  In addition,
all C<DateTime::Fiction::JRRTolkien::Shire> objects will interpolate
into a string representing the date when used in a double-quoted string.

=head2 Durations and Date Math

Durations and date math are supported as of 0.900_01.
Because of the peculiarities of the Shire calendar, the relevant
duration object is
L<DateTime::Fiction::JRRTolkien::Shire::Duration|DateTime::Fiction::JRRTolkien::Shire::Duration>,
which is B<not> a subclass of L<DateTime::Duration|DateTime::Duration>.

The date portion of the math is done in the order L<month|/month>,
L<week|/week>, L<year|/year>, L<day|/day>. Before adding (or
subtracting) months or weeks from a date that is not part of any month
(or week), that date will be adjusted forward or backward to the nearest
date that is part of a month (or week). The direction of adjustment is
specified by the

lib/DateTime/Fiction/JRRTolkien/Shire.pm  view on Meta::CPAN

L<https://www.glyphweb.com/arda/f/fourthage.html> references a letter sent
by Tolkien in 1958 in which he estimates approximately 6000 years have
passed since the War of the Ring and the end of the Third Age.  (Thanks
to Danny O'Brien from sending me this link).  I took this approximate as
an exact amount and calculated back 6000 years from 1958.  This I set as
the start of the 4th age (1422 S.R.).  Thus the fourth age begins in our
B.C 4042.

According to Appendix D of the Lord of the Rings, leap years in the
hobbits'
calendar are every 4 years unless it is the turn of the century, in which
case it is not a leap year. Our calendar (Gregorian) uses every 4 years
unless it's 100 years unless its 400 years.  So, if no changes have been
made to the hobbits' calendar since the end of the third age, their
calendar would be about 15 days further behind ours now than when the
War of the Ring took place.  Implementing this seemed to me to go
against Tolkien's general habit of converting dates in the novel to our
equivalents to give us a better sense of time.  My thought, at least
right now, is that it is truer to the spirit of things for years to line
up, and for Midyear's day to still be approximately on the summer
solstice.  So instead, I have modified Tolkien's description of the
hobbit calendar so that leap years occur once every 4 years unless it's
100 years unless it's 400 years, so as it matches the Gregorian calendar
in that regard.  These 100 and 400 year intervals occur at different
times in the two calendars, so there is not a one to one correspondence
of days regardless of years.  However, the variations follow a 400 year
cycle.

I<The "I" in the above is Tom Braun -- TRW>

=head1 AUTHOR

Tom Braun <tbraun@pobox.com>

Thomas R. Wyant, III F<wyant at cpan dot org>

=head1 COPYRIGHT AND LICENSE

Copyright (c) 2003 Tom Braun. All rights reserved.

Copyright (C) 2017-2022, 2025 Thomas R. Wyant, III

The calendar implemented on this module was created by J.R.R. Tolkien,
and the copyright is still held by his estate.  The license and
copyright given herein applies only to this code and not to the
calendar itself.

This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself. For more details, see the full text
of the licenses in the LICENSES directory included with this module.

This program is distributed in the hope that it will be useful, but
without any warranty; without even the implied warranty of
merchantability or fitness for a particular purpose.

=head1 SUPPORT

lib/DateTime/Fiction/JRRTolkien/Shire/Duration.pm  view on Meta::CPAN

	$self->{weeks} += $dur->{weeks};
	$self->{duration}->add_duration( $dur->{duration} );
    } elsif ( _isa( $dur, 'DateTime::Duration' ) ) {
	$self->{duration}->add_duration( $dur );
    } else {
	Carp::croak( "Can not do arithmetic on $dur" );
    }
    return $self;
}

sub calendar_duration {
    my ( $self ) = @_;
    return $self->new(
	years	=> $self->delta_years(),
	months	=> $self->delta_months(),
	weeks	=> $self->delta_weeks(),
	days	=> $self->delta_days(),
	end_of_month	=> $self->end_of_month_mode(),
    );
}

lib/DateTime/Fiction/JRRTolkien/Shire/Duration.pm  view on Meta::CPAN


    return $left->clone()->subtract_duration( $right );
}

1;

__END__

=head1 NAME

DateTime::Fiction::JRRTolkien::Shire::Duration - Duration objects for Shire calendar date math

=head1 SYNOPSIS

 use DateTime::Fiction::JRRTolkien::Shire;
 use DateTime::Fiction::JRRTolkien::Shire::Duration;
 
 my $dt  = DateTime::Fiction::JRRTolkien::Shire->new(
     year  => 1419,
     month => 3,
     day   => 25,

lib/DateTime/Fiction/JRRTolkien/Shire/Duration.pm  view on Meta::CPAN

     hours       => 5,
     minutes     => 6,
     seconds     => 7,
     nanoseconds => 8,
     holiday     => 'forward',
 );
 print $dt->add( $dur )->iso8601(), "\n";

=head1 DESCRIPTION

This is a simple class for representing durations in the Shire calendar.
It is B<not> a subclass of L<DateTime::Duration|DateTime::Duration>,
though it implements the same interface, plus some extra bells and
whistles.  Objects of this class are used whenever you do date math with
L<DateTime::Fiction::JRRTolkien::Shire|DateTime::Fiction::JRRTolkien::Shire>.

Unlike L<DateTime::Duration|DateTime::Duration>, this class preserves
years and weeks rather than folding them into months and days
respectively. This is because the Shire calendar contains days that are
not part of any week or month. An example may clarify this.

You would expect adding a week to a Monday to produce the following
Monday. But adding seven days to 30 Forelithe (a Mersday) gives you 4
Afterlithe (a Hevensday) because the interval between these two dates
contains Midsummer's day, which is not part of any week. In a leap year
this would give 3 Afterlithe (a Trewsday) because the leap year day also
falls in this interval and is part of no week. The issues for months are
similar.

A related issue with this calendar is what happens when you try, for
example, to add a month to a date that is not part of any month. When
something like this happens, the date is first adjusted to a nearby date
that B<is> part of a month (or week). By default the adjustment is
forward for a positive delta and backward for a negative delta, though
you can specify the direction of adjustment when the object is
instantiated. So adding a month to 1 Lithe gives 1 Wedmath by default,
but 30 Afterlithe if the adjustment is backward.

=head1 METHODS

t/02accessor.t  view on Meta::CPAN

is( $shire->time(), '10:15:00' );
is( $shire->iso8601(), '1419-03-25S10:15:00' );
is( $shire->datetime(), '1419-03-25S10:15:00' );

my $time = time;
my $shire2 = DateTime::Fiction::JRRTolkien::Shire->from_epoch(epoch => $time);
is($shire2->epoch, $time);
is(int($shire2->hires_epoch), $time);
# utc_rd_values and utc_rd_as_seconds were tested in the constructor tests

is( $shire->calendar_name(), 'Shire', q<Calendar name is 'Shire'> );

# Aliased to DateTime
is( $shire->time_zone()->name(), 'floating', q<Time zone is 'floating'> );
is( $shire->time_zone_long_name(),
    'floating', q<Time zone long name is 'floating'> );
is( $shire->time_zone_short_name(),
    'floating', q<Time zone short name is 'floating'> );

# Holidays

t/11duration.t  view on Meta::CPAN

    cmp_ok( $dur->nanoseconds(), '==', 0, 'nanoseconds() is 0' );

    is_deeply( { $dur->inverse()->deltas() }, {
	    years	=> -1,
	    months	=> -2,
	    weeks	=> -3,
	    days	=> -4,
	    map { $_ => 0 } qw{ minutes seconds nanoseconds },
	}, 'Inverse' );

    is_deeply( { $dur->calendar_duration()->deltas() }, \%want,
	'Calendar duration' );

    is_deeply( { $dur->clock_duration()->deltas() }, {
	    map { $_ => 0 } qw{
		years months weeks days minutes seconds nanoseconds
	    },
	}, 'Clock duration' );

    $dur->add( months => 1, weeks => -1 );

tools/lib/DateTime/Fiction/JRRTolkien/Shire.pm  view on Meta::CPAN

our $VERSION = '0.900_04';

# This assumes all the values in the info hashref are valid, and doesn't do validation
# However, the day and month parameters will be given defaults if not present
sub _recalc_DateTime {
    my ($self, %dt_args) = @_;
    my ($prevleap, $gregleap, $modyear, $yday, $arg);
    my @monthlen = (0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);

    $dt_args{year} = $self->{year} - 5464;
    # $prevleap refers to shire calendar
    $prevleap = 0;
    $prevleap = 1 if ((($self->{year} - 1) % 4 == 0) and (($self->{year} - 1) % 100 != 0));
    $prevleap = 1 if (($self->{year} - 1) % 400 == 0);

    if ($self->{holiday}) {
	if ($self->{leapyear}) {
	    $yday = (0, 1, 182, 183, 184, 185, 366)[$self->{holiday}];
	} else {
	    $yday = (0, 1, 182, 183, 0, 184, 365)[$self->{holiday}];
	}

tools/lib/DateTime/Fiction/JRRTolkien/Shire.pm  view on Meta::CPAN


sub _recalc_Shire {
    my $self = shift;
    my ($yday, $modyear);

    $self->{year} = $self->{dt}->year + 5464;
    $self->{holiday} = 0; #assume this unless we find otherwise
    $yday = $self->{dt}->day_of_year + 9; # + 9 to account fora different year starting points

    # year adjustments are needed since "except every 100 except every
    # 400 year rule applies to different years in the two calendars"
    $modyear = $self->{year} % 400;
    if (($modyear > 300) && ($modyear < 364)) {
	++$yday;
    } elsif ($modyear == 364) {
	++$yday;
    } elsif ((($modyear > 64) && ($modyear < 100)) || (($modyear > 164) && ($modyear < 200))) {
	--$yday;
    } elsif (($modyear == 100) || ($modyear == 200)) {
	--$yday;
    }

tools/lib/DateTime/Fiction/JRRTolkien/Shire.pm  view on Meta::CPAN

    my $self;

    $self->{dt} = DateTime->from_object(%args);
    $self->{recalc} = 1;

    return bless $self, $class;
} # end sub from_object

sub last_day_of_month {
    my ($class, %args) = @_;
    $args{day} = 30; # The shire calendar is nice this way
    return $class->new(%args);
} # end sub last_day_of_month

sub from_day_of_year {
    my ($class, %args) = @_;
    my ($doy, $self, $leap);

    $doy = $args{day_of_year};
    delete $args{day_of_year};

tools/lib/DateTime/Fiction/JRRTolkien/Shire.pm  view on Meta::CPAN

	}
    }

    return $yday;
} # end sub day_of_year

sub doy { return $_[0]->day_of_year };

sub week { return ($_[0]->week_year, $_[0]->week_number); }

sub week_year { return $_[0]->year; } # the shire calendar is nice this way

sub week_number {
    my $self = shift;
    my $yday = $self->day_of_year;

    183 == $yday
	and return 0;	# Midyear's day has no week number
    184 == $yday
	and $self->is_leap_year
	and return 0;	# The Overlithe has no week number either.

tools/lib/DateTime/Fiction/JRRTolkien/Shire.pm  view on Meta::CPAN

    $shire == $shire2;

    # Strings
    print "$shire1\n"; # Prints Sunday 25 Rethe 1419

    # On this date in history
    print $shire->on_date;

=head1 DESCRIPTION
 
Implementation of the calendar used by the hobbits in J.R.R. Tolkien's exceptional
novel The Lord of The Rings, as described in Appendix D of that book 
(except where noted).  The calendar has 12 months, each with 30 days, and 5
holidays that are not part of any month.  A sixth holiday, Overlithe, is added on 
leap years.  The holiday Midyear's Day (and the Overlithe on a leap year) is
not part of any week, which means that the year always starts on Sterday.

This module is a follow on to the Date::Tolkien::Shire module, and is rewritten
to support Dave Rolsky and company's DateTime module.  The DateTime module must
be installed for this module to work.  Unlike the DateTime module, which includes
time support, this calendar does not have any mechanisms for giving a shire 
time (mostly because I've never quite figured out what it should look like).
Time is maintained, however, so that objects can be converted from other
calendars to the shire calendar and then converted back without their time components
being lost.  The same is true of time zones.

=head1 METHODS

Most of these methods mimic their corresponding DateTime methods in functionality.
For additional information on these methods, see the DateTime documentation.

=over 4

=head2 Constructors

tools/lib/DateTime/Fiction/JRRTolkien/Shire.pm  view on Meta::CPAN


Same as in DateTime.  Note that this is equivalent to 
    from_epoch( epoch => time() );

=item * today( ... )

Same as in DateTime.  

=item * from_object( object => $object, ... )

Same as in DateTime.  Takes any other DateTime calendar object and converts it to
a DateTime::Fiction::JRRTolkien::Shire object.

=item * last_day_of_month( ... )

Same as in DateTime.  Like the new constructor, but it does not take a day parameter.  
Instead, the day is set to 30, which is the last day of any month in the shire 
calendar.  A holiday parameter should not be used with this method.  Use new instead.

=item * from_day_of_year( year => $year, day_of_year => $yday)

Same as in DateTime.  Gets the date from the given year and day of year, both
of which must be given.  Hour, minute, second, time_zone, etc. parameters
may also be given, and will be passed to the underlying DateTime object, just
like in new.

=item * clone

tools/lib/DateTime/Fiction/JRRTolkien/Shire.pm  view on Meta::CPAN

=item * holiday_name

Returns the name of the holiday.  If the day is not a holiday, an empty string
is returned.

=item * is_leap_year

Returns 1 if the year is a leap year, and 0 otherwise.  

Leap years are given
the same rule as the Gregorian calendar.  Every four years is a leap year,
except the first year of the century, which is not a leap year.  However,
every fourth century (400 years), the first year of the century is a leap 
year (every 4, except every 100, except every 400).  This is a slight
change from the calendar descibed in Appendix D, which uses the rule of 
once every 4 years, except every 100 years (the same as in the Julian 
calendar).  Given some uncertainty about how many years have passed
since the time in Lord of the Rings (see note below), and the expectations
of most people that the years match up with what they're used to, I have
changed this rule for this implementation.  However, this does mean that 
this calendar implementation is not strictly that described in Appendix D.

=item * week

A two element array, where the first is the week_year and the latter is the week_number.

=item * week_year

This is always the same as the year in the shire calendar, but is present for
compatability with other DateTime objects.

=item * week_number

Returns the week of the year.

=item * epoch

Returns the epoch of the given object, just like in DateTime.

=item * hires_epoch

Returns the epoch as a floating point number, with the fractional portion
for fractional seconds.  Functions the same as in DateTime.

=item * utc_rd_values

Returns the UTC rata die days, seconds, and nanoseconds. Ignores fractional
seconds.  This is the standard method used by other methods to convert 
the shire calendar to other calendars.  See the DateTime documentation for
more information.

=item * utc_rd_as_seconds

Returns the UTC rata die days entirely as seconds.  

=item * on_date

Prints out the current day.  If the day has some events that transpired on it
(as defined in Appendix B of the Lord of the Rings), those events are also printed.

tools/lib/DateTime/Fiction/JRRTolkien/Shire.pm  view on Meta::CPAN

except for time_zone.  This is used in much the same way as new, with the 
exception that any parameters not given will be left as is.

All parameters are optional, with the current values inserted if the values are not
supplied.  However, with holidays not falling in any month, it is recommended
that a day and month always be given together.  Otherwise, unanticipated
results may occur.

As in the new constructor, time parameters have no effect on the shire dates 
returned.  However, they are maintained in case the object is converted to another
calendar which supports time.

=item * Truncate( ... )

Same as in DateTime.  If the date is a holiday, a truncation to either
'month' or 'day' is equivalent.  Otherwise, this functions as specified in the
DateTime object.

=item * set_time_zone( $tz )

Just like in DateTime.  This method has no effect on the shire calendar, but be
stored with the date if it is ever converted to another calendar with time support.

=head2 Comparisons and Stringification

All comparison operators should work, just as in DateTime.  In addition,
all DateTime::Fiction::JRRTolkien::Shire objects will interpolate into
a string representing the date when used in a double-quoted string.  

=back

=head1 DURATIONS AND DATE MATH

tools/lib/DateTime/Fiction/JRRTolkien/Shire.pm  view on Meta::CPAN

=head1 NOTE: YEAR CALCULATION

http://www.glyhweb.com/arda/f/fourthage.html references a letter sent by
Tolkien in 1958 in which he estimates approxiimately 6000 years have passed
since the War of the Ring and the end of the Third Age.  (Thanks to Danny
O'Brien from sending me this link).  I took this approximate as an exact amount
and calculated back 6000 years from 1958.  This I set as the start of the 
4th age (1422 S.R.).  Thus the fourth age begins in our B.C 4042.

According to Appendix D of the Lord of the Rings, leap years in hobbit
calendar are every 4 years unless its the turn of the century, in which
case it's not a leap year.  Our calendar (Gregorian) uses every 4 years unless it's 
100 years unless its 400 years.  So, if no changes have been made to 
the hobbit's calendar since the end of the third age, their calendar would
be about 15 days further behind ours now then when the War of the Ring took
place.  Implementing this seemed to me to go against Tolkien's general habit
of converting dates in the novel to our equivalents to give us a better
sense of time.  My thoughts, at least right now, is that it is truer to the
spirit of things for years to line up, and for Midyear's day to still be 
approximately on the summer solstice.  So instead, I have modified Tolkien's 
description of the hobbit 
calendar so that leap years occur once every 4 years unless it's 100
years unless it's 400 years, so as it matches the Gregorian calendar in that
regard.  These 100 and 400 year intervals occur at different times in
the two calendars, so there is not a one to one correspondence
of days regardless of years.  However, the variations follow a 400 year cycle.

=head1 AUTHOR

Tom Braun <tbraun@pobox.com>

=head1 LICENSE AND COPYRIGHT

Copyright (c) 2003 Tom Braun.  All rights reserved.  This program is
free software; you can redistribute it and/or modify it under the same
terms as Perl itself.
                                                                                
The calendar implemented on this module was created by J.R.R. Tolkien,
and the copyright is still held by his estate.  The license and 
copyright given herein applies only to this code and not to the 
calendar itself.
                                                                   
The full text of the license can be found in the LICENSE file included
with this module.

=head1 SUPPORT

Support on this module may be obtained by emailing me.  However,
I am not a developer on the other classes in the DateTime project.  For
support on them, please see the support options in the DateTime documentation.

tools/make-regression  view on Meta::CPAN

    object	=> DateTime->new(
	year	=> $yr,
	month	=> $mon,
	day	=> $day,
    ),
);
EOD

	no warnings qw{ qw };
	foreach my $method ( qw{
	    #calendar_name
	    #clone
	    day
	    day_name
	    day_name_trad
	    day_of_month
	    day_of_week
	    day_of_year
	    dow
	    doy
	    epoch



( run in 0.552 second using v1.01-cache-2.11-cpan-5dc5da66d9d )