File Coverage

blib/lib/DateTimeX/Auto.pm
Criterion Covered Total %
statement 107 141 75.8
branch 31 60 51.6
condition 7 31 22.5
subroutine 26 31 83.8
pod 0 1 0.0
total 171 264 64.7


line stmt bran cond sub pod time code
1 2     2   55436 use 5.008;
  2         6  
  2         67  
2 2     2   10 use strict;
  2         5  
  2         60  
3 2     2   8 use warnings;
  2         7  
  2         64  
4              
5             {
6             package DateTimeX::Auto;
7            
8 2     2   3206 use overload ();
  2         2071  
  2         38  
9 2     2   12 use Carp qw( croak );
  2         4  
  2         156  
10 2     2   1653 use Exporter::Shiny 0.036 qw( d dt dur );
  2         8781  
  2         10  
11            
12             BEGIN {
13 2     2   127 $DateTimeX::Auto::AUTHORITY = 'cpan:TOBYINK';
14 2         908 $DateTimeX::Auto::VERSION = '0.008';
15             }
16            
17             our %EXPORT_TAGS = (
18             auto => sub {
19             my $class = shift;
20             my ($name, $args, $globals) = @_;
21            
22             my $datetime_class = $args->{datetime_class} || "$class\::DateTime";
23             my $duration_class = $args->{duration_class} || "$class\::Duration";
24            
25             overload::constant "q" => sub {
26             return $_[1] unless $_[2] eq "q";
27             $datetime_class->new($_[0]) or $duration_class->new($_[0]) or $_[1];
28             };
29            
30             return;
31             },
32             );
33            
34             sub unimport
35             {
36 2     2   18 overload::remove_constant "q" => undef;
37             }
38            
39             sub _generate_d
40             {
41 1     1   844 my $class = shift;
42 1         2 my ($name, $args, $globals) = @_;
43 1   33     6 my $datetime_class = $args->{datetime_class} || "$class\::DateTime";
44            
45             sub {
46 7 100   7   3184 return $datetime_class->now if not @_;
47 6 50       22 $datetime_class->new("$_[0]")
48             or croak("Could not turn '$_[0]' into a DateTime; stopped");
49 1         7 };
50             }
51            
52             sub _generate_dt
53             {
54 0     0   0 shift->_generate_d(@_);
55             }
56            
57             sub _generate_dur
58             {
59 0     0   0 my $class = shift;
60 0         0 my ($name, $args, $globals) = @_;
61 0   0     0 my $duration_class = $args->{duration_class} || "$class\::Duration";
62            
63             sub {
64 0 0   0   0 $duration_class->new("$_[0]")
65             or croak("Could not turn '$_[0]' into a Duration; stopped");
66 0         0 };
67             }
68            
69             # For back-compat, allow construtor to be called for this package
70             sub new
71             {
72 0     0 0 0 shift;
73 0         0 'DateTimeX::Auto::DateTime'->new(@_);
74             }
75             }
76              
77             {
78             package DateTimeX::Auto::DateTime;
79            
80 2     2   18 use base qw[DateTime];
  2         4  
  2         4380  
81 2     2   363931 use UNIVERSAL::ref;
  2         368146  
  2         18  
82 2     2   169 use constant ref => 'DateTime';
  2         13  
  2         140  
83            
84 2     2   2996 use DateTime::Format::Strptime qw[];
  2         14770  
  2         99  
85            
86             BEGIN {
87 2     2   5 $DateTimeX::Auto::DateTime::AUTHORITY = 'cpan:TOBYINK';
88 2         1365 $DateTimeX::Auto::DateTime::VERSION = '0.008';
89             }
90            
91             sub from_object
92             {
93 2     2   1100 my ($proto, %args) = @_;
94            
95 2         5 my %x;
96 2         17 my $rv = $proto->SUPER::from_object(%args);
97 2 50       291 $rv->{+__PACKAGE__} = { %x } if %x = %{ $args{object}->{+__PACKAGE__} };
  2         20  
98            
99 2         11 return $rv;
100             }
101            
102             sub new
103             {
104 17 100   17   229 if (scalar @_ > 2)
105             {
106 2         3 my $class = shift;
107 2         14 return $class->SUPER::new(@_);
108             }
109            
110 15         21 my ($class, $string) = @_;
111            
112 15 100       64 if ($string =~ /^(\d{4})-(0[1-9]|1[0-2])-([0-2][0-9]|30|31)(Z?)$/)
113             {
114 5         6 my $dt;
115 5 50       17 my $z = defined($4) ? $4 : '';
116 5         7 eval {
117 5         27 $dt = $class->SUPER::new( year => $1, month=>$2, day=>$3, hour=>0, minute=>0, second=>0 );
118 5         1434 $dt->{+__PACKAGE__}{format} = 'D';
119 5 100 66     26 if ($z eq 'Z' and defined $dt)
120             {
121 2         6 $dt->set_time_zone('UTC');
122 2         290 $dt->{+__PACKAGE__}{trailer} = $z;
123             }
124             };
125 5 50       16 return $dt if $dt;
126             }
127            
128 10 100       37 if ($string =~ /^(\d{4})-(0[1-9]|1[0-2])-([0-2][0-9]|30|31)T([0-1][0-9]|2[0-4]):([0-5][0-9]):([0-5][0-9]|60)(\.[0-9]+)?(Z?)$/)
129             {
130 5         8 my $dt;
131 5 50       16 my $z = defined($8) ? $8 : '';
132 5 100       13 my $nano = defined($7) ? $7 : '';
133 5         8 eval {
134 5         23 $dt = $class->SUPER::new( year => $1, month=>$2, day=>$3, hour=>$4, minute=>$5, second=>$6 );
135 5         958 $dt->{+__PACKAGE__}{format} = 'DT';
136 5 100 66     36 if (length $nano and defined $dt)
137             {
138 2         5 $dt->{+__PACKAGE__}{format} = length($nano) - 1;
139 2         6 $dt->{rd_nanosecs} = substr($nano.('0' x 9), 1, 9) + 0;
140             }
141 5 100 66     23 if ($z eq 'Z' and defined $dt)
142             {
143 2         4 $dt->set_time_zone('UTC');
144 2         237 $dt->{+__PACKAGE__}{trailer} = $z;
145             }
146             };
147 5 50       22 return $dt if $dt;
148             }
149            
150 5         31 return undef;
151             }
152            
153             sub set_time_zone
154             {
155 6     6   686 my ($self, @args) = @_;
156 6         12 delete $self->{+__PACKAGE__}{trailer};
157 6         29 $self->SUPER::set_time_zone(@args);
158             }
159            
160             use overload '""' => sub
161             {
162 50     50   2974 my ($self) = @_;
163            
164 50 50       104 return $self->SUPER::_stringify
165             unless exists $self->{+__PACKAGE__};
166            
167 50         76 my $trailer = $self->{+__PACKAGE__}{trailer};
168 50 100       91 $trailer = '' unless defined $trailer;
169            
170 50 100       154 return $self->ymd('-') . $trailer
171             if $self->{+__PACKAGE__}{format} eq 'D';
172            
173 26 100       80 return sprintf('%sT%s%s', $self->ymd('-'), $self->hms(':'), $trailer)
174             if $self->{+__PACKAGE__}{format} eq 'DT';
175            
176 10         31 my $nano = substr(
177             $self->strftime('%N') . ('0' x $self->{+__PACKAGE__}{format}),
178             0,
179             $self->{+__PACKAGE__}{format},
180             );
181 10         269 sprintf(
182             '%sT%s.%s%s',
183             $self->ymd('-'),
184             $self->hms(':'),
185             $nano,
186             $trailer,
187             );
188 2     2   17 };
  2         5  
  2         26  
189             }
190              
191             {
192             package DateTimeX::Auto::Duration;
193            
194 2     2   153 use base qw[DateTime::Duration];
  2         3  
  2         201  
195 2     2   9 use UNIVERSAL::ref;
  2         4  
  2         15  
196 2     2   70 use constant ref => 'DateTime::Duration';
  2         4  
  2         147  
197            
198             BEGIN {
199 2     2   4 $DateTimeX::Auto::Duration::AUTHORITY = 'cpan:TOBYINK';
200 2         1092 $DateTimeX::Auto::Duration::VERSION = '0.008';
201             }
202            
203             sub new
204             {
205 5 50   5   24 if (scalar @_ > 2)
206             {
207 0         0 my $class = shift;
208 0         0 return $class->SUPER::new(@_);
209             }
210            
211 5         7 my ($class, $string) = @_;
212            
213 5 50       151 return undef unless $string =~ /^
214             ([\+\-])? # Potentially negitive...
215             P # Period of...
216             (?:([\d\.]*)Y)? # n Years
217             (?:([\d\.]*)M)? # n Months
218             (?:([\d\.]*)W)? # n Weeks
219             (?:([\d\.]*)D)? # n Days
220             (?:
221             T # And a time of...
222             (?:([\d\.]*)H)? # n Hours
223             (?:([\d\.]*)M)? # n Minutes
224             (?:([\d\.]*)S)? # n Seconds
225             )?
226             /ix;
227            
228 0           my $X = {
229             I => $1,
230             y => $2,
231             m => $3,
232             w => $4,
233             d => $5,
234             h => $6,
235             min => $7,
236             s => $8,
237             n => 0,
238             };
239            
240             # Handle fractional
241 0           foreach my $frac (qw(y=12.m m=30.d w=7.d d=24.h h=60.min min=60.s s=1000000000.n))
242             {
243 0           my ($big, $mult, $small) = split /[\=\.]/, $frac;
244 0 0         next unless $X->{$big} =~ /\./;
245            
246 0           my $int_part = int($X->{$big});
247 0           my $frac_part = $X->{$big} - $int_part;
248            
249 0           $X->{$big} = $int_part;
250 0           $X->{$small} += ($mult * $frac_part);
251             }
252 0           $X->{'n'} = int($X->{'n'});
253            
254             # Construct and return object.
255 0   0       my $dur = $class->SUPER::new(
      0        
      0        
      0        
      0        
      0        
      0        
      0        
256             years => $X->{'y'} || 0,
257             months => $X->{'m'} || 0,
258             weeks => $X->{'w'} || 0,
259             days => $X->{'d'} || 0,
260             hours => $X->{'h'} || 0,
261             minutes => $X->{'min'} || 0,
262             seconds => $X->{'s'} || 0,
263             nanoseconds => $X->{'n'} || 0,
264             );
265            
266 0 0         $X->{'I'} eq '-' ? $dur->inverse : $dur;
267             }
268            
269             use overload '""' => sub
270             {
271 0     0   0 my $self = shift;
272            
273             # We coerce weeks into days and nanoseconds into fractions of a second
274             # for compatibility with xsd:duration.
275 0         0 my $_days = $self->days + (7 * $self->weeks);
276 0         0 my $_secs = $self->seconds + ($self->nanoseconds / 1000000000);
277            
278 0 0       0 my $str = $self->is_negative ? '-P' : 'P';
279 0 0       0 $str .= $self->years . 'Y' if $self->years;
280 0 0       0 $str .= $self->months . 'M' if $self->months;
281 0 0       0 $str .= $_days . 'D' if $_days;
282 0         0 $str .= 'T';
283 0 0       0 $str .= $self->hours . 'H' if $self->hours;
284 0 0       0 $str .= $self->minutes . 'M' if $self->minutes;
285 0 0       0 $str .= $_secs . 'S' if $_secs;
286            
287 0         0 $str =~ s/T$//;
288            
289 0         0 return $str;
290 2     2   10 };
  2         3  
  2         12  
291             }
292              
293             __FILE__
294             __END__