File Coverage

blib/lib/DateTimeX/AATW.pm
Criterion Covered Total %
statement 105 154 68.1
branch 27 52 51.9
condition 4 9 44.4
subroutine 13 15 86.6
pod 11 11 100.0
total 160 241 66.3


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             DateTimeX::AATW - DateTime All Around The World
4              
5             =head1 SYNOPSIS
6              
7             use DateTime;
8             use DateTimeX::AATW;
9              
10             my $dt = DateTime->now();
11             my $aatw = DateTimeX::AATW->new($dt);
12              
13             ### Return names of all time zones that are in hour '2' of the day
14             my $zone_names_for_hour_2_ref = $aatw->zone_names_for_hour(2);
15             my @zone_names_for_hour_2_ary = $aatw->zone_names_for_hour(2);
16              
17             ### Return DateTime::TimeZone objects of all time zones that are
18             ### in hour '2' of the day
19             my $zones_for_hour_2_ref = $aatw->zones_for_hour(2);
20             my @zones_for_hour_2_ary = $aatw->zones_for_hour(2);
21              
22             ### Return names of all time zones that are in hours '2' and '5'
23             ### of the day
24             my $zone_names_for_hours_2and5_ref = $aatw->zone_names_for_hours(2,5);
25             my @zone_names_for_hours_2and5_ary = $aatw->zone_names_for_hours(2,5);
26              
27             ### Return DateTime::TimeZone objets of all time zones that are in
28             ### hours '2' and '5' of the day
29             my $zones_for_hours_2and5_ref = $aatw->zones_for_hours(2,5);
30             my @zones_for_hours_2and5_ary = $aatw->zones_for_hours(2,5);
31              
32             ### Return a DateTime object for a specific time zone
33             my $dt_for_NewYork = $aatw->dt_for_zone('America/New_York');
34             my $dt_for_Paris = $aatw->dt_for_zone('Europe/Paris');
35              
36             ### Return a HASH mapping an hour in the day to an ARRAYREF
37             ### of DateTime::TimeZone objects that are part of that hour.
38             my $hour_zones_map = $aatw->hour_zones_map();
39             my $hour_zones_map = $aatw->hour_zones_map(0,4,8,12,16);
40              
41             ### Return a HASH mapping an hour in the day to an ARRAYREF
42             ### of time zone names that are part of that hour.
43             my $hour_zone_names_map = $aatw->hour_zones_map();
44             my $hour_zone_names_map = $aatw->hour_zones_map(0,4,8,12,16);
45              
46             ### Return a HASH mapping a DateTime string to an ARRAYREF
47             ### of DateTime::TimeZone objects.
48             my $dt_zones_map = $aatw->dt_zones_map();
49             my $dt_zones_map = $aatw->dt_zones_map(0,4,8,12,16);
50              
51             ### Return a HASH mapping a DateTime string to an ARRAYREF
52             ### of time zone names.
53             my $dt_zones_map = $aatw->dt_zones_map();
54             my $dt_zones_map = $aatw->dt_zones_map(0,4,8,12,16);
55              
56             ### Return a HASH mapping a zone name to it's current DateTime
57             ### objct
58             my $zone_name_dt_map = $aatw->zone_name_dt_map();
59             my $zone_name_dt_map = $aatw->zone_name_dt_map(
60             'America/New_York',
61             'Europe/Paris',
62             'Asia/Tokyo');
63              
64              
65             =head1 DESCRIPTION
66              
67             This module intends to make it easy to find what time or hour it is
68             for every time zone known to L and provide
69             easy lookup functions for that data based on a single L object.
70              
71             The inital reason for creating this module grew from a need to run
72             scheduled tasks on servers around the world from a single monitoring /
73             administration server. Some information for example, needed to be
74             collected on the 0,4,8,12,16,20 hours within that servers time zone.
75             The script on the monitoring server could be kicked off every hour,
76             calculate which time zones needed to be collected from, then collect
77             information form servres only in those time zones.
78              
79             Combining this module with L helps figure out
80             which time zones need be operated on at a specific time and schedule.
81              
82              
83             =cut
84              
85             package DateTimeX::AATW;
86 1     1   268984 use strict;
  1         3  
  1         36  
87              
88 1     1   6 use DateTime;
  1         3  
  1         21  
89 1     1   5 use DateTime::TimeZone;
  1         42  
  1         8081  
