r16229 - in /branches/upstream/libdate-convert-perl: ./ current/ current/t/

sgran at users.alioth.debian.org sgran at users.alioth.debian.org
Sun Mar 2 01:57:14 UTC 2008


Author: sgran
Date: Sun Mar  2 01:57:13 2008
New Revision: 16229

URL: http://svn.debian.org/wsvn/?sc=1&rev=16229
Log:
[svn-inject] Installing original source of libdate-convert-perl

Added:
    branches/upstream/libdate-convert-perl/
    branches/upstream/libdate-convert-perl/current/
    branches/upstream/libdate-convert-perl/current/CHANGES
    branches/upstream/libdate-convert-perl/current/Convert.pm
    branches/upstream/libdate-convert-perl/current/INSTALL
    branches/upstream/libdate-convert-perl/current/Makefile.PL
    branches/upstream/libdate-convert-perl/current/README
    branches/upstream/libdate-convert-perl/current/TO-DO
    branches/upstream/libdate-convert-perl/current/t/
    branches/upstream/libdate-convert-perl/current/t/absolute.t
    branches/upstream/libdate-convert-perl/current/t/heb_and_greg.t
    branches/upstream/libdate-convert-perl/current/t/hebrew.t
    branches/upstream/libdate-convert-perl/current/t/identity.t
    branches/upstream/libdate-convert-perl/current/t/julian.t

Added: branches/upstream/libdate-convert-perl/current/CHANGES
URL: http://svn.debian.org/wsvn/branches/upstream/libdate-convert-perl/current/CHANGES?rev=16229&op=file
==============================================================================
--- branches/upstream/libdate-convert-perl/current/CHANGES (added)
+++ branches/upstream/libdate-convert-perl/current/CHANGES Sun Mar  2 01:57:13 2008
@@ -1,0 +1,10 @@
+
+0.16:
+	- BUG: Hebrew broken, off-by-one error in rosh calulations
+
+0.15:
+	- BUG: no initialize for Julian!  How embarassing.
+	- reworded docs to replace "Absolute" for "Astro"
+
+0.14:
+	- first public release

