line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Date::Easy::Datetime; |
2
|
|
|
|
|
|
|
|
3
|
18
|
|
|
18
|
|
304182
|
use strict; |
|
18
|
|
|
|
|
56
|
|
|
18
|
|
|
|
|
431
|
|
4
|
18
|
|
|
18
|
|
72
|
use warnings; |
|
18
|
|
|
|
|
27
|
|
|
18
|
|
|
|
|
342
|
|
5
|
18
|
|
|
18
|
|
1161
|
use autodie; |
|
18
|
|
|
|
|
35803
|
|
|
18
|
|
|
|
|
69
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = '0.09_01'; # TRIAL VERSION |
8
|
|
|
|
|
|
|
|
9
|
18
|
|
|
18
|
|
81185
|
use Exporter; |
|
18
|
|
|
|
|
36
|
|
|
18
|
|
|
|
|
659
|
|
10
|
18
|
|
|
18
|
|
87
|
use parent 'Exporter'; |
|
18
|
|
|
|
|
30
|
|
|
18
|
|
|
|
|
121
|
|
11
|
|
|
|
|
|
|
our @EXPORT_OK = qw< datetime now >; |
12
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( all => \@EXPORT_OK ); |
13
|
|
|
|
|
|
|
|
14
|
18
|
|
|
18
|
|
1750
|
use Carp; |
|
18
|
|
|
|
|
42
|
|
|
18
|
|
|
|
|
995
|
|
15
|
18
|
|
|
18
|
|
8403
|
use Time::Piece; |
|
18
|
|
|
|
|
160479
|
|
|
18
|
|
|
|
|
73
|
|
16
|
18
|
|
|
18
|
|
1488
|
use Scalar::Util 'blessed'; |
|
18
|
|
|
|
|
34
|
|
|
18
|
|
|
|
|
786
|
|
17
|
18
|
|
|
18
|
|
89
|
use Time::Local 1.26, qw< timegm_modern timelocal_modern >; |
|
18
|
|
|
|
|
32
|
|
|
18
|
|
|
|
|
38588
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
# this can be modified (preferably using `local`) to use GMT/UTC as the default |
21
|
|
|
|
|
|
|
# or you can pass a value to `import` via your `use` line |
22
|
|
|
|
|
|
|
our $DEFAULT_ZONE = 'local'; |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
my %ZONE_FLAG = ( local => 1, UTC => 0, GMT => 0 ); |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
sub import |
28
|
|
|
|
|
|
|
{ |
29
|
19
|
|
|
19
|
|
6196
|
my @args; |
30
|
19
|
100
|
|
|
|
107
|
exists $ZONE_FLAG{$_} ? $DEFAULT_ZONE = $_ : push @args, $_ foreach @_; |
31
|
19
|
|
|
|
|
45
|
@_ = @args; |
32
|
19
|
|
|
|
|
5272
|
goto &Exporter::import; |
33
|
|
|
|
|
|
|
} |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
############################## |
37
|
|
|
|
|
|
|
# FUNCTIONS (*NOT* METHODS!) # |
38
|
|
|
|
|
|
|
############################## |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
sub datetime |
41
|
|
|
|
|
|
|
{ |
42
|
2809
|
100
|
|
2809
|
1
|
1426050
|
my $zonespec = @_ % 2 == 0 ? shift : $DEFAULT_ZONE; |
43
|
2809
|
|
|
|
|
4113
|
my $datetime = shift; |
44
|
2809
|
100
|
|
|
|
10242
|
if ( $datetime =~ /^-?\d+$/ ) |
45
|
|
|
|
|
|
|
{ |
46
|
7
|
|
|
|
|
36
|
return Date::Easy::Datetime->new($zonespec, $datetime); |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
else |
49
|
|
|
|
|
|
|
{ |
50
|
2802
|
|
|
|
|
4748
|
my $t = _str2time($datetime, $zonespec); |
51
|
2802
|
100
|
|
|
|
4929
|
$t = _parsedate($datetime, $zonespec) unless defined $t; |
52
|
2802
|
100
|
|
|
|
73977
|
croak("Illegal datetime: $datetime") unless defined $t; |
53
|
2801
|
|
|
|
|
6544
|
return Date::Easy::Datetime->new( $zonespec, $t ); |
54
|
|
|
|
|
|
|
} |
55
|
0
|
|
|
|
|
0
|
die("reached unreachable code"); |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
5
|
|
|
5
|
1
|
1804
|
sub now () { Date::Easy::Datetime->new } |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
sub _strptime |
62
|
|
|
|
|
|
|
{ |
63
|
3047
|
|
|
3047
|
|
8104
|
require Date::Parse; |
64
|
|
|
|
|
|
|
# Most of this code is stolen from Date::Parse, by Graham Barr. It is used here (see _str2time, |
65
|
|
|
|
|
|
|
# below), but its true raison d'etre is for use by Date::Easy::Date. |
66
|
|
|
|
|
|
|
# |
67
|
|
|
|
|
|
|
# In an ideal world, I would just use the code from Date::Parse and not repeat it here. |
68
|
|
|
|
|
|
|
# However, the problem is that str2time() calls strptime() to generate the pieces of a datetime, |
69
|
|
|
|
|
|
|
# then does some validation, then returns epoch seconds by calling timegm (from Time::Local) on |
70
|
|
|
|
|
|
|
# it. For dates, I don't _want_ to call str2time because I'm just going to take the epoch |
71
|
|
|
|
|
|
|
# seconds and turn them back into pieces, so it's inefficicent. But more importantly I _can't_ |
72
|
|
|
|
|
|
|
# call str2time because it converts to UTC, and I want the pieces as they are relative to |
73
|
|
|
|
|
|
|
# whatever timezone the parsed date has. |
74
|
|
|
|
|
|
|
# |
75
|
|
|
|
|
|
|
# On the other hand, the problem with calling strptime directly is that str2time is doing two |
76
|
|
|
|
|
|
|
# things there: the conversion to epoch seconds, which I don't want or need for dates, and the |
77
|
|
|
|
|
|
|
# validation, which, it turns out, I *do* want, and need, even for dates. For instance, |
78
|
|
|
|
|
|
|
# strptime will happily return a month of -1 if it hits a parsing hiccough. Which then str2time |
79
|
|
|
|
|
|
|
# will turn into undef, as you would expect. But, if you're just calling strptime, that doesn't |
80
|
|
|
|
|
|
|
# help you much. :-( |
81
|
|
|
|
|
|
|
# |
82
|
|
|
|
|
|
|
# Thus, for dates in particular, I'm left with 3 possibilities, none of them very palatable: |
83
|
|
|
|
|
|
|
# # call strptime, then call str2time as well |
84
|
|
|
|
|
|
|
# # repeat at least some of the code from str2time here |
85
|
|
|
|
|
|
|
# # do Something Devious, like wrap/monkey-patch strptime |
86
|
|
|
|
|
|
|
# #1 doesn't seem practical, because it means that every string that has to be parsed this way |
87
|
|
|
|
|
|
|
# has to be parsed twice, meaning it will take twice as long. #3 seems too complex--since the |
88
|
|
|
|
|
|
|
# call to strptime is out of my control, I can't add arguments to it, or get any extra data out |
89
|
|
|
|
|
|
|
# of it, which means I have to store things in global variables, which means it wouldn't be |
90
|
|
|
|
|
|
|
# reentrant ... it would be a big mess. So #2, unpalatable as it is, is what we're going with. |
91
|
|
|
|
|
|
|
# |
92
|
|
|
|
|
|
|
# Of course, this gives me the opportunity to tweak a few things. Primarily, we can tweak our |
93
|
|
|
|
|
|
|
# code to fix RT/105031 et al (see comments below, in _str2time). There's a few minor |
94
|
|
|
|
|
|
|
# efficiency gains we can get from not doing things the older code seemed to think was |
95
|
|
|
|
|
|
|
# necessary. (Of course, maybe it really is, in which case I'll have to put it all back.) |
96
|
|
|
|
|
|
|
# |
97
|
|
|
|
|
|
|
# The code in _strptime is as much of Date::Parse::str2time as is necessary to handle all the |
98
|
|
|
|
|
|
|
# validation and still return separate time values. This way it can be used by both dates and |
99
|
|
|
|
|
|
|
# datetimes. |
100
|
|
|
|
|
|
|
|
101
|
3047
|
|
|
|
|
12198
|
my ($str, $zonespec) = @_; |
102
|
|
|
|
|
|
|
|
103
|
3047
|
100
|
|
|
|
54999
|
my ($sec, $min, $hour, $day, $month, $year, $zone) |
104
|
|
|
|
|
|
|
= Date::Parse::strptime($str, $zonespec eq 'local' ? () : $zonespec); |
105
|
3047
|
|
|
|
|
215545
|
my $num_defined = defined($day) + defined($month) + defined($year); |
106
|
3047
|
100
|
|
|
|
6580
|
return () if $num_defined == 0; |
107
|
2710
|
100
|
|
|
|
4508
|
if ($num_defined < 3) |
108
|
|
|
|
|
|
|
{ |
109
|
12
|
|
|
|
|
35
|
my @lt = localtime(time); |
110
|
|
|
|
|
|
|
|
111
|
12
|
50
|
|
|
|
599
|
$month = $lt[4] unless defined $month; |
112
|
12
|
50
|
|
|
|
24
|
$day = $lt[3] unless defined $day; |
113
|
12
|
50
|
|
|
|
44
|
$year = ($month > $lt[4]) ? ($lt[5] - 1) : $lt[5] unless defined $year; |
|
|
50
|
|
|
|
|
|
114
|
|
|
|
|
|
|
} |
115
|
2710
|
|
100
|
|
|
8012
|
$hour ||= 0; $min ||= 0; $sec ||= 0; # default time components to zero |
|
2710
|
|
100
|
|
|
6864
|
|
|
2710
|
|
100
|
|
|
6369
|
|
116
|
2710
|
|
|
|
|
3755
|
my $subsec = $sec - int($sec); $sec = int($sec);# extract any fractional part (e.g. milliseconds) |
|
2710
|
|
|
|
|
2912
|
|
117
|
2710
|
100
|
|
|
|
4321
|
$year += 1900 if $year < 1000; # undo timelocal funkiness and adjust for RT/53413 / RT/105031 |
118
|
|
|
|
|
|
|
|
119
|
2710
|
100
|
100
|
|
|
19540
|
return () unless $month >= 0 and $month <= 11 and $day >= 1 and $day <= 31 |
|
|
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
120
|
|
|
|
|
|
|
and $hour <= 23 and $min <= 59 and $sec <= 59; |
121
|
|
|
|
|
|
|
|
122
|
2637
|
|
|
|
|
8330
|
return ($sec, $min, $hour, $day, $month, $year, $zone, $subsec); |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
sub _str2time |
126
|
|
|
|
|
|
|
{ |
127
|
2802
|
|
|
2802
|
|
12550
|
require Date::Parse; |
128
|
|
|
|
|
|
|
# Most of this code is also stolen from Date::Parse, by Graham Barr. This is the remainder of |
129
|
|
|
|
|
|
|
# Date::Parse::str2time, which takes the separate values (from _strptime, above) and turns them |
130
|
|
|
|
|
|
|
# into an epoch seconds value. See also the big comment block below. |
131
|
|
|
|
|
|
|
|
132
|
2802
|
|
|
|
|
12535
|
my ($time, $zonespec) = @_; |
133
|
2802
|
|
|
|
|
4924
|
my ($sec, $min, $hour, $day, $month, $year, $zone, $subsec) = _strptime($time, $zonespec); |
134
|
|
|
|
|
|
|
# doesn't really matter which one we check (other than $zone); either they're all defined, or none are |
135
|
2802
|
100
|
|
|
|
5433
|
return undef unless defined $year; |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
# This block is changed from the original in Date::Parse in the following ways: |
138
|
|
|
|
|
|
|
# * We're using timegm_modern/timelocal_modern instead of timegm/timelocal. This fixes all |
139
|
|
|
|
|
|
|
# sorts of gnarly issues, but most especially the heinous RT/53413 / RT/105031 bug. (Side |
140
|
|
|
|
|
|
|
# note: perhaps Parse::Date could use these as well? If so, that would close that raft of |
141
|
|
|
|
|
|
|
# bugs and then we wouldn't need to reimplement the guts of `str2time` at all.) |
142
|
|
|
|
|
|
|
# * The original code set the __DIE__ sig handler to ignore in the `eval`s. But I'm not |
143
|
|
|
|
|
|
|
# comfortable doing that, and I'm not convinced it's necessary. |
144
|
|
|
|
|
|
|
# * The original code did a little dance to make sure that a -1 return from timegm/timelocal |
145
|
|
|
|
|
|
|
# was a valid return and not an indication of an error. But I can't see any indication |
146
|
|
|
|
|
|
|
# that they ever actually return -1 on error, either in the current Time::Local code, or |
147
|
|
|
|
|
|
|
# in its Changes file (e.g. for older versions). And, since our version of `strptime` |
148
|
|
|
|
|
|
|
# specifically adds 1900 to the year (sometimes) to avoid Time::Local's horrible |
149
|
|
|
|
|
|
|
# "two-digit year" handling, it makes coming up with a value to compare -1 against more of |
150
|
|
|
|
|
|
|
# a PITA. Plus it's inefficient for what appears to be no real gain. |
151
|
2484
|
|
|
|
|
2918
|
my $result; |
152
|
2484
|
100
|
|
|
|
3790
|
if (defined $zone) |
153
|
|
|
|
|
|
|
{ |
154
|
563
|
|
|
|
|
713
|
$result = eval { timegm_modern($sec, $min, $hour, $day, $month, $year) }; |
|
563
|
|
|
|
|
1398
|
|
155
|
563
|
50
|
|
|
|
14879
|
return undef unless defined $result; |
156
|
563
|
|
|
|
|
713
|
$result -= $zone; |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
else |
159
|
|
|
|
|
|
|
{ |
160
|
1921
|
|
|
|
|
2389
|
$result = eval { timelocal_modern($sec, $min, $hour, $day, $month, $year) }; |
|
1921
|
|
|
|
|
4606
|
|
161
|
1921
|
50
|
|
|
|
111003
|
return undef unless defined $result; |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
2484
|
|
|
|
|
4757
|
return $result + $subsec; |
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
sub _parsedate |
168
|
|
|
|
|
|
|
{ |
169
|
318
|
|
|
318
|
|
1190
|
require Time::ParseDate; |
170
|
318
|
|
|
|
|
526
|
my ($time, $zonespec) = @_; |
171
|
318
|
100
|
|
|
|
915
|
return scalar Time::ParseDate::parsedate($time, $zonespec eq 'local' ? () : (GMT => 1)); |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
####################### |
176
|
|
|
|
|
|
|
# REGULAR CLASS STUFF # |
177
|
|
|
|
|
|
|
####################### |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
sub new |
180
|
|
|
|
|
|
|
{ |
181
|
8229
|
|
|
8229
|
1
|
214805
|
my $class = shift; |
182
|
8229
|
100
|
100
|
|
|
22863
|
my $zonespec = @_ == 2 || @_ == 7 ? shift : $DEFAULT_ZONE; |
183
|
8229
|
100
|
|
|
|
15098
|
croak("Unrecognized timezone specifier") unless exists $ZONE_FLAG{$zonespec}; |
184
|
|
|
|
|
|
|
|
185
|
8228
|
|
|
|
|
8938
|
my $t; |
186
|
8228
|
100
|
|
|
|
17677
|
if (@_ == 0) |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
187
|
|
|
|
|
|
|
{ |
188
|
9
|
|
|
|
|
13
|
$t = time; |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
elsif (@_ == 6) |
191
|
|
|
|
|
|
|
{ |
192
|
44
|
|
|
|
|
92
|
my ($y, $m, $d, $H, $M, $S) = @_; |
193
|
44
|
|
|
|
|
74
|
--$m; # timelocal/timegm will expect month as 0..11 |
194
|
|
|
|
|
|
|
# but we'll use timelocal_modern/timegm_modern so we don't need to twiddle the year number |
195
|
44
|
100
|
|
|
|
55
|
$t = eval { $zonespec eq 'local' |
|
44
|
|
|
|
|
148
|
|
196
|
|
|
|
|
|
|
? timelocal_modern($S, $M, $H, $d, $m, $y) |
197
|
|
|
|
|
|
|
: timegm_modern($S, $M, $H, $d, $m, $y) |
198
|
|
|
|
|
|
|
}; |
199
|
44
|
100
|
|
|
|
2119
|
croak("Illegal datetime: $y/" . ($m + 1) . "/$d $H:$M:$S") unless defined $t; |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
elsif (@_ == 1) |
202
|
|
|
|
|
|
|
{ |
203
|
8170
|
|
|
|
|
9490
|
$t = shift; |
204
|
8170
|
100
|
|
|
|
20015
|
if ( my $conv_class = blessed $t ) |
205
|
|
|
|
|
|
|
{ |
206
|
3214
|
100
|
|
|
|
6947
|
if ( $t->isa('Time::Piece') ) |
207
|
|
|
|
|
|
|
{ |
208
|
|
|
|
|
|
|
# it's already what we were going to construct anyway; |
209
|
|
|
|
|
|
|
# just stick it in a hashref and call it a day |
210
|
3212
|
|
|
|
|
18353
|
return bless { impl => $t }, $class; |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
else |
213
|
|
|
|
|
|
|
{ |
214
|
2
|
|
|
|
|
20
|
croak("Don't know how to convert $conv_class to $class"); |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
else |
219
|
|
|
|
|
|
|
{ |
220
|
5
|
|
|
|
|
43
|
croak("Illegal number of arguments to datetime()"); |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
|
223
|
5008
|
|
|
|
|
12148
|
bless { impl => scalar Time::Piece->_mktime($t, $ZONE_FLAG{$zonespec}) }, $class; |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
|
227
|
7
|
|
|
7
|
1
|
755
|
sub is_local { shift->{impl}->[Time::Piece::c_islocal] } |
228
|
11
|
|
|
11
|
1
|
1100
|
sub is_gmt { !shift->{impl}->[Time::Piece::c_islocal] } |
229
|
|
|
|
|
|
|
*is_utc = \&is_gmt; |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
sub as |
233
|
|
|
|
|
|
|
{ |
234
|
6
|
|
|
6
|
1
|
2262
|
my ($self, $conv_spec) = @_; |
235
|
|
|
|
|
|
|
|
236
|
6
|
100
|
|
|
|
34
|
if ( $conv_spec =~ /^(\W)(\w+)$/ ) |
237
|
|
|
|
|
|
|
{ |
238
|
3
|
|
|
|
|
13
|
my $fmt = join($1, map { "%$_" } split('', $2)); |
|
9
|
|
|
|
|
22
|
|
239
|
3
|
|
|
|
|
8
|
return $self->strftime($fmt); |
240
|
|
|
|
|
|
|
} |
241
|
3
|
100
|
|
|
|
11
|
if ( $conv_spec eq 'Time::Piece' ) |
242
|
|
|
|
|
|
|
{ |
243
|
2
|
|
|
|
|
78
|
return $self->{impl}; |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
else |
246
|
|
|
|
|
|
|
{ |
247
|
1
|
|
|
|
|
13
|
croak("Don't know how to convert " . ref( $self) . " to $conv_spec"); |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
# ACCESSORS |
253
|
|
|
|
|
|
|
|
254
|
1903
|
|
|
1903
|
1
|
77015
|
sub year { shift->{impl}->year } |
255
|
3
|
|
|
3
|
1
|
1665
|
sub month { shift->{impl}->mon } |
256
|
3
|
|
|
3
|
1
|
1349
|
sub day { shift->{impl}->mday } |
257
|
6
|
|
|
6
|
1
|
2746
|
sub hour { shift->{impl}->hour } |
258
|
6
|
|
|
6
|
1
|
2679
|
sub minute { shift->{impl}->min } |
259
|
6
|
|
|
6
|
1
|
3085
|
sub second { shift->{impl}->sec } |
260
|
2608
|
|
|
2608
|
1
|
115091
|
sub epoch { shift->{impl}->epoch } |
261
|
2
|
|
|
2
|
1
|
845
|
sub time_zone { shift->{impl}->strftime('%Z') } |
262
|
14
|
100
|
|
14
|
1
|
592
|
sub day_of_week { shift->{impl}->day_of_week || 7 } # change Sunday from 0 to 7 |
263
|
1462
|
|
|
1462
|
1
|
30964
|
sub day_of_year { shift->{impl}->yday + 1 } # change from 0-based to 1-based |
264
|
24
|
|
|
24
|
1
|
974
|
sub quarter { int(shift->{impl}->_mon / 3) + 1 } # calc quarter from (zero-based) month |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
sub split |
267
|
|
|
|
|
|
|
{ |
268
|
1
|
|
|
1
|
1
|
455
|
my $impl = shift->{impl}; |
269
|
1
|
|
|
|
|
4
|
( $impl->year, $impl->mon, $impl->mday, $impl->hour, $impl->min, $impl->sec ) |
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
# FORMATTERS |
274
|
|
|
|
|
|
|
|
275
|
1348
|
|
|
1348
|
1
|
570982
|
sub strftime { shift->{impl}->strftime(@_) } |
276
|
2
|
|
|
2
|
1
|
1329
|
sub iso8601 { shift->{impl}->datetime } |
277
|
|
|
|
|
|
|
*iso = \&iso8601; |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
######################## |
281
|
|
|
|
|
|
|
# OVERLOADED OPERATORS # |
282
|
|
|
|
|
|
|
######################## |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
sub _op_convert |
285
|
|
|
|
|
|
|
{ |
286
|
14806
|
|
|
14806
|
|
18307
|
my $operand = shift; |
287
|
14806
|
100
|
|
|
|
37297
|
return $operand unless blessed $operand; |
288
|
9897
|
50
|
|
|
|
32546
|
return $operand->{impl} if $operand->isa('Date::Easy::Datetime'); |
289
|
0
|
0
|
|
|
|
0
|
return $operand if $operand->isa('Time::Piece'); |
290
|
0
|
|
|
|
|
0
|
croak ("don't know how to handle conversion of " . ref $operand); |
291
|
|
|
|
|
|
|
} |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
sub _result_convert |
294
|
|
|
|
|
|
|
{ |
295
|
4909
|
|
|
4909
|
|
5749
|
my $func = shift; |
296
|
4909
|
|
|
|
|
8672
|
return ref($_[0])->new( scalar $func->(_op_convert($_[0]), _op_convert($_[1]), $_[2]) ); |
297
|
|
|
|
|
|
|
} |
298
|
|
|
|
|
|
|
|
299
|
3194
|
|
|
3194
|
|
6421
|
sub _add_seconds { _result_convert( \&Time::Piece::add => @_ ) } |
300
|
1715
|
|
|
1715
|
|
3219
|
sub _subtract_seconds { _result_convert( \&Time::Piece::subtract => @_ ) } |
301
|
|
|
|
|
|
|
# subclasses can override these to change what units an integer represents |
302
|
1338
|
|
|
1338
|
|
2011
|
sub _add_integer { $_[0]->add_seconds($_[1]) } |
303
|
607
|
|
|
607
|
|
943
|
sub _subtract_integer { $_[0]->subtract_seconds($_[1]) } |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
sub _dispatch_add |
306
|
|
|
|
|
|
|
{ |
307
|
2333
|
100
|
66
|
2333
|
|
663013
|
if ( blessed $_[1] && $_[1]->isa('Date::Easy::Units') ) |
308
|
|
|
|
|
|
|
{ |
309
|
17
|
|
|
|
|
48
|
$_[1]->_add_to($_[0]); |
310
|
|
|
|
|
|
|
} |
311
|
|
|
|
|
|
|
else |
312
|
|
|
|
|
|
|
{ |
313
|
|
|
|
|
|
|
# this should DTRT for whichever class we are |
314
|
2316
|
|
|
|
|
4669
|
$_[0]->_add_integer($_[1]); |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
sub _dispatch_subtract |
319
|
|
|
|
|
|
|
{ |
320
|
902
|
100
|
100
|
902
|
|
40380
|
if ( blessed $_[1] && $_[1]->isa('Date::Easy::Units') ) |
|
|
100
|
66
|
|
|
|
|
321
|
|
|
|
|
|
|
{ |
322
|
|
|
|
|
|
|
# this shouldn't be possible ... |
323
|
16
|
50
|
|
|
|
31
|
die("should have called overloaded - for ::Units") if $_[2]; |
324
|
|
|
|
|
|
|
# as the name implies, this method assumes reversed operands |
325
|
16
|
|
|
|
|
40
|
$_[1]->_subtract_from($_[0]); |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
elsif ( blessed $_[1] && $_[1]->isa('Date::Easy::Datetime') ) |
328
|
|
|
|
|
|
|
{ |
329
|
33
|
50
|
|
|
|
81
|
my ($lhs, $rhs) = $_[2] ? @_[1,0] : @_[0,1]; |
330
|
33
|
100
|
66
|
|
|
114
|
my $divisor = $lhs->isa('Date::Easy::Date') && $rhs->isa('Date::Easy::Date') ? 86_400 : 1; |
331
|
33
|
|
|
|
|
58
|
($lhs->epoch - $rhs->epoch) / $divisor; |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
else |
334
|
|
|
|
|
|
|
{ |
335
|
|
|
|
|
|
|
# this should DTRT for whichever class we are |
336
|
853
|
|
|
|
|
1556
|
$_[0]->_subtract_integer($_[1]); |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
use overload |
341
|
1510
|
|
|
1510
|
|
9253
|
'""' => sub { Time::Piece::cdate (_op_convert($_[0]) ) }, |
342
|
10
|
|
|
10
|
|
2750
|
'<=>' => sub { Time::Piece::compare (_op_convert($_[0]), _op_convert($_[1]), $_[2]) }, |
343
|
1729
|
|
|
1729
|
|
327192
|
'cmp' => sub { Time::Piece::str_compare(_op_convert($_[0]), _op_convert($_[1]), $_[2]) }, |
344
|
|
|
|
|
|
|
|
345
|
18
|
|
|
|
|
195
|
'+' => \&_dispatch_add, |
346
|
|
|
|
|
|
|
'-' => \&_dispatch_subtract, |
347
|
18
|
|
|
18
|
|
125
|
; |
|
18
|
|
|
|
|
35
|
|
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
# MATH METHODS |
351
|
|
|
|
|
|
|
|
352
|
1464
|
|
|
1464
|
1
|
42136
|
sub add_seconds { shift->_add_seconds (@_) } |
353
|
125
|
|
|
125
|
1
|
321
|
sub add_minutes { shift->_add_seconds ($_[0] * 60) } |
354
|
126
|
|
|
126
|
1
|
317
|
sub add_hours { shift->_add_seconds ($_[0] * 60 * 60) } |
355
|
1479
|
|
|
1479
|
1
|
39571
|
sub add_days { shift->_add_seconds ($_[0] * 60 * 60 * 24) } |
356
|
250
|
|
|
250
|
1
|
36531
|
sub add_weeks { shift->add_days ($_[0] * 7) } |
357
|
19
|
|
|
19
|
1
|
2591
|
sub add_months { ref($_[0])->new( shift->{impl}->add_months(@_) ) } |
358
|
18
|
|
|
18
|
1
|
2216
|
sub add_years { ref($_[0])->new( shift->{impl}->add_years (@_) ) } |
359
|
|
|
|
|
|
|
|
360
|
730
|
|
|
730
|
1
|
1277
|
sub subtract_seconds { shift->_subtract_seconds (@_) } |
361
|
124
|
|
|
124
|
1
|
293
|
sub subtract_minutes { shift->_subtract_seconds ($_[0] * 60) } |
362
|
123
|
|
|
123
|
1
|
305
|
sub subtract_hours { shift->_subtract_seconds ($_[0] * 60 * 60) } |
363
|
738
|
|
|
738
|
1
|
37354
|
sub subtract_days { shift->_subtract_seconds ($_[0] * 60 * 60 * 24) } |
364
|
246
|
|
|
246
|
1
|
36529
|
sub subtract_weeks { shift->subtract_days ($_[0] * 7) } |
365
|
5
|
|
|
5
|
1
|
572
|
sub subtract_months { shift->add_months($_[0] * -1) } |
366
|
6
|
|
|
6
|
1
|
582
|
sub subtract_years { shift->add_years ($_[0] * -1) } |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
1; |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
# ABSTRACT: easy datetime class |
375
|
|
|
|
|
|
|
# COPYRIGHT |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
__END__ |