90              
91             our $VERSION = '0.04';
92              
93              
94             =head1 CONSTRUCTOR
95              
96             =over 4
97              
98             =item B
99              
100             Returns a DateTimeX::AATW object. A vaild L object must be passed.
101              
102             =back
103              
104             =cut
105              
106              
107             sub new {
108 1     1 1 453 my $class = shift;
109 1         2 my $dt = shift;
110              
111 1 50       7 die "Must pass a DateTime object." unless UNIVERSAL::isa( $dt, "DateTime" );
112              
113 1         6 my $self = {
114             '_dt' => $dt->clone,
115             };
116              
117 1         14 bless $self, $class;
118              
119 1         6 $self->_build_lookups();
120            
121 1         5 return $self;
122             }
123              
124              
125             =head1 OBJECT METHODS
126              
127             =over 4
128              
129             =cut
130              
131              
132              
133              
134              
135              
136             =item B
137              
138             Returns an ARRAY or ARRAYREF depending on context of L objects for the requests hour(s).
139             The requested hour(s) must be integers between 0 and 23.
140              
141             =over 4
142              
143             If you create a DateTimeX::AATW object with a L object based on UTC and call $aatw->zones_for_hour(2),
144             the function will return all time zones that are in the second hour of the day based on that L object.
145              
146             =back
147              
148             =cut
149              
150             sub zones_for_hour {
151 12     12 1 2024 my $self = shift;
152 12         853 my @hours;
153 12 50       29 if (ref $_[0] eq 'ARRAY') {
154 0         0 @hours = @{$_};
  0         0  
155             } else {
156 12         29 @hours = @_;
157             }
158              
159              
160 12         22 my @zones = ();
161              
162 12         22 foreach my $hour (@hours) {
163 16 100 66     76 if ($hour >= 0 && $hour <= 23) {
164 12         14 push @zones, @{$self->{_hour_zone_map}->{$hour}->{zones}};
  12         169  
165             } else {
166             #warn "Hour must be an integer from 0 to 23";
167 4         13 return undef;
168             }
169             }
170              
171 8 100       47 wantarray ? @zones : \@zones;
172              
173             }
174              
175              
176              
177             =item B
178              
179             Alias for L
180              
181             =back
182              
183             =cut
184              
185             sub zones_for_hours {
186 2     2 1 1299 my $self = shift;
187 2         6 $self->zones_for_hour(@_);
188             }
189              
190              
191              
192              
193             =item B
194              
195             Returns an ARRAY or ARRAYREF depending on context of time zone names for the requests hour(s).
196             The requested hour(s) must be integers between 0 and 23.
197              
198             =cut
199              
200             sub zone_names_for_hour {
201 6     6 1 2887 my $self = shift;
202              
203 6         7 my $zone_names = undef;
204 6         19 my $zones = $self->zones_for_hour(@_);
205              
206 6 100       22 if ($zones) {
207 4         9 $zone_names = [];
208 4         8 push @$zone_names, map {$_->name } @$zones;
  130         684  
209             } else {
210 2         6 return undef;
211             }
212              
213 4 100       87 wantarray ? @$zone_names : $zone_names;
214             }
215              
216              
217              
218             =item B
219              
220             Alias for L
221              
222             =back
223              
224             =cut
225              
226             sub zone_names_for_hours {
227 2     2 1 1508 my $self = shift;
228 2         6 $self->zone_names_for_hour(@_);
229             }
230              
231              
232              
233              
234             =item B
235              
236             Returns a HASHREF that maps an hour of the day to an ARRAYREF
237             of L objects. Hour(s) passed must be integers between 0 and 23.
238              
239             With no parameters a map of all hours between 0 and 23 will be returned.
240              
241             =cut
242              
243              
244             sub hour_zones_map {
245 5     5 1 4316 my $self = shift;
246 5         9 my @hours;
247 5 50       17 if (ref $_[0] eq 'ARRAY') {
248 0         0 @hours = @{$_};
  0         0  
249             } else {
250 5         11 @hours = @_;
251             }
252              
253 5         12 my $hour_zones_map = {};
254 5 100       14 if (@hours > 0) {
255 3         6 foreach my $hour (@hours) {
256 7 50 33     33 if ($hour >= 0 && $hour <= 23) {
257 7         39 $hour_zones_map->{$hour} = $self->{_hour_zone_map}->{$hour}->{zones};
258             } else {
259 0         0 return undef;
260             }
261             }
262             } else {
263 2         4 map {$hour_zones_map->{$_} = $self->{_hour_zone_map}->{$_}->{zones}} keys %{$self->{_hour_zone_map}};
  48         161  
  2         26  
264             }
265              
266 5         18 return $hour_zones_map;
267              
268             }
269              
270              
271              
272             =item B
273              
274             Returns a HASHREF that maps an hour of the day to an ARRAYREF
275             of time zone names. Hour(s) passed must be integers between 0 and 23.
276              
277             With no parameters a map of all hours between 0 and 23 will be returned.
278              
279             =cut
280              
281              
282             ### Got Lazy copied from hour_zone_map, look to make generic _build_map function in the future
283             sub hour_zone_names_map {
284 1     1 1 520 my $self = shift;
285 1         2 my @hours;
286 1 50       5 if (ref $_[0] eq 'ARRAY') {
287 0         0 @hours = @{$_};
  0         0  
288             } else {
289 1         4 @hours = @_;
290             }
291              
292 1         2 my $hour_zones_map = {};
293 1 50       5 if (@hours > 0) {
294 1         4 foreach my $hour (@hours) {
295 1 50 33     12 if ($hour >= 0 && $hour <= 23) {
296 1         9 $hour_zones_map->{$hour} = $self->{_hour_zone_map}->{$hour}->{zone_names};
297             } else {
298 0         0 return undef;
299             }
300             }
301             } else {
302 0         0 map {$hour_zones_map->{$_} = $self->{_hour_zone_map}->{$_}->{zone_names}} keys %{$self->{_hour_zone_map}};
  0         0  
  0         0  
303             }
304              
305 1         5 return $hour_zones_map;
306              
307             }
308              
309              
310              
311             =item B
312              
313             Returns a HASHREF that maps a L string to an ARRAYREF
314             of L objects.
315              
316             Parameters must be valid L objects
317              
318             With no parameters a map of all L strings will be returned.
319              
320             =cut
321              
322             sub dt_zones_map {
323 4     4 1 6155 my $self = shift;
324 4         9 my @datetimes;
325 4 50       14 if (ref $_[0] eq 'ARRAY') {
326 0         0 @datetimes = @{$_};
  0         0  
327             } else {
328 4         9 @datetimes = @_;
329             }
330              
331 4         8 my $dt_zones_map = {};
332 4 100       11 if (@datetimes > 0) {
333 2         4 foreach my $dt (@datetimes) {
334 2 50       11 if (UNIVERSAL::isa( $dt, "DateTime" )) {
335 2         17 $dt_zones_map->{$dt} = $self->{_time_zone_map}->{$dt}->{zones};
336             } else {
337 0         0 return undef;
338             }
339             }
340             } else {
341 2         5 map {$dt_zones_map->{$_} = $self->{_time_zone_map}->{$_}->{zones}} keys %{$self->{_time_zone_map}};
  78         251  
  2         55  
342             }
343              
344 4         130 return $dt_zones_map;
345             }
346              
347              
348             =item B
349              
350             Returns a HASHREF that maps a L string to an ARRAYREF
351             of time zone names.
352              
353             Parameters must be valid L objects
354              
355             With no parameters a map of all L strings will be returned.
356              
357             =cut
358              
359              
360             ### Got Lazy copied from dt_zone_map, look to make generic _build_map function in the future
361             sub dt_zone_names_map {
362 0     0 1 0 my $self = shift;
363 0         0 my @datetimes;
364 0 0       0 if (ref $_[0] eq 'ARRAY') {
365 0         0 @datetimes = @{$_};
  0         0  
366             } else {
367 0         0 @datetimes = @_;
368             }
369              
370 0         0 my $dt_zones_map = {};
371 0 0       0 if (@datetimes > 0) {
372 0         0 foreach my $dt (@datetimes) {
373 0 0       0 if (UNIVERSAL::isa( $dt, "DateTime::TimeZone" )) {
374 0         0 $dt_zones_map->{$dt} = $self->{_time_zone_map}->{$dt}->{zone_names};
375             } else {
376 0         0 return undef;
377             }
378             }
379             } else {
380 0         0 map {$dt_zones_map->{$_} = $self->{_time_zone_map}->{$_}->{zone_names}} keys %{$self->{_time_zone_map}};
  0         0  
  0         0  
381             }
382              
383 0         0 return $dt_zones_map;
384              
385             }
386              
387              
388             =item B
389              
390             Returns a L object.
391              
392             Parameters must be a valid L string or a valid L object.
393              
394             =cut
395              
396             sub dt_for_zone {
397 2     2 1 592 my $self = shift;
398 2         5 my $zone = shift;
399              
400 2 50       47 if (UNIVERSAL::isa( $zone, "DateTime::TimeZone" )) {
    50          
401 0         0 return $self->{_zone_time_map}->{$zone->name}->{dt};
402             } elsif (DateTime::TimeZone->is_valid_name($zone)) {
403 2         306 return $self->{_zone_time_map}->{$zone}->{dt};
404             }
405              
406 0         0 return undef;
407              
408             }
409              
410              
411             =item B
412              
413             Returns a HASHREF that maps a zone name to a L object.
414              
415             Parameters must be valid L string(s) or a valid L object(s).
416              
417             With no parameters a map of all zone names is returned.
418              
419             =cut
420              
421              
422             sub zone_name_dt_map {
423 0     0 1 0 my $self = shift;
424 0         0 my @zones;
425 0 0       0 if (ref $_[0] eq 'ARRAY') {
426 0         0 @zones = @{$_};
  0         0  
427             } else {
428 0         0 @zones = @_;
429             }
430              
431 0         0 my $zone_dt_map = {};
432 0 0       0 if (@zones > 0) {
433 0         0 foreach my $zone (@zones) {
434 0 0       0 if (UNIVERSAL::isa( $zone, "DateTime::TimeZone" )) {
    0          
435 0         0 $zone_dt_map->{$zone->name} = $self->{_zone_time_map}->{$zone->name}->{dt};
436             } elsif (DateTime::TimeZone->is_valid_name($zone)) {
437 0         0 $zone_dt_map->{$zone} = $self->{_zone_time_map}->{$zone}->{dt};
438             } else {
439 0         0 return undef;
440             }
441             }
442             } else {
443 0         0 map { $zone_dt_map->{$_} = $self->{_zone_time_map}->{$_}->{dt} } keys %{$self->{_zone_time_map}};
  0         0  
  0         0  
444             }
445              
446 0         0 return $zone_dt_map;
447             }
448              
449              
450              
451              
452             sub _build_lookups {
453 1     1   2 my $self = shift;
454              
455 1         6 my $dt = $self->{_dt}->clone;
456              
457 1         12 my $time_zone_map = {};
458 1         2 my $zone_time_map = {};
459 1         1 my $hour_zone_map = {};
460              
461 1         7 foreach my $name (DateTime::TimeZone->all_names) {
462 376         3402 $dt->set_time_zone($name);
463 376         1063277 my $new_dt = $dt->clone;
464 376         7598 my $tz = $new_dt->time_zone;
465 376         4039 my $tz_name = $tz->name;
466              
467 376         2473 $zone_time_map->{$name}->{dt} = $new_dt;
468            
469 376 100       1266 $time_zone_map->{$new_dt}->{dt} = $new_dt unless $time_zone_map->{$new_dt}->{dt};
470 376         25481 push @{$time_zone_map->{$new_dt}->{zones}}, $tz;
  376         974  
471 376         7322 push @{$time_zone_map->{$new_dt}->{zone_names}}, $tz_name;
  376         1140  
472              
473 376 100       20594 $hour_zone_map->{int($new_dt->hour)}->{dt} = $new_dt unless $hour_zone_map->{int($new_dt->hour)}->{dt};
474 376         15510 push @{$hour_zone_map->{int($new_dt->hour)}->{zones}}, $tz;
  376         1000  
475 376         2259 push @{$hour_zone_map->{int($new_dt->hour)}->{zone_names}}, $tz_name;
  376         997  
476              
477             }
478              
479 1         31 $self->{_time_zone_map} = $time_zone_map;
480 1         4 $self->{_zone_time_map} = $zone_time_map;
481 1         4 $self->{_hour_zone_map} = $hour_zone_map;
482            
483 1         14 return 1;
484             }
485              
486              
487              
488             1;
489              
490              
491             =back
492              
493              
494             =head1 AUTHOR
495              
496             Kevin C. McGrath
497             CPAN ID: KMCGRATH
498             kmcgrath@baknet.com
499              
500             =head1 COPYRIGHT
501              
502             This program is free software; you can redistribute
503             it and/or modify it under the same terms as Perl itself.
504              
505             The full text of the license can be found in the
506             LICENSE file included with this module.
507              
508              
509             =head1 SEE ALSO
510              
511             perl(1).
512              
513             =cut
514              
515             # The preceding line will help the module return a true value
516