Added: branches/upstream/libdate-convert-perl/current/Convert.pm
URL: http://svn.debian.org/wsvn/branches/upstream/libdate-convert-perl/current/Convert.pm?rev=16229&op=file
==============================================================================
--- branches/upstream/libdate-convert-perl/current/Convert.pm (added)
+++ branches/upstream/libdate-convert-perl/current/Convert.pm Sun Mar  2 01:57:13 2008
@@ -1,0 +1,876 @@
+
+package Date::Convert;
+
+use Carp;
+
+$VERSION="0.16";
+
+
+$VERSION=$VERSION; # to make -w happy.  :)
+
+# methods that every class should have:
+# initialize, day, date, date_string
+
+# methods that are recommended if applicable:
+# year, month, day, is_leap
+
+
+$BEGINNING=1721426; # 1 Jan 1 in the Gregorian calendar, although technically, 
+                    # the Gregorian calendar didn't exist at the time.
+$VERSION_TODAY=2450522; # today in JDN, when I wrote this.
+
+
+sub new { # straight out of the perlobj manpage:
+    my $class = shift;
+    my $self = {};
+    bless $self, $class;
+    $self->initialize(@_);
+    return $self;
+}
+
+
+sub initialize {
+    my $self = shift;
+    my $val  = shift || $VERSION_TODAY;
+    carp "Date::Convert is not reliable before Absolute $BEGINNING" 
+	if $val < $BEGINNING;
+    $$self{absol}=$val;
+}
+
+
+
+sub clean {
+    my $self  = shift;
+    my $key;
+    foreach $key (keys %$self) {
+	delete $$self{$key} unless $key eq 'absol';
+    }
+}
+
+
+
+sub convert {
+    my $class = shift;
+    my $self  = shift;
+    $self->clean;
+    bless $self, $class;
+}
+
+
+
+
+sub absol {
+    my $self = shift;
+    return $$self{absol};
+}
+
+
+
+
+
+package Date::Convert::Gregorian;
+
+use Carp;
+ at ISA = qw ( Date::Convert );
+
+$GREG_BEGINNING=1721426; # 1 Jan 1 in the Gregorian calendar, although
+                    # technically, the Gregorian calendar didn't exist at
+                    # the time.
+ at MONTHS_SHORT  = qw ( nil Jan Feb Mar Apr May Jun July Aug Sep Oct Nov Dec );
+ at MONTH_ENDS    = qw ( 0   31  59  90  120 151 181  212 243 273 304 334 365 );
+ at LEAP_ENDS     = qw ( 0   31  60  91  121 152 182  213 244 274 305 335 366 );
+
+$NORMAL_YEAR    = 365;
+$LEAP_YEAR      = $NORMAL_YEAR + 1;
+$FOUR_YEARS     = 4 * $NORMAL_YEAR + 1; # one leap year every four years
+$CENTURY        = 25 * $FOUR_YEARS - 1; # centuries aren't leap years . . .
+$FOUR_CENTURIES = 4 * $CENTURY + 1;     # . . .except every four centuries.
+
+
+sub year {
+    my $self = shift;
+    return $$self{year} if exists $$self{year}; # no point recalculating.
+    my $days;
+    my $year;
+    # note:  years and days are initially days *before* today, rather than
+    # today's date.  This is because of fenceposts.  :)
+    $days =  $$self{absol} - $GREG_BEGINNING;
+    if (($days+1) % $FOUR_CENTURIES) { # normal case
+	$year =  int ($days / $FOUR_CENTURIES) * 400;
+	$days %= $FOUR_CENTURIES;
+	$year += int ($days / $CENTURY) * 100; # years.
+	$days %= $CENTURY;
+	$year += int ($days / $FOUR_YEARS) * 4;
+	$days %= $FOUR_YEARS;
+	if (($days+1) % $FOUR_YEARS) {
+	    $year += int ($days / $NORMAL_YEAR); # fence post from year 1
+	    $days %= $NORMAL_YEAR; 
+	    $days += 1; # today
+	    $year += 1;
+	} else {
+	    $year += int ($days / $NORMAL_YEAR + 1) - 1;
+	    $days =  $LEAP_YEAR;
+	}
+    } else { # exact four century boundary.  Uh oh. . .
+	$year =  int ($days / $FOUR_CENTURIES + 1) * 400;
+	$days =  $LEAP_YEAR; # correction for later.
+    }
+    $$self{year}=$year;
+    $$self{days_into_year}=$days;
+    return $year;
+}
+
+
+
+
+sub is_leap {
+    my $self = shift;
+    my $year = shift || $self->year; # so is_leap can be static or method
+    return 0 if (($year %4) || (($year % 400) && !($year % 100)));
+    return 1;
+}
+
+
+sub month {
+    my $self = shift;
+    return $$self{month} if exists $$self{month};
+    my $year = $self -> year;
+    my $days = $$self{days_into_year};
+    my $MONTH_REF = \@MONTH_ENDS;
+    $MONTH_REF = \@LEAP_ENDS if ($self->is_leap);
+    my $month= 13 - (grep {$days <= $_} @$MONTH_REF);
+    $$self{month} = $month;
+    $$self{day}   = $days-@$MONTH_REF[$month-1];
+    return $month;
+}
+
+
+
+sub day {
+    my $self = shift;
+    return $$self{day} if exists $$self{day};
+    $self->month; # calculates day as a side-effect
+    return $$self{day};
+}
+
+
+
+sub date {
+    my $self = shift;
+    return ($self->year, $self->month, $self->day);
+}
+
+
+
+sub date_string {
+    my $self  = shift;
+    my $year  = $self->year;
+    my $month = $self->month;
+    my $day   = $self->day;
+    return "$year $MONTHS_SHORT[$month] $day";
+}
+
+
+
+
+sub initialize {
+    my $self = shift;
+    my $year = shift || return Date::Convert::initialize;
+    my $month= shift ||
+	croak "Date::Convert::Gregorian::initialize needs more args";
+    my $day  = shift ||
+	croak "Date::Convert::Gregorian::initialize needs more args";
+    warn "These routines don't work well for Gregorian before year 1"
+	if $year<1;
+    my $absol = $GREG_BEGINNING;
+    $$self{'year'} = $year;
+    $$self{'month'}= $month;
+    $$self{'day'}  = $day;
+    my $is_leap = is_leap Date::Convert::Gregorian $year;
+    $year --;  #get years *before* this year.  Makes math easier.  :)
+    # first, convert year into days. . .
+    $absol += int($year/400)*$FOUR_CENTURIES;
+    $year  %= 400;
+    $absol += int($year/100)*$CENTURY;
+    $year  %= 100;
+    $absol += int($year/4)*$FOUR_YEARS;
+    $year  %= 4;
+    $absol += $year*$NORMAL_YEAR;
+    # now, month into days.
+    croak "month number $month out of range" 
+	if $month < 1 || $month >12;
+    my $MONTH_REF=\@MONTH_ENDS;
+    $MONTH_REF=\@LEAP_ENDS if $is_leap;
+    croak "day number $day out of range for month $month"
+	if $day<1 || $day+$$MONTH_REF[$month-1]>$$MONTH_REF[$month];
+    $absol += $day+$$MONTH_REF[$month-1]-1;
+    $$self{absol}=$absol;
+}
+
+
+
+
+
+package Date::Convert::Hebrew;
+use Carp;
+ at ISA = qw ( Date::Convert );
+
+$HEBREW_BEGINNING = 347996; # 1 Tishri 1
+
+                                # @MONTH       = (29,   12, 793);
+ at NORMAL_YEAR = (354,   8, 876); # &part_mult(12,  @MONTH);
+ at LEAP_YEAR   = (383,  21, 589); # &part_mult(13,  @MONTH);
+ at CYCLE_YEARS = (6939, 16, 595); # &part_mult(235, @MONTH);
+ at FIRST_MOLAD = ( 1,  5, 204);
+ at LEAP_CYCLE  = qw ( 3 6 8 11 14 17 0 );
+
+ at MONTHS = ('Nissan', 'Iyyar', 'Sivan', 'Tammuz', 'Av',
+	'Elul', 'Tishrei', 'Cheshvan', 'Kislev', 'Teves',
+	'Shevat', 'Adar', 'Adar II' );
+
+# In the Hebrew calendar, the year starts in the seventh month, there can
+# be a leap month, and there are two months with a variable number of days.
+# Rather than calculate do the actual math, let's set up lookup tables based
+# on year length.  :)
+
+%MONTH_START=
+    ('353' => [177, 207, 236, 266, 295, 325, 1, 31, 60, 89, 118, 148],
+     '354' => [178, 208, 237, 267, 296, 326, 1, 31, 60, 90, 119, 149],
+     '355' => [179, 209, 238, 268, 297, 327, 1, 31, 61, 91, 120, 150],
+     '383' => [207, 237, 266, 296, 325, 355, 1, 31, 60, 89, 118, 148, 178],
+     '384' => [208, 238, 267, 297, 326, 356, 1, 31, 60, 90, 119, 149, 179],
+     '385' => [209, 239, 268, 298, 327, 357, 1, 31, 61, 91, 120, 150, 180]);
+
+sub is_leap {
+    my $self = shift;
+    my $year = shift;
+    $year=$self->year if ! defined $year;
+    my $mod=$year % 19;
+    return scalar(grep {$_==$mod} @LEAP_CYCLE);
+}
+
+
+sub initialize {
+    my $self = shift;
+    my $year = shift || return Date::Convert::initialize;
+    my $month= shift ||
+	croak "Date::Convert::Hebrew::initialize needs more args";
+    my $day  = shift ||
+	croak "Date::Convert::Hebrew::initialize needs more args";
+    warn "These routines don't work well for Hebrew before year 1"
+	if $year<1;
+    $$self{year}=$year; $$self{$month}=$month; $$self{day}=$day;
+    my $rosh=$self->rosh;
+    my $year_length=(rosh Date::Convert::Hebrew ($year+1))-$rosh;
+    carp "Impossible year length" unless defined $MONTH_START{$year_length};
+    my $months_ref=$MONTH_START{$year_length};
+    my $days=$$months_ref[$month-1]+$day-1;
+    $$self{days}=$days;
+    my $absol=$rosh+$days-1;
+    $$self{absol}=$absol;
+}
+
+
+
+sub year {
+    my $self = shift;
+    return $$self{year} if exists $$self{year};
+    my $days=$$self{absol};
+    my $year=int($days/365)-3*365; # just an initial guess, but a good one.
+    warn "Date::Convert::Hebrew isn't reliable before the beginning of\n".
+	"\tthe Hebrew calendar" if $days < $HEBREW_BEGINNING;
+    $year++ while rosh Date::Convert::Hebrew ($year+1)<=$days;
+    $$self{year}=$year;
+    $$self{days}=$days-(rosh Date::Convert::Hebrew $year)+1;
+    return $year;
+}
+
+
+sub month {
+    my $self = shift;
+    return $$self{month} if exists $$self{month};
+    my $year_length=
+	rosh Date::Convert::Hebrew ($self->year+1) - 
+	    rosh Date::Convert::Hebrew $self->year;
+    carp "Impossible year length" unless defined $MONTH_START{$year_length};
+    my $months_ref=$MONTH_START{$year_length};
+    my $days=$$self{days};
+    my ($n, $month)=(1);
+    my $day=31; # 31 is too large.  Good.  :)
+    grep {if ($days>=$_ && $days-$_<$day) 
+	  {$day=$days-$_+1;$month=$n}
+	  $n++} @$months_ref;
+    $$self{month}=$month;
+    $$self{day}=$day;
+    return $month;
+}
+
+
+
+
+sub day {
+    my $self = shift;
+    return $$self{day} if exists $$self{day};
+    $self->month; # calculates day as a side-effect.
+    return $$self{day};
+}
+
+
+sub date {
+    my $self = shift;
+    return ($self->year, $self->month, $self->day);
+}
+
+
+sub date_string {
+    my $self=shift;
+    return $self->year." $MONTHS[$self->month-1] ".$self->day;
+}
+
+
+sub rosh {
+    my $self = shift;
+    my $year = shift || $self->year;    
+    my @molad= @FIRST_MOLAD;
+    @molad = &part_add(@molad, &part_mult(int(($year-1)/19), at CYCLE_YEARS));
+    my $offset=($year-1)%19;
+    my $num_leaps=(grep {$_<=$offset} @LEAP_CYCLE) - 1;
+    @molad = &part_add(@molad, &part_mult($num_leaps, @LEAP_YEAR));
+    @molad = &part_add(@molad, &part_mult($offset-$num_leaps, 
+					      @NORMAL_YEAR));
+    my $day=shift @molad;
+    my $hour=shift @molad;
+    my $part= shift @molad;
+    my $guess=$day%7;
+    if (($hour>=18)                              # molad zoken al tidrosh
+	or
+	((is_leap Date::Convert::Hebrew $year) and   # gatrad b'shanah
+	 ($guess==2) and                         #      p'shutah g'rosh
+	 (($hour>9)or($hour==9 && $part>=204)))
+        or
+        ((is_leap Date::Convert::Hebrew $year-1) and # b'to takfat achar
+	 ($guess==1) and                         #      ha'ibur akor
+	 (($hour>15)or($hour==15&&$part>589)))){ #      mi-lishorsh
+	$guess++;
+	$day++;
+    }
+    $guess%=7;
+    if (scalar(grep {$guess==$_} (0, 3, 5))) {   # lo ad"o rosh
+	$guess++;
+	$day++;
+    }
+    $guess%=7;
+    return ($day+1+$HEBREW_BEGINNING);
+}
+
+
+
+
+sub part_add {
+    my ($day1, $hour1, $part1)=(shift, shift, shift);
+    my ($day2, $hour2, $part2)=(shift, shift, shift);
+    my $part=$part1+$part2;
+    my $hour=$hour1+$hour2;
+    my $day =$day1 +$day2;
+    if ($part>1080) {
+	$part-=1080;
+	$hour++;
+    }
+    if ($hour>24) {
+	$hour-=24;
+	$day++;
+    }
+    return ($day, $hour, $part);
+}
+
+
+sub part_mult {
+    my $scalar = shift;
+    my $day= ((0+ shift) * $scalar);
+    my $hour=((0+ shift) * $scalar);
+    my $part=((0+ shift) * $scalar);
+    my $tmp;
+    if ($part>1080) {
+	$tmp=int($part/1080);
+	$part%=1080;
+	$hour+=$tmp;
+    }
+    if ($hour>24) {
+	$tmp=int($hour/24);
+	$hour%=24;
+	$day+=$tmp;
+    }
+    return($day, $hour, $part);
+}
+
+
+# Here's a quickie, based on the base class.
+
+package Date::Convert::Absolute;
+use Date::Convert;
+ at ISA = qw ( Date::Convert );
+
+sub initialize {
+    return Date::Convert::initialize @_;
+}
+
+
+sub date {
+    my $self=shift;
+    return $$self{'absol'};
+}
+
+sub date_string {
+    my $self=shift;
+    my $date=$self->date; # just a scalar
+    return "$date";
+}
+
+
+
+# Julian is kinda like Gregorian, but the leap year rule is easier.
+
+package Date::Convert::Julian;  
+
+use Carp;
+ at ISA = qw ( Date::Convert::Gregorian Date::Convert );  
+# we steal useful constants from Gregorian
+$JULIAN_BEGINNING=$Date::Convert::Gregorian::GREG_BEGINNING - 2;
+$NORMAL_YEAR=     $Date::Convert::Gregorian::NORMAL_YEAR;
+$LEAP_YEAR=       $Date::Convert::Gregorian::LEAP_YEAR;
+$FOUR_YEARS=      $Date::Convert::Gregorian::FOUR_YEARS;
+
+ at MONTH_ENDS    = @Date::Convert::Gregorian::MONTH_ENDS;
+ at LEAP_ENDS     = @Date::Convert::Gregorian::LEAP_ENDS;
+
+sub initialize {
+    my $self=shift ||
+	croak "Date::Convert::Julian::initialize needs more args";
+    my $year=shift || return Date::Convert::initialize;
+    my $month=shift ||
+	croak "Date::Convert::Julian::initialize needs more args";
+    my $day=shift ||
+	croak "Date::Convert::Julian::initialize needs more args";
+
+    warn "These routines don't work well for Julian before year 1"
+	if $year<1;
+    my $absol = $JULIAN_BEGINNING;
+    $$self{'year'} = $year;
+    $$self{'month'}= $month;
+    $$self{'day'}  = $day;
+    my $is_leap = is_leap Date::Convert::Gregorian $year;
+    $year --;  #get years *before* this year.  Makes math easier.  :)
+    # first, convert year into days. . .
+    $absol += int($year/4)*$FOUR_YEARS;
+    $year  %= 4;
+    $absol += $year*$NORMAL_YEAR;
+    # now, month into days.
+    croak "month number $month out of range" 
+	if $month < 1 || $month >12;
+    my $MONTH_REF=\@MONTH_ENDS;
+    $MONTH_REF=\@LEAP_ENDS if $is_leap;
+    croak "day number $day out of range for month $month"
+	if $day<1 || $day+$$MONTH_REF[$month-1]>$$MONTH_REF[$month];
+    $absol += $day+$$MONTH_REF[$month-1]-1;
+    $$self{absol}=$absol;
+}
+
+
+sub year {
+    my $self = shift;
+    return $$self{year} if exists $$self{year};
+    my ($days, $year);
+    # To avoid fenceposts, year and days are initially *before* today.
+    # the next code is stolen directly form the ::Gregorian code.  Good thing
+    # I'm the one who wrote it. . .
+    $days=$$self{absol}-$JULIAN_BEGINNING;
+    $year =  int ($days / $FOUR_YEARS) * 4;
+    $days %= $FOUR_YEARS;
+    if (($days+1) % $FOUR_YEARS) { # Not on a four-year boundary.  Good!
+	$year += int ($days / $NORMAL_YEAR); # fence post from year 1
+	$days %= $NORMAL_YEAR; 
+	$days += 1; # today
+	$year += 1;
+    } else {
+	$year += int ($days / $NORMAL_YEAR + 1) - 1;
+	$days =  $LEAP_YEAR;
+    }
+    $$self{year}=$year;
+    $$self{days_into_year}=$days;
+    return $year;
+}
+
+
+
+sub is_leap {
+    my $self = shift;
+    my $year = shift || $self->year; # so is_leap can be static or method
+    return 0 if ($year %4);
+    return 1;
+}
+
+
+# OK, we're done.  Everything else just gets inherited from Gregorian.
+
+
+1;
+
+__END__
+
+=head1 NAME
+
+Date::Convert - Convert Between any two Calendrical Formats
+
+=head1 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 B<Convert> method to do this transparently.
+
+Nothing is exported because it wouldn't make any sense to export.  :)
+
+
+=head1 DESCRIPTION
+
+Fucntion can be split into several categories:
+
+=over 4
+
+=item * 
+
+Universal functions available for all subclasses (ie. all formats).  The
+fundamental conversion routines fit this category.
+
+=item *
+
+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.
+
+=item *
+
+Private functions that are required of all subclasses, ie. B<initialize>.
+These should I<not> be called by users.
+
+=back
+
+Here's the breakdown by category:
+
+=head2 Functions Defined for all Subclasses
+
+=over 4
+
+=item new
+
+Create a new object in the specified format with the specified start
+paramaters, ie. C<$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".
+
+=item date
+
+Extract the date in a format appropriate for the subclass.  Preferably this
+should match the format used with B<new>, so
+
+	(new date::Convert::SomeClass(@a))->date;
+
+should be an identity function on @a if @a was in a legitmate format.
+
+=item date_string
+
+Return the date in a pretty format.
+
+=item convert
+
+Change the date to a new format.
+
+=back
+
+=head2 Non-universal functions
+
+=over 4
+
+=item year
+
+Return just the year element of date.
+
+=item month
+
+Just like year.
+
+=item day
+
+Just like year and month.
+
+=item is_leap
+
+Boolean.  Note that (for B<::Hebrew> and B<::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
+
+=back
+
+=head2 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.
+
+=over 4
+
+=item 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 B<new>.)  Note the American spelling of
+"initialize": "z", not "s".
+
+=back
+
+
+=head1 SUBCLASS SPECIFIC NOTES
+
+=head2 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.
+
+=head2 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 B<::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, B<Gregorian> also has B<year>,
+B<month>, B<day>, and B<is_leap> methods.  As mentioned above, B<is_leap>
+can also be used statically.
+
+=head2 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: B<year>, B<month>, B<day>,
+B<is_leap>, B<rosh>, B<part_add>, and B<part_mult>.  B<rosh> returns the
+absolute day corresponding to "Rosh HaShana" (New year) for a given year,
+and can also be invoked as a static.  B<part_add> and B<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.
+
+
+=head2 Islamic
+
+The traditional Muslim calendar, a purely lunar calendar with a year that
+is a rough approximation of a solar year.  Currently unimplemented.
+
+=head2 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.
+
+
+=head1 ADDING NEW SUBCLASSES
+
+This section describes how to extend B<Date::Convert> to add your favorite
+date formats.  If you're not interested, feel free to skip it.  :)
+
+There are only three function you I<have> to write to add a new subclass:
+you need B<initialize>, B<date>, and B<date_string>.  Of course, helper
+functions would probably help. . .  You do I<not> need to write a B<new> or
+B<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 B<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' B<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
+B<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
+B<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:
+
+=over 4
+
+=item initialize
+
+Take the date supplied as argument as appropriate to the format, and
+convert it to "absol" format.  Store it as C<$$self{'absol'}>.  You might
+also want to store other data, ie. B<::Gregorian> stores C<$$self{'year'}>,
+C<$$self{'month'}>, and C<$$self{'day'}>.  If no args are supplied,
+explicitly call the base class's initialize,
+ie. C<Date::Convert::initialize>, to initialize with a default 'absol' date
+and nothing else.
+
+I<NOTE:>  I may move the default behavior into the new constructor.
+
+=item date
+
+Return the date in a appropriate format.  Note that the only fact that
+B<date> can take as given is that C<$$self{'absol'}> is defined, ie. this
+object may I<not> have been initialized by the B<initialize> of this
+object's class.  For instance, you might have it check if C<$$self{'year'}>
+is defined.  If it is, then you have the year component, otherwise, you
+calculate year from C<$$self{'absol'}>.
+
+=item date_string
+
+This is the easy part.  Just call date, then return a pretty string based
+on the values.
+
+=back
+
+
+I<NOTE:> The B<::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 B<::Julian> except that Julian inherits from B<::Gregorian>.
+Maybe I'll reverse that. . .
+
+
+=head1 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 at 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.
+
+=head1 SEE ALSO
+
+perl(1), Date::DateCalc(3)
+
+=head1 VERSION
+
+Date::Convert 0.15 (pre-alpha)
+
+=head1 AUTHOR
+
+Mordechai T. Abzug <morty at umbc.edu>
+
+=head1 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,
+I<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,
+I<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 I<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 I<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!
+
+=head1 COPYRIGHT
+
+Copyright 1997 by Mordechai T. Abzug
+
+=head1 LICENSE STUFF
+
+You can distribute, modify, and otherwise mangle Date::Convert under the
+same terms as perl.
+

