Tom Wyant
and 2 contributors

NAME

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

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,
                                                          month => 3,
                                                          day => 25);
    my $shire = DateTime::Fiction::JRRTolkien::Shire->new(year => 1419,
                                                          holiday => '2 Lithe');

    my $shire = DateTime::Fiction::JRRTolkien::Shire->from_epoch(
        epoch = $time);
    my $shire = DateTime::Fiction::JRRTolkien::Shire->today;
        # same as from_epoch(epoch = time());

    my $shire = DateTime::Fiction::JRRTolkien::Shire->from_object(
        object => $some_other_DateTime_object);
    my $shire = DateTime::Fiction::JRRTolkien::Shire->from_day_of_year(
        year => 1420,
        day_of_year => 182);
    my $shire2 = $shire->clone;

    # Accessors
    $year = $shire->year;
    $month = $shire->month;            # 1 - 12, or 0 on a holiday
    $month_name = $shire->month_name;
    $day = $shire->day;                # 1 - 30, or 0 on a holiday

    $dow = $shire->day_of_week;        # 1 - 7, or 0 on certain holidays
    $day_name = $shire->day_name;

    $holiday = $shire->holiday;
    $holiday_name = $shire->holiday_name;

    $leap = $shire->is_leap_year;

    $time = $shire->epoch;
    @rd = $shire->utc_rd_values;

    # Set Methods
    $shire->set(year => 7463,
                month => 5,
                day => 3);
    $shire->set(year => 7463,
                holiday => 6);
    $shire->truncate(to => 'month');

    # Comparisons
    $shire < $shire2;
    $shire == $shire2;

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

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

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.

This module provides support for most DateTime functionality, with the known exception of format_cldr(), which may be added later.

Support for strftime() comes from Date::Tolkien::Shire::Data, and you should see the documentation for that module for the details of the formatting codes.

Some assumptions have had to be made on how the hobbits represent time. We have references to (e.g.) "nine o'clock" (in the morning), which seem to imply they start the day at midnight. But there appears to be nothing to say whether they used a 12- or 24-hour clock. Default time formats (say, '%X') use a 12-hour clock because that is the English system and Tolkien did not specify anything to the contrary.

Calendar quarters are not mentioned at all in any of Tolkien's writings (that I can find -- Wyant), but are part of the DateTime interface. This package implements a quarter as being exactly 13 weeks, with Midyear's day and Overlithe not being part of any quarter, on no better justification than that the present author thinks that is consistent with the Shire's approach to horology.

METHODS

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

Constructors

new

 my $dt_ring = DateTime::Fiction::JRRTolkien::Shire->new(
     year   => 1419,
     month  => 3,
     day    => 25,
 );
 my $dt_aa = DateTime::Fiction::JRRTolkien::Shire->new(
     year    => 1419,
     holiday => 3,     # Midyear's day
 );

This method takes a year, month, and day parameter, or a year and holiday parameter. The year can be any value. The month can be specified with a string giving the name of the month (the same string that would be returned by month_name, with the first letter capitalized and the rest in lower case) or by giving the numerical value for the month, between 1 and 12. The day should always be between 1 and 30. If a holiday is given instead of a day and month, it should be the name of the holiday as returned by holiday_name (with the first letter of each word capitalized) or a value between 1 and 6. The 1 through 6 numbers map to holidays as follows:

    1 => 2 Yule
    2 => 1 Lithe
    3 => Midyear's Day
    4 => Overlithe      # Leap years only
    5 => 2 Lithe
    6 => 1 Yule

The new() method will also take parameters for hour, minute, second, nanosecond, time_zone and locale. If given, these parameters will be stored in case the object is converted to another class that makes use of these attributes.

Additionally, parameters accented and traditional control the form of on_date() text (accented or not) and week day names (traditional or common) generated. These must be undef, '', or 0 (for false) or 1 (for true).

If a day is not given, it will default to 1. If neither a day or month is given, the date will default to 2 Yule, the first day of the year.

