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