Added: branches/upstream/libdate-convert-perl/current/INSTALL
URL: http://svn.debian.org/wsvn/branches/upstream/libdate-convert-perl/current/INSTALL?rev=16229&op=file
==============================================================================
--- branches/upstream/libdate-convert-perl/current/INSTALL (added)
+++ branches/upstream/libdate-convert-perl/current/INSTALL Sun Mar  2 01:57:13 2008
@@ -1,0 +1,7 @@
+
+Install the normal way:
+
+perl Makefile.PL
+make
+make test
+make install

Added: branches/upstream/libdate-convert-perl/current/Makefile.PL
URL: http://svn.debian.org/wsvn/branches/upstream/libdate-convert-perl/current/Makefile.PL?rev=16229&op=file
==============================================================================
--- branches/upstream/libdate-convert-perl/current/Makefile.PL (added)
+++ branches/upstream/libdate-convert-perl/current/Makefile.PL Sun Mar  2 01:57:13 2008
@@ -1,0 +1,6 @@
+use ExtUtils::MakeMaker;
+WriteMakefile(
+    'NAME'      => 'Date::Convert',
+    'VERSION'   => '0.10'
+);
+

Added: branches/upstream/libdate-convert-perl/current/README
URL: http://svn.debian.org/wsvn/branches/upstream/libdate-convert-perl/current/README?rev=16229&op=file
==============================================================================
--- branches/upstream/libdate-convert-perl/current/README (added)
+++ branches/upstream/libdate-convert-perl/current/README Sun Mar  2 01:57:13 2008
@@ -1,0 +1,24 @@
+
+Date::Convert 0.13 pre-alpha by Mordechai T. Abzug <morty at umbc.edu>
+
+Allows you to convert date formats using an OO mechanism that lets you
+easily choose any two formats and add in new ones.
+
+At the moment, the only documentation is the man page.  That's not
+surprising, since it *is* pre-alpha.  And of course, since it's pre-alpha,
+'tis subject to change, and is unreliable.
+
+Install the normal way:
+
+perl Makefile.PL
+make
+make test
+make install
+
+If you have suggestions, bug reports, or if you want to add a new date
+format, feel free to contact me:  morty at sanctuary.arbutus.md.us
+
+If you want to be on the announcement list for new releases, send a mail
+with "subscribe" as the first line of the body to:
+dateconvert-announce-request at sanctuary.arbutus.md.us
+