from_epoch

     $dts = DateTime::Fiction::JRRTolkien::Shire->from_epoch(
         epoch  => time,
         ...
     );

Same as in DateTime, but you can also specify parameters accented and traditional (see new()).

now

    $dts = DateTime::Fiction::JRRTolkien::Shire->now( ... );

Same as in DateTime, but you can also specify parameters accented and traditional (see new()). Note that this is equivalent to

    from_epoch( epoch => time() );

and produces an object whose time zone is UTC.

now_local

    $dts = DateTime::Fiction::JRRTolkien::Shire->now_local( ... );

This static method creates a new object set to the current local time. Under the hood it just calls the localtime() built-in, and then calls new() with the results. Unlike now(), this method produces an object whose zone is floating.

today

    $dts = DateTime::Fiction::JRRTolkien::Shire->today( ... );

Same as in DateTime, but you can also specify parameters accented and traditional (see new()).

from_object

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

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

last_day_of_month

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

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.

from_day_of_year

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

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().

clone

    $dts2 = $dts->clone();

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

"Get" Methods

calendar_name

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

Returns 'Shire'.

year

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

Returns the year.

month

    print 'Month: ', $dts->month(), "\n";

Returns the month number, from 1 to 12. If the date is a holiday, a 0 is returned for the month.

mon

Synonym for month().

month_name

    print 'Month name: ', $dts->month_name(), "\n";

Returns the name of the month. If the date is a holiday, an empty string is returned.

day_of_month

    print 'Day of month: ', $dts->day_of_month(), "\n";

Returns the day of the current month, from 1 to 30. If the date is a holiday, 0 is returned.

day

Synonym for day_of_month().

mday

Synonym for day_of_month().

day_of_week

    print 'Day of week: ', $dts->day_of_week(), "\n";

