=head1 NAME
Panda::Date::Rel - Relative date object.
=head1 DESCRIPTION
Relative date is a period of time not bound to any particular point in time and is used for date calculations.
Reldate consists of 6 units - seconds, minutes, hours, days, months and years. Some units convert to another inaccurate.
=head1 CLASS METHODS
=head4 new([$rel_string | $seconds | \@rel_array | \%rel_hash | $reldate])
Creates a date object using one of these source data types:
=over
=item 123456 or "123456"
Treated as a number of seconds
=item [$year, $month, $day, $hour, $min, $sec]
Missing elements are considered = 0.
=item {year => x, month => x, day => x, hour => x, min => x, sec => x}
Missing elements are considered = 0.
=item string "1Y 2M 3D 4h 5m 6s"
Any part can be absent or negative.
=item Another relative date object
Clones another object
=back
=head4 new($from, $till)
Creates relative date $rel so that $from + $rel == $till.
$from and $till can be L<Panda::Date> objects or any data supported by L<Panda::Date> constructor.
=head1 OBJECT METHODS
=head4 set($rel_string | $seconds | \@rel_array | \%rel_hash | $reldate)
=head4 set($from, $till)
Set relative date from data (data can be anything that constructor supports). This is much faster than creating new object.
=head4 year([$years]), years
Number of years in relative date
=head4 month([$months]), months, mon, mons
Number of month in relative date
=head4 day([$days]), days
Number of days in relative date
=head4 hour([$hours]), hours
Number of hours in relative date
=head4 min([$mins]), mins, minute, minutes
Number of minutes in relative date
=head4 sec([$secs]), secs, second, seconds
Number of seconds in relative date
=head4 to_sec(), to_second, to_secs, to_seconds, duration
Converts relative date to number of seconds.
If any of day/month/year are non-zero then this value can be inaccurate because one need to know exact dates
to calculate exact number of seconds.
For such calculations the following assumptions are made:
=over
=item 1M = 2_629_744s
=item 1M = 2_629_744/86400 D
=item 1D = 86400s
=back
=head4 to_min(), to_minute, to_mins, to_minutes
Converts relative date to number of minutes. If any of day/month/year are non-zero then this value can be inaccurate, see to_sec().
=head4 to_hour(), to_hours
Converts relative date to number of hours. If any of day/month/year are non-zero then this value can be inaccurate, see to_sec().
=head4 to_day(), to_days
Converts relative date to number of days. If any of sec/min/hour/month/year are non-zero then this value can be inaccurate, see to_sec().
=head4 to_month(), to_months, to_mon, to_mons
Converts relative date to number of months. If any of sec/min/hour/day are non-zero then this value can be inaccurate, see to_sec().
=head4 to_year(), to_years
Converts relative date to number of years. If any of sec/min/hour/day are non-zero then this value can be inaccurate, see to_sec().
=head4 "", to_string(), string(), as_string()
Returns string in "4M 15D 123s" format, any of YMDhms can be absent or negative. If all the parts YMDhms are 0, then "" is returned.
=head4 'bool', to_bool()
Called implicitly in boolean context.
Returns FALSE, if sec = 0 and min = 0 and .... year = 0, i.e. duration = 0. Otherwise TRUE.
=head4 '0+', to_number()
Returns to_sec().
=head4 '*', multiply_new($num)
Multiplies relative date by $num. $num can be fractional but the result is always integer.
Examples
$rel = "1M 1D";
print $rel * 2; # 2M 2D
print rdate("10h")->multiply(10); # 100h
Relative date can only be multiplied by number (scalar).
No normalization are made, i.e. 12h*2 = 24h is not normalized to 1D because that would be inaccurate (on DST border day for example, 1D is 25 or 23h)
=head4 '*=', multiply($num)
Same as C<multiply_new()>, but changes current object instead of creating new one.
=head4 '/', divide_new($num)
Divides relative date by $num. $num can be fractional but the result is always integer.
System will denormalize values if in another way (rounding) precision loses are bigger,
for example "1Y" / 2 = "6M" (without denormalization it would be 0).
This applies even if units are not converted accurate. In this case assumptions mentioned in to_sec() are made.
Examples
$rel = "2Y";
print $rel/2; # 1Y
print $rel/4; # 6M
print rdate("1D")/3; # 8h
print (rdate("1D")/3)*3; # 24h
print MONTH/2; # "15D 5h 14m 32s"
P.S. Keep in mind that ($rel / N) * N is not always equals $rel, as well as ($rel * N) / N
=head4 '/=', divide($num)
Same as C<divide_new()>, but changes current object instead of creating new one.
=head4 '+', add_new($reldate | $rel_string | $seconds | \@rel_array | \%rel_hash)
Adds another rel date to current. Another reldate can be Panda::Date::Rel object or any data valid for its constructor.
Examples
my $rel = 2*MONTH;
print $rel+MONTH; # 3M
print $rel+'30D'; # 2M 30D
print $rel+[1,2,3]; # 1Y 4M 3D
=head4 '+=', add($reldate | $rel_string | $seconds | \@rel_array | \%rel_hash)
Same as C<add_new()>, but changes current object instead of creating new one.
Examples
my $rel = 2*MONTH;
$rel += '16h'; # 2M 16h
$rel += {sec => 10, min => 20}; # 2M 16h 20m 10s
$rel += $rel; # 4M 32h 40m 20s
=head4 '-', subtract_new($reldate | $rel_string | $seconds | \@rel_array | \%rel_hash)
Subtracts another reldate from current. Another reldate can be Panda::Date::Rel object or any data valid for its constructor.
Examples
my $rel = 2*MONTH;
print $rel-MONTH; # 1M
print $rel-'30D'; # 2M -30D
print $rel-[1,2,3]; # -1Y -3D
=head4 '-=', subtract($reldate | $rel_string | $seconds | \@rel_array | \%rel_hash)
Same as C<subtract_new()>, but changes current object instead of creating new one.
=head4 'neg', negative_new() (unary '-')
Changes sign of YMDhms
=head4 negative()
Same as C<negative_new()>, but changes current object instead of creating new one.
=head4 '<=>', compare($reldate | $rel_string | $seconds | \@rel_array | \%rel_hash)
Compares 2 relative dates and returns -1, 0 or 1. Another reldate can be Panda::Date::Rel object or any data valid for its constructor.
Dates are compared using C<to_sec()>, therefore 2 dates can be equal even if they consist of different components.
If you want full equality test, use 'eq'.
Examples
MONTH > YEAR; # false
rdate("1Y 1M") > YEAR; #true
12*MONTH == YEAR; #true
12*MONTH eq YEAR; #false
=head4 'eq', equals($reldate | $rel_string | $seconds | \@rel_array | \%rel_hash)
Same as '==' but returns TRUE only if 2 reldates are fully identical.
$reldate = rdate("1Y 2M");
$reldate == "1Y 2M"; # true
$reldate == "14M"; # true
$reldate eq "1Y 2M"; # true
$reldate eq "14M"; # false
=head4 clone()
Clones object.
=head1 OPERATOR OVERLOAD RULES
See screenshot L<http://crazypanda.ru/v/clip2net/g/0/KfYbuNhu0b.png>
=head1 CLONING/SERIALIZATION
Panda::Date::Rel supports:
=over
=item Storable serialization/deserealization
=item L<Panda::Lib>'s C<clone>
=back
=head1 AUTHOR
Pronin Oleg <syber@cpan.org>, Crazy Panda, CP Decision LTD
=head1 LICENSE
You may distribute this code under the same terms as Perl itself.
=cut