Added: branches/upstream/libdate-convert-perl/current/TO-DO
URL: http://svn.debian.org/wsvn/branches/upstream/libdate-convert-perl/current/TO-DO?rev=16229&op=file
==============================================================================
--- branches/upstream/libdate-convert-perl/current/TO-DO (added)
+++ branches/upstream/libdate-convert-perl/current/TO-DO Sun Mar  2 01:57:13 2008
@@ -1,0 +1,16 @@
+- stick some sort of forward_day and back_day methods into the base class
+- make things more OO.
+- make it impossible to instantiate the base class (ie. make it an ADT).
+- move the responsibilty for default constructor from subclasses to base
+	class
+- make Gregorian inherit from Julian rather than the other way around
+- Add more calendars (ie. Islamic)
+- Get ahold of my original sources
+- make the default constructor initialize using today's date.
+- add a whole lot more test cases to the test suites, particularly boundary
+	conditions
+- add more argument passing options a la CGI.pm, ie. 'year'=>1974 or 
+	-year=>1974
+- docs: explain about the second-part approximation that bugged Ed. Sabol
+- add some form of format specifier to date_string for Gregorian
+- Conversion between formats that understand time of dat and ones that don't?

Added: branches/upstream/libdate-convert-perl/current/t/absolute.t
URL: http://svn.debian.org/wsvn/branches/upstream/libdate-convert-perl/current/t/absolute.t?rev=16229&op=file
==============================================================================
--- branches/upstream/libdate-convert-perl/current/t/absolute.t (added)
+++ branches/upstream/libdate-convert-perl/current/t/absolute.t Sun Mar  2 01:57:13 2008
@@ -1,0 +1,25 @@
+#!perl -w
+
+use Date::Convert;
+
+print "1..3\n";
+
+$n=1;
+
+$date=new Date::Convert::Absolute(2450526);
+if ($date->date == 2450526)
+    {print "ok $n\n"} else 
+    {print "not ok $n\n"}
+$n++;
+
+if ($date->date_string eq "2450526")
+    {print "ok $n\n"} else 
+    {print "not ok $n\n"}
+$n++;
+
+convert Date::Convert::Hebrew $date;
+if ($date->date_string eq "5757 Adar II 9")
+    {print "ok $n\n"} else 
+    {print "not ok $n\n"}
+$n++;
+

