line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package DateTime::Fiction::JRRTolkien::Shire::Duration; |
2
|
|
|
|
|
|
|
|
3
|
9
|
|
|
9
|
|
1164
|
use 5.008004; |
|
9
|
|
|
|
|
54
|
|
4
|
|
|
|
|
|
|
|
5
|
9
|
|
|
9
|
|
67
|
use strict; |
|
9
|
|
|
|
|
24
|
|
|
9
|
|
|
|
|
228
|
|
6
|
9
|
|
|
9
|
|
57
|
use warnings; |
|
9
|
|
|
|
|
22
|
|
|
9
|
|
|
|
|
303
|
|
7
|
|
|
|
|
|
|
|
8
|
9
|
|
|
9
|
|
51
|
use Carp (); |
|
9
|
|
|
|
|
21
|
|
|
9
|
|
|
|
|
258
|
|
9
|
9
|
|
|
9
|
|
614
|
use DateTime::Duration 0.140 (); |
|
9
|
|
|
|
|
568920
|
|
|
9
|
|
|
|
|
201
|
|
10
|
9
|
|
|
9
|
|
5039
|
use DateTime::Fiction::JRRTolkien::Shire::Types (); |
|
9
|
|
|
|
|
45
|
|
|
9
|
|
|
|
|
585
|
|
11
|
9
|
|
|
9
|
|
99
|
use Params::ValidationCompiler 0.13 (); |
|
9
|
|
|
|
|
263
|
|
|
9
|
|
|
|
|
215
|
|
12
|
9
|
|
|
9
|
|
63
|
use Scalar::Util (); |
|
9
|
|
|
|
|
27
|
|
|
9
|
|
|
|
|
714
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
*__t = \&DateTime::Fiction::JRRTolkien::Shire::Types::t; |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
use overload |
17
|
9
|
|
|
|
|
103
|
fallback => 1, |
18
|
|
|
|
|
|
|
'+' => '_add_overload', |
19
|
|
|
|
|
|
|
'-' => '_subtract_overload', |
20
|
|
|
|
|
|
|
'*' => '_multiply_overload', |
21
|
|
|
|
|
|
|
'<=>' => '_compare_overload', |
22
|
|
|
|
|
|
|
'cmp' => '_compare_overload', |
23
|
9
|
|
|
9
|
|
111
|
; |
|
9
|
|
|
|
|
26
|
|
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
our $VERSION = '0.906'; |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
{ |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
my $validate = Params::ValidationCompiler::validation_for( |
30
|
|
|
|
|
|
|
name => '_validation_for_new', |
31
|
|
|
|
|
|
|
name_is_optional => 1, |
32
|
|
|
|
|
|
|
params => { |
33
|
|
|
|
|
|
|
years => { type => __t( 'IntOrUndef' ) }, |
34
|
|
|
|
|
|
|
months => { type => __t( 'IntOrUndef' ) }, |
35
|
|
|
|
|
|
|
weeks => { type => __t( 'IntOrUndef' ) }, |
36
|
|
|
|
|
|
|
}, |
37
|
|
|
|
|
|
|
); |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
sub new { |
40
|
43
|
|
|
43
|
1
|
1638
|
my ( $class, %arg ) = @_; |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
$validate->( |
43
|
|
|
|
|
|
|
years => $arg{years}, |
44
|
|
|
|
|
|
|
months => $arg{months}, |
45
|
|
|
|
|
|
|
weeks => $arg{weeks}, |
46
|
43
|
|
|
|
|
1126
|
); |
47
|
|
|
|
|
|
|
|
48
|
43
|
|
100
|
|
|
2081
|
$arg{$_} ||= 0 foreach qw{ years months weeks days }; |
49
|
|
|
|
|
|
|
|
50
|
43
|
|
|
|
|
80
|
my $default_mode; |
51
|
|
|
|
|
|
|
( my $mode_specified = $arg{end_of_month} || $arg{holiday} ) |
52
|
43
|
100
|
100
|
|
|
227
|
or $default_mode = _compute_default_mode( \%arg ); |
53
|
|
|
|
|
|
|
|
54
|
43
|
|
|
|
|
105
|
my $years = delete $arg{years}; |
55
|
43
|
|
|
|
|
84
|
my $weeks = delete $arg{weeks}; |
56
|
|
|
|
|
|
|
|
57
|
43
|
100
|
|
|
|
126
|
if ( defined $arg{holiday} ) { |
58
|
|
|
|
|
|
|
defined $arg{end_of_month} |
59
|
6
|
50
|
|
|
|
18
|
and Carp::croak( |
60
|
|
|
|
|
|
|
q<You may not specify both end_of_month and holiday> ); |
61
|
6
|
|
|
|
|
21
|
$arg{end_of_month} = _map_holiday_mode( delete $arg{holiday} ); |
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
defined $arg{end_of_month} |
65
|
43
|
100
|
|
|
|
136
|
or $arg{end_of_month} = $default_mode; |
66
|
|
|
|
|
|
|
|
67
|
43
|
|
66
|
|
|
209
|
return bless { |
68
|
|
|
|
|
|
|
duration => DateTime::Duration->new( %arg ), |
69
|
|
|
|
|
|
|
mode_specified => $mode_specified, |
70
|
|
|
|
|
|
|
weeks => $weeks, |
71
|
|
|
|
|
|
|
years => $years, |
72
|
|
|
|
|
|
|
}, ref $class || $class; |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
sub add { |
77
|
1
|
|
|
1
|
0
|
654
|
my ( $self, @arg ) = @_; |
78
|
1
|
|
|
|
|
7
|
return $self->add_duration( _make_duration( @arg ) ); |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
sub add_duration { |
82
|
4
|
|
|
4
|
0
|
155
|
my ( $self, $dur ) = @_; |
83
|
4
|
50
|
|
|
|
12
|
if ( _isa( $dur, __PACKAGE__ ) ) { |
|
|
0
|
|
|
|
|
|
84
|
4
|
|
|
|
|
13
|
$self->{weeks} += $dur->{weeks}; |
85
|
4
|
|
|
|
|
16
|
$self->{duration}->add_duration( $dur->{duration} ); |
86
|
|
|
|
|
|
|
} elsif ( _isa( $dur, 'DateTime::Duration' ) ) { |
87
|
0
|
|
|
|
|
0
|
$self->{duration}->add_duration( $dur ); |
88
|
|
|
|
|
|
|
} else { |
89
|
0
|
|
|
|
|
0
|
Carp::croak( "Can not do arithmetic on $dur" ); |
90
|
|
|
|
|
|
|
} |
91
|
4
|
|
|
|
|
82
|
return $self; |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
sub calendar_duration { |
95
|
1
|
|
|
1
|
0
|
795
|
my ( $self ) = @_; |
96
|
1
|
|
|
|
|
6
|
return $self->new( |
97
|
|
|
|
|
|
|
years => $self->delta_years(), |
98
|
|
|
|
|
|
|
months => $self->delta_months(), |
99
|
|
|
|
|
|
|
weeks => $self->delta_weeks(), |
100
|
|
|
|
|
|
|
days => $self->delta_days(), |
101
|
|
|
|
|
|
|
end_of_month => $self->end_of_month_mode(), |
102
|
|
|
|
|
|
|
); |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
sub clock_duration { |
106
|
1
|
|
|
1
|
0
|
642
|
my ( $self ) = @_; |
107
|
1
|
|
|
|
|
6
|
return $self->new( |
108
|
|
|
|
|
|
|
minutes => $self->delta_minutes(), |
109
|
|
|
|
|
|
|
seconds => $self->delta_seconds(), |
110
|
|
|
|
|
|
|
nanoseconds => $self->delta_nanoseconds(), |
111
|
|
|
|
|
|
|
end_of_month => $self->end_of_month_mode(), |
112
|
|
|
|
|
|
|
); |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
sub clone { |
116
|
3
|
|
|
3
|
0
|
7
|
my ( $self ) = @_; |
117
|
3
|
|
|
|
|
7
|
my %clone = %{ $self }; |
|
3
|
|
|
|
|
13
|
|
118
|
3
|
|
|
|
|
16
|
$clone{duration} = $self->{duration}->clone(); |
119
|
3
|
|
|
|
|
40
|
return bless \%clone, ref $self; |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
require DateTime::Fiction::JRRTolkien::Shire; |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
sub compare { |
125
|
0
|
|
|
0
|
0
|
0
|
my ( undef, $left, $right, $base ) = @_; |
126
|
|
|
|
|
|
|
|
127
|
0
|
|
0
|
|
|
0
|
$base ||= DateTime::Fiction::JRRTolkien::Shire->now(); |
128
|
|
|
|
|
|
|
|
129
|
0
|
|
|
|
|
0
|
return DateTime::Fiction::JRRTolkien::Shire->compare( |
130
|
|
|
|
|
|
|
$base->clone()->add_duration( $left ), |
131
|
|
|
|
|
|
|
$base->clone()->add_duration( $right ), |
132
|
|
|
|
|
|
|
); |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
sub delta_weeks { |
136
|
2
|
|
|
2
|
1
|
596
|
my ( $self ) = @_; |
137
|
2
|
|
|
|
|
13
|
return $self->{weeks}; |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
sub delta_years { |
141
|
2
|
|
|
2
|
1
|
747
|
my ( $self ) = @_; |
142
|
2
|
|
|
|
|
15
|
return $self->{years}; |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
# sub delta_months; sub delta_days; sub delta_minutes; |
146
|
|
|
|
|
|
|
# sub delta_seconds; sub delta_nanoseconds; |
147
|
|
|
|
|
|
|
# sub end_of_month_mode; is_wrap_mode; is_limit_mode; is_preserve_mode; |
148
|
|
|
|
|
|
|
# sub months; sub days; sub hours; sub minutes; sub seconds; |
149
|
|
|
|
|
|
|
# sub nanoseconds; |
150
|
|
|
|
|
|
|
foreach my $method ( qw{ |
151
|
|
|
|
|
|
|
delta_months delta_days delta_minutes delta_seconds |
152
|
|
|
|
|
|
|
delta_nanoseconds |
153
|
|
|
|
|
|
|
end_of_month_mode is_wrap_mode is_limit_mode is_preserve_mode |
154
|
|
|
|
|
|
|
months days hours minutes seconds nanoseconds |
155
|
|
|
|
|
|
|
} ) { |
156
|
9
|
|
|
9
|
|
9201
|
no strict qw{ refs }; |
|
9
|
|
|
|
|
48
|
|
|
9
|
|
|
|
|
13903
|
|
157
|
47
|
|
|
47
|
|
4456
|
*$method = sub { return $_[0]->{duration}->$method() }; |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
|
160
|
25
|
100
|
|
25
|
1
|
75
|
sub is_forward_mode { return $_[0]->is_wrap_mode() ? 1 : 0 } |
161
|
|
|
|
|
|
|
|
162
|
0
|
0
|
|
0
|
1
|
0
|
sub is_backward_mode { return $_[0]->is_wrap_mode() ? 0 : 1 } |
163
|
|
|
|
|
|
|
|
164
|
0
|
|
|
0
|
1
|
0
|
sub holiday_mode { return ( qw{ backward forward } )[ |
165
|
|
|
|
|
|
|
$_[0]->is_forward_mode() ] } |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
sub deltas { |
168
|
62
|
|
|
62
|
1
|
762
|
my ( $self ) = @_; |
169
|
|
|
|
|
|
|
return ( |
170
|
|
|
|
|
|
|
$self->{duration}->deltas(), |
171
|
|
|
|
|
|
|
weeks => $self->{weeks}, |
172
|
|
|
|
|
|
|
years => $self->{years}, |
173
|
62
|
|
|
|
|
175
|
); |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
{ |
177
|
|
|
|
|
|
|
my %on_side = map { $_ => 1 } qw{ years weeks }; |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
sub in_units { |
180
|
0
|
|
|
0
|
0
|
0
|
my ( $self, @units ) = @_; |
181
|
0
|
|
|
|
|
0
|
my @rslt = $self->{duration}->in_units( @units ); |
182
|
0
|
|
|
|
|
0
|
foreach my $inx ( 0 .. $#units ) { |
183
|
|
|
|
|
|
|
$on_side{$units[$inx]} |
184
|
0
|
0
|
|
|
|
0
|
and $rslt[$inx] = $self->{$units[$inx]}; |
185
|
|
|
|
|
|
|
} |
186
|
0
|
0
|
|
|
|
0
|
return wantarray ? @rslt : $rslt[0]; |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
# Note that we always specify am end-of-month mode to the contained |
191
|
|
|
|
|
|
|
# DateTime::Duration, because it does not have enough information to |
192
|
|
|
|
|
|
|
# properly default, AND if an end-of-month mode was originally specified |
193
|
|
|
|
|
|
|
# it is not preserved across the inversion. |
194
|
|
|
|
|
|
|
sub inverse { |
195
|
20
|
|
|
20
|
0
|
695
|
my ( $self, %arg ) = @_; |
196
|
|
|
|
|
|
|
|
197
|
20
|
50
|
|
|
|
88
|
if ( $arg{holiday} ) { |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
198
|
0
|
|
|
|
|
0
|
$arg{end_of_month} = _map_holiday_mode( delete $arg{holiday} ); |
199
|
|
|
|
|
|
|
} elsif ( $arg{end_of_month} ) { |
200
|
|
|
|
|
|
|
# Do nothing |
201
|
|
|
|
|
|
|
} elsif ( $self->{mode_specified} ) { |
202
|
4
|
|
|
|
|
16
|
$arg{end_of_month} = $self->end_of_month_mode(); |
203
|
|
|
|
|
|
|
} else { |
204
|
16
|
|
|
|
|
42
|
my %delta = $self->deltas(); |
205
|
16
|
|
|
|
|
289
|
$arg{end_of_month} = _compute_default_mode( \%delta, 1 ); |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
|
208
|
20
|
|
|
|
|
65
|
my %inverse = %{ $self }; |
|
20
|
|
|
|
|
90
|
|
209
|
|
|
|
|
|
|
$inverse{weeks} |
210
|
20
|
100
|
|
|
|
65
|
and $inverse{weeks} *= -1; |
211
|
|
|
|
|
|
|
$inverse{years} |
212
|
20
|
100
|
|
|
|
54
|
and $inverse{years} *= -1; |
213
|
20
|
|
|
|
|
77
|
$inverse{duration} = $self->{duration}->inverse( %arg ); |
214
|
20
|
|
|
|
|
2589
|
return bless \%inverse, ref $self; |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
sub is_negative { |
218
|
1
|
|
|
1
|
0
|
5
|
my ( $self ) = @_; |
219
|
1
|
50
|
|
|
|
8
|
$self->{weeks} > 0 |
220
|
|
|
|
|
|
|
and return 0; |
221
|
0
|
0
|
|
|
|
0
|
$self->{years} > 0 |
222
|
|
|
|
|
|
|
and return 0; |
223
|
|
|
|
|
|
|
( $self->{weeks} || $self->{years} ) |
224
|
0
|
0
|
0
|
|
|
0
|
and return $self->{duration}->is_negative() ? 1 : 0; |
|
|
0
|
|
|
|
|
|
225
|
0
|
|
|
|
|
0
|
return $self->{duration}->is_negative(); |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
sub is_positive { |
229
|
1
|
|
|
1
|
0
|
219
|
my ( $self ) = @_; |
230
|
1
|
50
|
|
|
|
31
|
$self->{weeks} < 0 |
231
|
|
|
|
|
|
|
and return 0; |
232
|
1
|
50
|
|
|
|
5
|
$self->{years} < 0 |
233
|
|
|
|
|
|
|
and return 0; |
234
|
|
|
|
|
|
|
( $self->{weeks} || $self->{years} ) |
235
|
1
|
50
|
33
|
|
|
8
|
and return $self->{duration}->is_positive() ? 1 : 0; |
|
|
50
|
|
|
|
|
|
236
|
0
|
|
|
|
|
0
|
return $self->{duration}->is_positive(); |
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
sub is_zero { |
240
|
34
|
|
|
34
|
0
|
79
|
my ( $self ) = @_; |
241
|
|
|
|
|
|
|
return ( $self->{duration}->is_zero() && 0 == $self->{weeks} && |
242
|
34
|
50
|
66
|
|
|
128
|
$self->{years} == 0 ) ? 1 : 0; |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
sub multiply { |
246
|
1
|
|
|
1
|
0
|
4
|
my ( $self, $multiplier ) = @_; |
247
|
1
|
|
|
|
|
2
|
$self->{weeks} *= $multiplier; |
248
|
1
|
|
|
|
|
3
|
$self->{years} *= $multiplier; |
249
|
1
|
|
|
|
|
6
|
$self->{duration}->multiply( $multiplier ); |
250
|
1
|
|
|
|
|
69
|
return $self; |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
sub subtract { |
254
|
1
|
|
|
1
|
0
|
646
|
my ( $self, @arg ) = @_; |
255
|
1
|
|
|
|
|
4
|
return $self->subtract_duration( _make_duration( @arg ) ); |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
sub subtract_duration { |
259
|
2
|
|
|
2
|
0
|
273
|
my ( $self, $dur ) = @_; |
260
|
2
|
|
|
|
|
43
|
return $self->add_duration( $dur->inverse() ); |
261
|
|
|
|
|
|
|
} |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
sub weeks { |
264
|
1
|
|
|
1
|
0
|
606
|
my ( $self ) = @_; |
265
|
1
|
|
|
|
|
7
|
return abs $self->{weeks}; |
266
|
|
|
|
|
|
|
} |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
sub years { |
269
|
1
|
|
|
1
|
0
|
600
|
my ( $self ) = @_; |
270
|
1
|
|
|
|
|
7
|
return abs $self->{years}; |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
sub _add_overload { |
274
|
1
|
|
|
1
|
|
118
|
my ( $left, $right, $reverse ) = @_; |
275
|
|
|
|
|
|
|
|
276
|
1
|
50
|
|
|
|
6
|
$reverse |
277
|
|
|
|
|
|
|
and ( $left, $right ) = ( $right, $left ); |
278
|
|
|
|
|
|
|
|
279
|
1
|
50
|
|
|
|
4
|
_isa( $right, 'DateTime::Fiction::JRRTolkien::Shire' ) |
280
|
|
|
|
|
|
|
and return $right->clone()->add_duration( $left ); |
281
|
|
|
|
|
|
|
|
282
|
1
|
|
|
|
|
6
|
return $left->clone()->add_duration( $right ); |
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
sub _compare_overload { |
286
|
0
|
|
|
0
|
|
0
|
Carp::croak( |
287
|
|
|
|
|
|
|
'DateTime::Fiction::JRRTolkien::Shire::Duration does not overload comparison' ); |
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
# Compute the default mode. Arguments are a reference to the argument |
291
|
|
|
|
|
|
|
# hash to compute from, and an optional invert flag. The basic |
292
|
|
|
|
|
|
|
# computation is to return 'preserve' if $arg->{months} * 30 + |
293
|
|
|
|
|
|
|
# $arg->{weeks} * 7 is negative, and 'wrap' otherwise. If the invert |
294
|
|
|
|
|
|
|
# flag is true, the opposite is returned. |
295
|
|
|
|
|
|
|
sub _compute_default_mode { |
296
|
51
|
|
|
51
|
|
120
|
my ( $arg, $invert ) = @_; |
297
|
|
|
|
|
|
|
my $inx = ( $arg->{years} * 365 + $arg->{months} * 30 + |
298
|
51
|
100
|
|
|
|
185
|
$arg->{weeks} * 7 ) >= 0 ? 1 : 0; |
299
|
51
|
100
|
|
|
|
125
|
$invert |
300
|
|
|
|
|
|
|
and $inx = 1 - $inx; |
301
|
51
|
|
|
|
|
143
|
return ( qw{ preserve wrap } )[$inx]; |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
sub _isa { |
305
|
6
|
|
|
6
|
|
15
|
my ( $obj, $class ) = @_; |
306
|
6
|
|
66
|
|
|
88
|
return Scalar::Util::blessed( $obj ) && $obj->isa( $class ); |
307
|
|
|
|
|
|
|
} |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
sub _make_duration { |
310
|
2
|
|
|
2
|
|
6
|
my @arg = @_; |
311
|
2
|
50
|
33
|
|
|
11
|
if ( 1 == @arg && Scalar::Util::blessed( $arg[0] ) ) { |
312
|
0
|
0
|
|
|
|
0
|
$arg[0]->isa( __PACKAGE__ ) |
313
|
|
|
|
|
|
|
and return $arg[0]; |
314
|
0
|
0
|
|
|
|
0
|
$arg[0]->isa( 'DateTime::Duration' ) |
315
|
|
|
|
|
|
|
and return __PACKAGE__->new( $arg[0]->deltas() ); |
316
|
|
|
|
|
|
|
} |
317
|
2
|
|
|
|
|
8
|
return __PACKAGE__->new( @arg ); |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
{ |
321
|
|
|
|
|
|
|
my %mode = ( |
322
|
|
|
|
|
|
|
forward => 'wrap', |
323
|
|
|
|
|
|
|
backward => 'preserve', |
324
|
|
|
|
|
|
|
); |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
sub _map_holiday_mode { |
327
|
6
|
|
|
6
|
|
13
|
my ( $m ) = @_; |
328
|
6
|
50
|
|
|
|
22
|
my $rslt = $mode{$m} |
329
|
|
|
|
|
|
|
or Carp::croak( "Invalid holiday mode '$m'"); |
330
|
6
|
|
|
|
|
15
|
return $rslt; |
331
|
|
|
|
|
|
|
} |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
sub _multiply_overload { |
335
|
1
|
|
|
1
|
|
633
|
my ( $left, $right ) = @_; |
336
|
1
|
|
|
|
|
6
|
return $left->clone()->multiply( $right ); |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
sub _subtract_overload { |
340
|
1
|
|
|
1
|
|
687
|
my ( $left, $right, $reverse ) = @_; |
341
|
|
|
|
|
|
|
|
342
|
1
|
50
|
|
|
|
5
|
$reverse |
343
|
|
|
|
|
|
|
and ( $left, $right ) = ( $right, $left ); |
344
|
|
|
|
|
|
|
|
345
|
1
|
50
|
|
|
|
5
|
_isa( $right, 'DateTime::Fiction::JRRTolkien::Shire' ) |
346
|
|
|
|
|
|
|
and Carp::croak( |
347
|
|
|
|
|
|
|
'Can not subtract a DateTime::Fiction::JRRTolkien::Shire from a DateTime::Fiction::JRRTolkien::Shire::Duration' ); |
348
|
|
|
|
|
|
|
|
349
|
1
|
|
|
|
|
8
|
return $left->clone()->subtract_duration( $right ); |
350
|
|
|
|
|
|
|
} |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
1; |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
__END__ |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
=head1 NAME |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
DateTime::Fiction::JRRTolkien::Shire::Duration - Duration objects for Shire calendar date math |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
=head1 SYNOPSIS |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
use DateTime::Fiction::JRRTolkien::Shire; |
363
|
|
|
|
|
|
|
use DateTime::Fiction::JRRTolkien::Shire::Duration; |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
my $dt = DateTime::Fiction::JRRTolkien::Shire->new( |
366
|
|
|
|
|
|
|
year => 1419, |
367
|
|
|
|
|
|
|
month => 3, |
368
|
|
|
|
|
|
|
day => 25, |
369
|
|
|
|
|
|
|
); |
370
|
|
|
|
|
|
|
my $dur = DateTime::Fiction::JRRTolkien::Shire::Duration->new( |
371
|
|
|
|
|
|
|
years => 1, |
372
|
|
|
|
|
|
|
months => 2, |
373
|
|
|
|
|
|
|
weeks => 3, |
374
|
|
|
|
|
|
|
days => 4, |
375
|
|
|
|
|
|
|
hours => 5, |
376
|
|
|
|
|
|
|
minutes => 6, |
377
|
|
|
|
|
|
|
seconds => 7, |
378
|
|
|
|
|
|
|
nanoseconds => 8, |
379
|
|
|
|
|
|
|
holiday => 'forward', |
380
|
|
|
|
|
|
|
); |
381
|
|
|
|
|
|
|
print $dt->add( $dur )->iso8601(), "\n"; |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
=head1 DESCRIPTION |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
This is a simple class for representing durations in the Shire calendar. |
386
|
|
|
|
|
|
|
It is B<not> a subclass of L<DateTime::Duration|DateTime::Duration>, |
387
|
|
|
|
|
|
|
though it implements the same interface, plus some extra bells and |
388
|
|
|
|
|
|
|
whistles. Objects of this class are used whenever you do date math with |
389
|
|
|
|
|
|
|
L<DateTime::Fiction::JRRTolkien::Shire|DateTime::Fiction::JRRTolkien::Shire>. |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
Unlike L<DateTime::Duration|DateTime::Duration>, this class preserves |
392
|
|
|
|
|
|
|
years and weeks rather than folding them into months and days |
393
|
|
|
|
|
|
|
respectively. This is because the Shire calendar contains days that are |
394
|
|
|
|
|
|
|
not part of any week or month. An example may clarify this. |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
You would expect adding a week to a Monday to produce the following |
397
|
|
|
|
|
|
|
Monday. But adding seven days to 30 Forelithe (a Mersday) gives you 4 |
398
|
|
|
|
|
|
|
Afterlithe (a Hevensday) because the interval between these two dates |
399
|
|
|
|
|
|
|
contains Midsummer's day, which is not part of any week. In a leap year |
400
|
|
|
|
|
|
|
this would give 3 Afterlithe (a Trewsday) because the leap year day also |
401
|
|
|
|
|
|
|
falls in this interval and is part of no week. The issues for months are |
402
|
|
|
|
|
|
|
similar. |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
A related issue with this calendar is what happens when you try, for |
405
|
|
|
|
|
|
|
example, to add a month to a date that is not part of any month. When |
406
|
|
|
|
|
|
|
something like this happens, the date is first adjusted to a nearby date |
407
|
|
|
|
|
|
|
that B<is> part of a month (or week). By default the adjustment is |
408
|
|
|
|
|
|
|
forward for a positive delta and backward for a negative delta, though |
409
|
|
|
|
|
|
|
you can specify the direction of adjustment when the object is |
410
|
|
|
|
|
|
|
instantiated. So adding a month to 1 Lithe gives 1 Wedmath by default, |
411
|
|
|
|
|
|
|
but 30 Afterlithe if the adjustment is backward. |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
=head1 METHODS |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
This class supports the following public methods over and above those |
416
|
|
|
|
|
|
|
supplied by L<DateTime::Duration|DateTime::Duration>: |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
=head2 new |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
This static method takes the same arguments as the corresponding |
421
|
|
|
|
|
|
|
L<DateTime::Duration|DateTime::Duration> method. As (maybe) a |
422
|
|
|
|
|
|
|
convenience, it also takes a C<holiday> parameter in lieu of the |
423
|
|
|
|
|
|
|
C<end_of_month> parameter. |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
The C<holiday> parameter must be either C<forward> or C<backward>, and |
426
|
|
|
|
|
|
|
specifies how a date should be adjusted (if needed) before doing |
427
|
|
|
|
|
|
|
arithmetic on it. |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
If you specify C<end_of_month> (a misnomer in this case since all Shire |
430
|
|
|
|
|
|
|
months have 30 days), C<wrap> specifies a forward adjustment, and |
431
|
|
|
|
|
|
|
anything else specifies a backward adjustment. |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
=head2 deltas |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
This method returns the deltas stored in the object. Possible keys are |
436
|
|
|
|
|
|
|
C<years>, C<months>, C<weeks>, C<days>, C<minutes>, C<seconds>, and |
437
|
|
|
|
|
|
|
C<nanoseconds>. |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
=head2 delta_weeks |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
This method returns the C<weeks> element of the object. |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
=head2 delta_years |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
This method returns the C<years> element of the object. |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
=head2 holiday_mode |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
This method returns one of the strings C<forward> or C<backward>, |
450
|
|
|
|
|
|
|
representing how dates are to be adjusted (if necessary) before |
451
|
|
|
|
|
|
|
performing arithmetic on them. |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
=head2 is_backward_mode |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
This method returns C<1> if dates are to be adjusted backward (if |
456
|
|
|
|
|
|
|
necessary) before doing arithmetic on them, and C<0> otherwise. |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
=head2 is_forward_mode |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
This method returns C<1> if dates are to be adjusted forward (if |
461
|
|
|
|
|
|
|
necessary) before doing arithmetic on them, and C<0> otherwise. |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
=head1 SEE ALSO |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
L<DateTime::Fiction::JRRTolkien::Shire|DateTime::Fiction::JRRTolkien::Shire> |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
L<DateTime|DateTime> |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
L<DateTime::Duration|DateTime::Duration> |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
=head1 SUPPORT |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
Support is by the author. Please file bug reports at |
474
|
|
|
|
|
|
|
L<https://rt.cpan.org/Public/Dist/Display.html?Name=DateTime-Fiction-JRRTolkien-Shire>, |
475
|
|
|
|
|
|
|
L<https://github.com/trwyant/perl-DateTime-Fiction-JRRTolkien-Shire/issues>, or in |
476
|
|
|
|
|
|
|
electronic mail to the author. |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
=head1 AUTHOR |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
Thomas R. Wyant, III F<wyant at cpan dot org> |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
Copyright (C) 2017-2021 by Thomas R. Wyant, III |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
487
|
|
|
|
|
|
|
under the same terms as Perl 5.10.0. For more details, see the full text |
488
|
|
|
|
|
|
|
of the licenses in the directory LICENSES. |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, but |
491
|
|
|
|
|
|
|
without any warranty; without even the implied warranty of |
492
|
|
|
|
|
|
|
merchantability or fitness for a particular purpose. |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
=cut |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
# ex: set textwidth=72 : |