NAME¶
Date::Convert - Convert Between any two Calendrical Formats
SYNOPSIS¶
use Date::DateCalc;
$date=new Date::Convert::Gregorian(1997, 11, 27);
@date=$date->date;
convert Date::Convert::Hebrew $date;
print $date->date_string, "\n";
Currently defined subclasses:
Date::Convert::Absolute
Date::Convert::Gregorian
Date::Convert::Hebrew
Date::Convert::Julian
Date::Convert is intended to allow you to convert back and forth between any
arbitrary date formats (ie. pick any from: Gregorian, Julian, Hebrew,
Absolute, and any others that get added on). It does this by having a separate
subclass for each format, and requiring each class to provide standardized
methods for converting to and from the date format of the base class. In this
way, instead of having to code a conversion routine for going between and two
arbitrary formats foo and bar, the function only needs to convert foo to the
base class and the base class to bar. Ie:
Gregorian <--> Base class <--> Hebrew
The base class includes a
Convert method to do this transparently.
Nothing is exported because it wouldn't make any sense to export. :)
DESCRIPTION¶
Fucntion can be split into several categories:
- •
- Universal functions available for all subclasses (ie. all formats). The
fundamental conversion routines fit this category.
- •
- Functions that are useful but don't necessarily make sense for all
subclasses. The overwhelming majority of functions fall into this
category. Even such seemingly universal concepts as year, for instance,
don't apply to all date formats.
- •
- Private functions that are required of all subclasses, ie.
initialize. These should not be called by users.
Here's the breakdown by category:
Functions Defined for all Subclasses
- new
- Create a new object in the specified format with the specified start
paramaters, ie. "$date = new Date::Convert::Gregorian(1974, 11,
27)". The start parameters vary with the subclass. My personal
preference is to order in decreasing order of generality (ie. year first,
then month, then day, or year then week, etc.)
This can have a default date, which should probably be
"today".
- date
- Extract the date in a format appropriate for the subclass. Preferably this
should match the format used with new, so
(new date::Convert::SomeClass(@a))->date;
should be an identity function on @a if @a was in a legitmate format.
- date_string
- Return the date in a pretty format.
- convert
- Change the date to a new format.
Non-universal functions
- year
- Return just the year element of date.
- month
- Just like year.
- day
- Just like year and month.
- is_leap
- Boolean. Note that (for ::Hebrew and ::Gregorian, at least!)
this can be also be used as a static. That is, you can either say
$date->is_leap or is_leap Date::Convert::Hebrew 5757
Private functions that are required of all subclasses
You shouldn't call these, but if you want to add a class, you'll need to write
them! Or it, since at the moment, there's only one.
- initialize
- Read in args and initialize object based on their values. If there are no
args, initialize with the base class's initialize (which will initialize
in the default way described above for new.) Note the American
spelling of "initialize": "z", not "s".
SUBCLASS SPECIFIC NOTES¶
Absolute
The "Absolute" calendar is just the number of days from a certain
reference point. Calendar people should recognize it as the "Julian Day
Number" with one minor modification: When you convert a Gregorian day n
to absolute, you get the JDN of the Gregorian day from noon on.
Since "absolute" has no notion of years it is an extremely easy
calendar for conversion purposes. I stole the "absolute" calendar
format from Reingold's emacs calendar mode, for debugging purposes.
The subclass is little more than the base class, and as the lowest common
denominator, doesn't have any special functions.
Gregorian
The Gregorian calendar is a purely solar calendar, with a month that is only an
approximation of a lunar month. It is based on the old Julian (Roman)
calendar. This is the calendar that has been used by most of the Western world
for the last few centuries. The time of its adoption varies from country to
country. This
::Gregorian allows you to extrapolate back to 1 A.D., as
per the prorgamming tradition, even though the calendar definitely was not in
use then.
In addition to the required methods,
Gregorian also has
year,
month,
day, and
is_leap methods. As mentioned above,
is_leap can also be used statically.
Hebrew
This is the traditional Jewish calendar. It's based on the solar year, on the
lunar month, and on a number of additional rules created by Rabbis to make
life tough on people who calculate calendars. :) If you actually wade through
the source, you should note that the seventh month really does come before the
first month, that's not a bug.
It comes with the following additional methods:
year,
month,
day,
is_leap,
rosh,
part_add, and
part_mult.
rosh returns the absolute day corresponding to
"Rosh HaShana" (New year) for a given year, and can also be invoked
as a static.
part_add and
part_mult are useful functions for
Hebrew calendrical calculations are not for much else; if you're not familiar
with the Hebrew calendar, don't worry about them.
Islamic
The traditional Muslim calendar, a purely lunar calendar with a year that is a
rough approximation of a solar year. Currently unimplemented.
Julian
The old Roman calendar, allegedly named for Julius Caesar. Purely solar, with a
month that is a rough approximation of the lunar month. Used extensively in
the Western world up to a few centuries ago, then the West gradually switched
over to the more accurate Gregorian. Now used only by the Eastern Orthodox
Church, AFAIK.
ADDING NEW SUBCLASSES¶
This section describes how to extend
Date::Convert to add your favorite
date formats. If you're not interested, feel free to skip it. :)
There are only three function you
have to write to add a new subclass:
you need
initialize,
date, and
date_string. Of course,
helper functions would probably help. . . You do
not need to write a
new or
convert function, since the base class handles them
nicely.
First, a quick conceptual overhaul: the base class uses an "absolute day
format" (basically "Julian day format") borrowed from
emacs. This is just days numbered absolutely from an extremely long
time ago. It's really easy to use, particularly if you have emacs and emacs'
calendar mode. Each Date::Convert object is a reference to a hash (as
in all OO perl) and includes a special "absol" value stored under a
reserved "absol" key. When
initialize initializes an object,
say a Gregorian date, it stores whatever data it was given in the object and
it also calculates the "absol" equivalent of the date and stores it,
too. If the user converts to another date, the object is wiped clean of all
data except "absol". Then when the
date method for the new
format is called, it calculates the date in the new format from the
"absol" data.
Now that I've thoroughly confused you, here's a more compartmentalized version:
- initialize
- Take the date supplied as argument as appropriate to the format, and
convert it to "absol" format. Store it as $$self{'absol'}. You
might also want to store other data, ie. ::Gregorian stores
$$self{'year'}, $$self{'month'}, and $$self{'day'}. If no args are
supplied, explicitly call the base class's initialize, ie.
"Date::Convert::initialize", to initialize with a default
'absol' date and nothing else.
NOTE: I may move the default behavior into the new constructor.
- date
- Return the date in a appropriate format. Note that the only fact that
date can take as given is that $$self{'absol'} is defined, ie. this
object may not have been initialized by the initialize of
this object's class. For instance, you might have it check if
$$self{'year'} is defined. If it is, then you have the year component,
otherwise, you calculate year from $$self{'absol'}.
- date_string
- This is the easy part. Just call date, then return a pretty string based
on the values.
NOTE: The
::Absolute subclass is a special case, since it's nearly
an empty subclass (ie. it's just the base class with the required methods
filled out). Don't use it as an example! The easiest code to follow would have
been
::Julian except that Julian inherits from
::Gregorian.
Maybe I'll reverse that. . .
EXAMPLES¶
#!/usr/local/bin/perl5 -w
use Date::Convert;
$date=new Date::Convert::Gregorian(1974, 11, 27);
convert Date::Convert::Hebrew $date;
print $date->date_string, "\n";
My Gregorian birthday is 27 Nov 1974. The above prints my Hebrew birthday.
convert Date::Convert::Gregorian $date;
print $date->date_string, "\n";
And that converts it back and prints it in Gregorian.
$guy = new Date::Convert::Hebrew (5756, 7, 8);
print $guy->date_string, " -> ";
convert Date::Convert::Gregorian $guy;
print $guy->date_string, "\n";
Another day, done in reverse.
@a=(5730, 3, 2);
@b=(new Date::Convert::Hebrew @a)->date;
print "@a\n@b\n";
The above should be an identity for any list @a that represents a legitimate
date.
#!/usr/local/bin/perl -an
use Date::Convert;
$date = new Date::Convert::Gregorian @F;
convert Date::Convert::Hebrew $date;
print $date->date_string, "\n";
And that's a quick Greg -> Hebrew conversion program, for those times when
people ask.
SEE ALSO¶
perl(1),
Date::DateCalc(3)
VERSION¶
Date::Convert 0.15 (pre-alpha)
AUTHOR¶
Mordechai T. Abzug <morty@umbc.edu>
ACKNOWLEDGEMENTS AND FURTHER READING¶
The basic idea of using astronomical dates as an intermediary between all
calculations comes from Dershowitz and Reingold. Reingold's code is the basis
of emacs's calendar mode. Two papers describing their work (which I used to
own, but lost! Darn.) are:
``Calendrical Calculations'' by Nachum Dershowitz and Edward M. Reingold,
Software--Practice and Experience, Volume 20, Number 9 (September,
1990), pages 899-928. ``Calendrical Calculations, Part II: Three Historical
Calendars'' by E. M. Reingold, N. Dershowitz, and S. M. Clamen,
Software--Practice and Experience, Volume 23, Number 4 (April, 1993),
pages 383-404.
They were also scheduled to come out with a book on calendrical calculations in
Dec. 1996, but as of March 1997, it still isn't out yet.
The Hebrew calendrical calculations are largely based on a cute little English
book called
The Hebrew Calendar (I think. . .) in a box somewhere at my
parents' house. (I'm organized, see!) I'll have to dig around next time I'm
there to find it. If you want to access the original Hebrew sources, let me
give you some advice: Hilchos Kiddush HaChodesh in the Mishneh Torah is not
the Rambam's most readable treatment of the subject. He later wrote a little
pamphlet called "MaAmar HaEibur" which is both more complete and
easier to comprehend. It's included in "Mich't'vei HaRambam" (or
some such; I've
got to visit that house), which was reprinted just a
few years ago.
Steffen Beyer's Date::DateCalc showed me how to use MakeMaker and write POD
documentation. Of course, any error is my fault, not his!
COPYRIGHT¶
Copyright 1997 by Mordechai T. Abzug
LICENSE STUFF¶
You can distribute, modify, and otherwise mangle Date::Convert under the same
terms as perl.