Added: branches/upstream/libdate-convert-perl/current/t/heb_and_greg.t
URL: http://svn.debian.org/wsvn/branches/upstream/libdate-convert-perl/current/t/heb_and_greg.t?rev=16229&op=file
==============================================================================
--- branches/upstream/libdate-convert-perl/current/t/heb_and_greg.t (added)
+++ branches/upstream/libdate-convert-perl/current/t/heb_and_greg.t Sun Mar  2 01:57:13 2008
@@ -1,0 +1,38 @@
+#!perl -w
+
+use Date::Convert;
+
+print "1..4\n";
+
+$n=1;
+
+$date=new Date::Convert::Gregorian(1974, 11, 27);
+
+convert Date::Convert::Hebrew $date;
+if ($date->date_string eq "5735 Kislev 13") 
+    {print "ok $n\n"} else 
+    {print "not ok $n\n"}
+$n++;
+
+convert Date::Convert::Gregorian $date;
+if ($date->date_string eq "1974 Nov 27")
+    {print "ok $n\n"} else 
+    {print "not ok $n\n"}
+$n++;
+
+
+
+$guy = new Date::Convert::Hebrew (5756, 7, 8);
+
+convert Date::Convert::Gregorian $guy;
+if ($guy->date_string eq "1995 Oct 2")
+    {print "ok $n\n"} else 
+    {print "not ok $n\n"}
+$n++;
+
+convert Date::Convert::Hebrew $guy;
+if ($guy->date_string eq "5756 Tishrei 8")
+    {print "ok $n\n"} else 
+    {print "not ok $n\n"}
+$n++;
+