Returns the day of the week from 1 to 7. If the day is not part of any week (Midyear's Day or the Overlithe), 0 is returned.

wday

Synonym for day_of_week.

dow

Synonym for day_of_week.

day_name

    print 'Common name of day of week: ',
        $dts->day_name(), "\n";

Returns the common name of the day of the week, or an empty string if the day is not part of any week. This method is not affected by the traditional() setting, for historical reasons.

day_name_trad

    print 'Traditional name of day of week: ',
        $dts->day_name_trad(), "\n";

Returns the common name of the day of the week, or an empty string if the day is not part of any week. This method is not affected by the traditional() setting, for historical reasons.

day_abbr

    print 'Common abbreviation of day of week: ',
        $dts->day_abbr(), "\n";

Returns the common abbreviation of the day of the week, or an empty string if the day is not part of any week. This method is not affected by the traditional() setting, for consistency with day_name().

day_abbr_trad

    print 'Traditional abbreviation of day of week: ',
        $dts->day_abbr_trad(), "\n";

Returns the traditional abbreviation of the day of the week, or an empty string if the day is not part of any week. This method is not affected by the traditional() setting, for consistency with day_name_trad().

day_of_year

    print 'Day of year: ', $dts->day_of_year(), "\n";

Returns the day of the year, from 1 to 366

doy

Synonym for day_of_year().

holiday

    print 'Holiday number: ', $dts->holiday(), "\n";

Returns the holiday number (given in the description of the new() constructor). If the day is not a holiday, 0 is returned.

holiday_name

    print 'Holiday name: ', $dts->holiday_name(), "\n";

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

holiday_abbr

    print 'Holiday abbreviation: ', $dts->holiday_abbr(), "\n";

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

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.

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.

week_number

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

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

week

    printf "Year %d; Week number %d\n", $dts->week();

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

weekday_of_month

Same as DateTime, but returns 0 for a holiday.

week_of_month

Same as DateTime, but returns nothing (undef in scalar context) for a holiday. The return for a holiday can not be 0, because this is a valid return, e.g. for 1 Rethe.

epoch

    print scalar gmtime $dts->epoch(), "UT\n";

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

hires_epoch

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

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 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.

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.

quarter_name

Returns the name of the quarter.

quarter_abbr

Returns the abbreviation of the quarter.

day_of_quarter

Returns the day of the date in the quarter, in the range 1 to 91. If the day is Midyear's day or the Overlithe, you get 1.

era_name

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

era_abbr

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

christian_era

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

secular_era

Returns the same thing era_abbr() does.

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.

utc_rd_as_seconds

Returns the UTC rata die days entirely as seconds.

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 on it (as defined in Appendix B of the Lord of the Rings), those events are appended. This can be fun to put in a .bashrc or .cshrc. Try

    perl -MDateTime::Fiction::JRRTolkien::Shire
      -le 'print DateTime::Fiction::JRRTolkien::Shire->now->on_date;'

iso8601

This is not, of course, a true ISO-8601 implementation. The differences are that holidays are represented by their abbreviations (e.g. '1419-Myd', and that the date and time are separated by the letter 'S', not 'T'.

strftime

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

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

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

accented

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

traditional

This method returns a true value if the dates returned by on_date(), strftime(), and stringification are to use traditional rather than common weekday names.

"Set" Methods

set

    $dts->set(
        month   => 3,
        day     => 25,
    );

Allows the day, month, and year to be changed. It takes any parameters allowed by the 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 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 set_*() methods from DateTime are provided. In addition, you get the following:

set_holiday

This convenience method is implemented in terms of

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

set_accented

This convenience method is implemented in terms of

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

set_traditional

This convenience method is implemented in terms of

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

truncate

    $dts->truncate( to => 'day' );

Like the corresponding DateTime method, with the following exceptions:

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

Similarly, if the date is Midyear's day or the Overlithe, truncation to 'week', 'local_week', or 'quarter' is equivalent to truncation to '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 'week' and 'local_week' truncate to that day.

There is no textual justification for quarters, but they are in the 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.

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.

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.

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 DateTime::Fiction::JRRTolkien::Shire::Duration, which is not a subclass of DateTime::Duration.

The date portion of the math is done in the order month, week, year, 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 DateTime::Fiction::JRRTolkien::Shire::Duration object; see its documentation for the details. The order of operation was chosen to ensure that only one such adjustment would be necessary for any computation.

add

This convenience method takes as arguments either a DateTime::Fiction::JRRTolkien::Shire::Duration object or the arguments needed to manufacture one. The duration is then passed to add_duration().

add_duration

This method takes as its argument a DateTime::Fiction::JRRTolkien::Shire::Duration object. This is added to the invocant (i.e. it is a mutator). The invocant is returned.

subtract

This convenience method takes as arguments either a DateTime::Fiction::JRRTolkien::Shire::Duration object or the arguments needed to manufacture one. The duration is then passed to subtract_duration().

subtract_duration

This convenience method takes as its argument a DateTime::Fiction::JRRTolkien::Shire::Duration object. The inverse of this object is then passed to add_duration().

subtract_datetime

This takes as its argument a DateTime::Fiction::JRRTolkien::Shire object. The return is a DateTime::Fiction::JRRTolkien::Shire::Duration object representing the difference between the two objects. If either the invocant or the argument represents a holiday, the date portion of this difference will contain years and days. Otherwise it will contain years, months and days.

subtract_datetime_absolute, delta_days, delta_md, delta_ms

These are just delegated to the corresponding DateTime method. The argument can be either a DateTime::Fiction::JRRTolkien::Shire object or a DateTime object.

NOTE: YEAR CALCULATION

http://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.

AUTHOR

Tom Braun <tbraun@pobox.com>

Thomas R. Wyant, III wyant at cpan dot org

COPYRIGHT AND LICENSE

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

Copyright (C) 2017 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.

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.

BIBLIOGRAPHY

Tolkien, J. R. R. Return of the King. New York: Houghton Mifflin Press, 1955.

http://www.glyphweb.com/arda/f/fourthage.html

SEE ALSO

The DateTime project documentation (perldoc DateTime, datetime@perl.org mailing list, or http://datetime.perl.org/).