File Coverage

blib/lib/Time/Moment/Role/TimeZone.pm
Criterion Covered Total %
statement 34 35 97.1
branch 6 12 50.0
condition 2 8 25.0
subroutine 7 7 100.0
pod 4 4 100.0
total 53 66 80.3


line stmt bran cond sub pod time code
1             package Time::Moment::Role::TimeZone;
2              
3 2     2   942 use Role::Tiny;
  2         4  
  2         11  
4 2     2   257 use Carp ();
  2         3  
  2         22  
5 2     2   1026 use Time::Local ();
  2         3511  
  2         630  
6              
7             our $VERSION = '0.003';
8              
9             requires qw(epoch offset with_offset_same_instant with_offset_same_local
10             utc_rd_as_seconds utc_rd_values local_rd_as_seconds local_rd_values utc_year);
11              
12             sub with_time_zone_offset_same_instant {
13 2     2 1 1837 my ($self, $tz) = @_;
14 2 50 33     15 Carp::croak "Invalid time zone object $tz" unless defined $tz and $tz->can('offset_for_datetime');
15 2         6 return $self->with_offset_same_instant($tz->offset_for_datetime($self) / 60);
16             }
17              
18             sub with_time_zone_offset_same_local {
19 2     2 1 2770 my ($self, $tz) = @_;
20 2 50 33     12 Carp::croak "Invalid time zone object $tz" unless defined $tz and $tz->can('offset_for_local_datetime');
21 2         4 my ($offset, $error);
22 2         3 { local $@;
  2         4  
23 2 50       3 unless (eval { $offset = $tz->offset_for_local_datetime($self); 1 }) {
  2         4  
  2         8  
24 0   0     0 $error = $@ || 'Error';
25             }
26             }
27 2 50       4 Carp::croak $error if defined $error;
28 2         16 return $self->with_offset_same_local($offset / 60);
29             }
30              
31             sub with_system_offset_same_instant {
32 1     1 1 594 my ($self) = @_;
33 1         5 my $time = $self->epoch;
34 1         12 my @localtime = localtime $time;
35 1 50       5 $localtime[5] += 1900 if $localtime[5] >= 0; # avoid timegm year heuristic
36 1         4 my $offset = Time::Local::timegm_nocheck(@localtime) - $time;
37 1         31 return $self->with_offset_same_instant($offset / 60);
38             }
39              
40             sub with_system_offset_same_local {
41 1     1 1 1164 my ($self) = @_;
42 1         8 my $time = $self->epoch + $self->offset * 60;
43 1         5 my @gmtime = gmtime $time;
44 1 50       3 $gmtime[5] += 1900 if $gmtime[5] >= 0; # avoid timelocal year heuristic
45 1         5 my $offset = $time - Time::Local::timelocal_nocheck(@gmtime);
46 1         52 return $self->with_offset_same_local($offset / 60);
47             }
48              
49             1;
50              
51             =head1 NAME
52              
53             Time::Moment::Role::TimeZone - Adjust Time::Moment with time zone objects
54              
55             =head1 SYNOPSIS
56              
57             use Time::Moment;
58             use Role::Tiny ();
59             use DateTime::TimeZone;
60              
61             my $class = Role::Tiny->create_class_with_roles('Time::Moment', 'Time::Moment::Role::TimeZone');
62              
63             my $tz = DateTime::TimeZone->new(name => 'America/New_York');
64             my $tm = $class->from_epoch(1000212360)->with_time_zone_offset_same_instant($tz);
65              
66             use DateTime::TimeZone::Olson 'olson_tz';
67              
68             my $tz = olson_tz('Europe/Oslo');
69             my $tm = Time::Moment->new(year => 2012, month => 3, day => 4, hour => 13, minute => 7, second => 42);
70             Role::Tiny->apply_roles_to_object($tm, 'Time::Moment::Role::TimeZone');
71             $tm = $tm->with_time_zone_offset_same_local($tz);
72              
73             my $tm = $class->from_epoch(1522095272)->with_system_offset_same_instant;
74              
75             my $tm = $class->new_from_string('2009-05-02T12:15:30Z')->with_system_offset_same_local;
76              
77             =head1 DESCRIPTION
78              
79             This role provides convenience methods to return a new L object
80             adjusted according to a L/
81             L<::Tzfile|DateTime::TimeZone::Tzfile>-compatible time zone object, as in
82             L. See L regarding usage with date math.
83              
84             =head1 METHODS
85              
86             =head2 with_time_zone_offset_same_instant
87              
88             my $same_instant = $tm->with_time_zone_offset_same_instant($tz);
89              
90             Returns a L of the same instant, but at an offset from UTC
91             according to the given time zone object at that instant.
92              
93             =head2 with_time_zone_offset_same_local
94              
95             my $same_local = $tm->with_time_zone_offset_same_local($tz);
96              
97             Returns a L of the same local time, with an offset from UTC
98             according to the given time zone object at that local time.
99              
100             If the local time of the L object is ambiguous in the given time
101             zone (such as when Daylight Savings Time ends), the time zone object will
102             usually use the earliest time. If the local time does not exist (such as when
103             Daylight Savings Time starts), the time zone object will usually throw an
104             exception.
105              
106             =head2 with_system_offset_same_instant
107              
108             my $same_instant = $tm->with_system_offset_same_instant;
109              
110             As in L, but using the system local time
111             zone via L.
112              
113             =head2 with_system_offset_same_local
114              
115             my $same_local = $tm->with_system_offset_same_local;
116              
117             As in L, but using the system local time
118             zone via L.
119              
120             If the local time of the L object is ambiguous in the system
121             local time zone (such as when Daylight Savings Time ends), L will
122             use the earliest time. If the local time does not exist (such as when Daylight
123             Savings Time starts), L will use the time one hour later.
124              
125             =head1 CAVEATS
126              
127             L does not store a time zone; these methods only set the offset
128             and local time for the instantaneous moment represented by the object. After
129             doing date math with the object, new times may need to be corrected, based on
130             whether the date math was intended to be done relative to the absolute or local
131             time.
132              
133             my $tm = $class->now_utc->with_time_zone_offset_same_instant($tz); # now in $tz
134             my $next_day = $tm->plus_days(1)->with_time_zone_offset_same_local($tz); # 1 day from now in $tz
135             my $24h_later = $tm->plus_days(1)->with_time_zone_offset_same_instant($tz); # 24 hours from now in $tz
136              
137             my $tm = $class->now; # now in system local time
138             my $next_day = $tm->plus_days(1)->with_system_offset_same_local; # 1 day from now in system local time
139             my $24h_later = $tm->plus_days(1)->with_system_offset_same_instant; # 24 hours from now in system local time
140              
141             Note that L may throw an exception here if
142             the new local time does not exist in that time zone (e.g. between 2 and 3 AM at
143             the start of Daylight Savings Time).
144              
145             =head1 BUGS
146              
147             Report any issues on the public bugtracker.
148              
149             =head1 AUTHOR
150              
151             Dan Book
152              
153             =head1 CONTRIBUTORS
154              
155             =over
156              
157             =item Christian Hansen (chansen)
158              
159             =back
160              
161             =head1 COPYRIGHT AND LICENSE
162              
163             This software is Copyright (c) 2018 by Dan Book.
164              
165             This is free software, licensed under:
166              
167             The Artistic License 2.0 (GPL Compatible)
168              
169             =head1 SEE ALSO
170              
171             L, L, L