Added: branches/upstream/libdate-convert-perl/current/t/hebrew.t
URL: http://svn.debian.org/wsvn/branches/upstream/libdate-convert-perl/current/t/hebrew.t?rev=16229&op=file
==============================================================================
--- branches/upstream/libdate-convert-perl/current/t/hebrew.t (added)
+++ branches/upstream/libdate-convert-perl/current/t/hebrew.t Sun Mar  2 01:57:13 2008
@@ -1,0 +1,77 @@
+#!perl -w
+
+use Date::Convert;
+
+print "1..137\n";
+
+$n=1;
+
+$date=new Date::Convert::Hebrew(5757, 13, 9);
+if ($$date{absol} == 2450526)
+    {print "ok $n\n"} else 
+    {print "not ok $n\n"}
+$n++;
+
+ at absols=qw(2447800 2448155 2448509 2448894 2449247 2449602 2449986
+	   2450341 2450724 2451078 2451433 2451818 2452171 2452525
+	   2452910 2453265 2453648 2454002 2454357 2454740 2455094
+	   2455449 2455834 2456188 2456541 2456926 2457280 2457665
+	   2458018 2458372 2458757
+	);
+
+
+foreach $i (5750..5780) {
+    my $rosh=rosh Date::Convert::Hebrew $i;
+    if ($rosh = shift @absols)
+    {print "ok $n\n"} else 
+    {print "not ok $n\n"}
+$n++;
+}
+
+
+$rina_birthday=new Date::Convert::Gregorian(1976, 5, 25);
+if ($rina_birthday->date_string eq "1976 May 25")
+    {print "ok $n\n"} else 
+    {print "not ok $n\n"}
+$n++;
+
+convert Date::Convert::Hebrew $rina_birthday;
+if ($rina_birthday->date_string eq "5736 Iyyar 25")
+    {print "ok $n\n"} else 
+    {print "not ok $n\n"}
+$n++;
+
+convert Date::Convert::Gregorian $rina_birthday;
+if ($rina_birthday->date_string eq "1976 May 25")
+    {print "ok $n\n"} else 
+    {print "not ok $n\n"}
+$n++;
+
+my $broken_date=new Date::Convert::Hebrew(5765, 10, 26);
+if ($broken_date->date_string eq "5765 Teves 26")
+    {print "ok $n\n"} else 
+    {print "not ok $n\n"}
+$n++;
+
+convert Date::Convert::Gregorian $broken_date;
+if ($broken_date->date_string eq "2005 Jan 7")
+    {print "ok $n\n"} else 
+    {print "not ok $n\n"}
+$n++;
+
+
+ at leaps=qw(0 0 1 0 0 1 0 1 0 0 1 0 0 1 0 0 1 0 1 
+	  0 0 1 0 0 1 0 1 0 0 1 0 0 1 0 0 1 0 1 
+	  0 0 1 0 0 1 0 1 0 0 1 0 0 1 0 0 1 0 1 
+	  0 0 1 0 0 1 0 1 0 0 1 0 0 1 0 0 1 0 1 
+	  0 0 1 0 0 1 0 1 0 0 1 0 0 1 0 0 1 0 1 
+	  0 0 1 0 0);
+
+foreach $i (1..100) {
+    if (is_leap Date::Convert::Hebrew($i) == shift @leaps)
+    {print "ok $n\n"} else 
+    {print "not ok $n\n"}
+$n++;
+}
+
+print "\n";

Added: branches/upstream/libdate-convert-perl/current/t/identity.t
URL: http://svn.debian.org/wsvn/branches/upstream/libdate-convert-perl/current/t/identity.t?rev=16229&op=file
==============================================================================
--- branches/upstream/libdate-convert-perl/current/t/identity.t (added)
+++ branches/upstream/libdate-convert-perl/current/t/identity.t Sun Mar  2 01:57:13 2008
@@ -1,0 +1,51 @@
+#!perl -w
+
+use Date::Convert;
+
+print "1..6\n";
+
+$n=1;
+
+ at a=(5730, 3, 2);
+ at b=(new Date::Convert::Hebrew @a)->date;
+if ("@a" eq "@b")
+    {print "ok $n\n"} else 
+    {print "not ok $n\n"}
+$n++;
+
+ at a=(5720, 8, 29);
+ at b=(new Date::Convert::Hebrew @a)->date;
+if ("@a" eq "@b")
+    {print "ok $n\n"} else 
+    {print "not ok $n\n"}
+$n++;
+
+ at a=(5755, 9, 20);
+ at b=(new Date::Convert::Hebrew @a)->date;
+if ("@a" eq "@b")
+    {print "ok $n\n"} else 
+    {print "not ok $n\n"}
+$n++;
+
+ at a=(5730, 3, 2);
+ at b=(new Date::Convert::Gregorian @a)->date;
+if ("@a" eq "@b")
+    {print "ok $n\n"} else 
+    {print "not ok $n\n"}
+$n++;
+
+ at a=(5730, 3, 2);
+ at b=(new Date::Convert::Gregorian @a)->date;
+if ("@a" eq "@b")
+    {print "ok $n\n"} else 
+    {print "not ok $n\n"}
+$n++;
+
+ at a=(5730, 3, 2);
+ at b=(new Date::Convert::Gregorian @a)->date;
+if ("@a" eq "@b")
+    {print "ok $n\n"} else 
+    {print "not ok $n\n"}
+$n++;
+
+

Added: branches/upstream/libdate-convert-perl/current/t/julian.t
URL: http://svn.debian.org/wsvn/branches/upstream/libdate-convert-perl/current/t/julian.t?rev=16229&op=file
==============================================================================
--- branches/upstream/libdate-convert-perl/current/t/julian.t (added)
+++ branches/upstream/libdate-convert-perl/current/t/julian.t Sun Mar  2 01:57:13 2008
@@ -1,0 +1,68 @@
+#!perl -w
+
+use Date::Convert;
+
+print "1..9\n";
+
+$n=1;
+
+$a=1757642;
+$date=new Date::Convert::Absolute($a);
+if ($date->date == 1757642)
+    {print "ok $n\n"} else 
+    {print "not ok $n\n"}
+$n++;
+
+convert Date::Convert::Julian $date;
+if ($date->date_string eq "100 Feb 29")
+    {print "ok $n\n"} else 
+    {print "not ok $n\n"}
+$n++;
+
+convert Date::Convert::Absolute $date;
+if ($date->date_string eq "1757642")
+    {print "ok $n\n"} else 
+    {print "not ok $n\n"}
+$n++;
+
+$date=new Date::Convert::Gregorian(1997, 4, 15);
+convert Date::Convert::Julian $date;
+if ($date->date_string eq "1997 Apr 2")
+    {print "ok $n\n"} else 
+    {print "not ok $n\n"}
+$n++;
+
+
+convert Date::Convert::Gregorian $date;
+if ($date->date_string eq "1997 Apr 15")
+    {print "ok $n\n"} else 
+    {print "not ok $n\n"}
+$n++;
+
+$date=new Date::Convert::Julian(1999, 9, 25);
+if ($date->date_string eq "1999 Sep 25")
+    {print "ok $n\n"} else
+    {print "no ok $n\n"}
+$n++;
+
+convert Date::Convert::Gregorian $date;
+if ($date->date_string eq "1999 Oct 8")
+    {print "ok $n\n"} else
+    {print "no ok $n\n"}
+$n++;
+
+$date=new Date::Convert::Julian(1999, 12, 18);
+convert Date::Convert::Gregorian $date;
+if ($date->date_string eq "1999 Dec 31")
+    {print "ok $n\n"} else
+    {print "no ok $n\n"}
+$n++;
+
+$date=new Date::Convert::Julian(1999, 12, 19);
+convert Date::Convert::Gregorian $date;
+if ($date->date_string eq "2000 Jan 1")
+    {print "ok $n\n"} else
+    {print "no ok $n\n"}
+$n++;
+
+




More information about the Pkg-perl-cvs-commits mailing list