File Coverage

blib/lib/App/Chart/TZ.pm
Criterion Covered Total %
statement 24 26 92.3
branch n/a
condition n/a
subroutine 9 9 100.0
pod n/a
total 33 35 94.2


line stmt bran cond sub pod time code
1             # Timezone objects.
2              
3             # Copyright 2007, 2008, 2009, 2010 Kevin Ryde
4              
5             # This file is part of Chart.
6             #
7             # Chart is free software; you can redistribute it and/or modify it under the
8             # terms of the GNU General Public License as published by the Free Software
9             # Foundation; either version 3, or (at your option) any later version.
10             #
11             # Chart is distributed in the hope that it will be useful, but WITHOUT ANY
12             # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13             # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14             # details.
15             #
16             # You should have received a copy of the GNU General Public License along
17             # with Chart. If not, see <http://www.gnu.org/licenses/>.
18              
19             package App::Chart::TZ;
20 1     1   385 use 5.010;
  1         4  
21 1     1   8 use strict;
  1         2  
  1         25  
22 1     1   5 use warnings;
  1         1  
  1         25  
23 1     1   4 use Carp;
  1         1  
  1         47  
24 1     1   4 use List::Util;
  1         2  
  1         41  
25 1     1   259 use POSIX ();
  1         4397  
  1         21  
26 1     1   5 use Scalar::Util;
  1         1  
  1         33  
27 1     1   298 use Locale::TextDomain ('App-Chart');
  1         17185  
  1         9  
28              
29 1     1   5579 use App::Chart;
  0            
  0            
30             use base 'Time::TZ';
31              
32              
33              
34             #------------------------------------------------------------------------------
35             # maybe for Time::TZ ...
36              
37             sub tm_localtime {
38             my ($self, $timet) = @_;
39             require Time::localtime;
40             if (! defined $timet) { $timet = time(); }
41             local $Tie::TZ::TZ = $self->tz;
42             return Time::localtime ($timet);
43             }
44              
45             # rolling century means they're not the reverse of localtime :-(.
46             #
47             # =item C<$time_t = $tz-E<gt>timelocal ($sec,$min,$hour,$mday,$mon,$year)>
48             #
49             # =item C<$time_t = $tz-E<gt>timelocal_nocheck ($sec,$min,$hour,$mday,$mon,$year)>
50             #
51             # Call C<Time::Local::timelocal()> in the given C<$tz> timezone. C<$time_t>
52             # is a value from C<time()>, or defaults to the current C<time()>. The return
53             # is the usual list of 9 localtime values (see L<perlfunc/localtime>).
54             #
55             # my $t = $tz->timelocal (0,0,12, 1,0,99);
56             #
57             sub timelocal {
58             my $self = shift;
59             require Time::Local;
60             local $Tie::TZ::TZ = $self->tz;
61             return Time::Local::timelocal (@_);
62             }
63             sub timelocal_nocheck {
64             my $self = shift;
65             require Time::Local;
66             local $Tie::TZ::TZ = $self->tz;
67             return Time::Local::timelocal_nocheck (@_);
68             }
69              
70             # =item C<$tz-E<gt>ymd ()>
71             #
72             # Return three values C<($year, $month, $day)> which is today's date in
73             # C<$tz>. Eg.
74             #
75             # my ($year, $month, $day) = $tz->ymd;
76             #
77             sub ymd {
78             my ($self, $timet) = @_;
79             if (defined $timet) {
80             my (undef,undef,undef,$mday,$mon,$year) = $self->localtime ($timet);
81             return ($year+1900, $mon+1, $mday);
82              
83             } else {
84             # cache against current time() to perhaps save some TZ switches (which
85             # read a file every time in glibc, circa version 2.7 at least)
86             $timet = time();
87             if (! defined $self->{'ymd_now_timet'}
88             || $timet != $self->{'ymd_now_timet'}) {
89             my (undef,undef,undef,$mday,$mon,$year) = $self->localtime ($timet);
90             $self->{'ymd_now'} = [ $year+1900, $mon+1, $mday ];
91             $self->{'ymd_now_timet'} = $timet;
92             }
93             return @{$self->{'ymd_now'}};
94             }
95             }
96              
97             sub iso_date {
98             my ($self) = @_;
99             return sprintf '%04d-%02d-%02d', $self->ymd;
100             }
101             sub iso_datetimezone {
102             my ($self, $timet) = @_;
103             my ($sec,$min,$hour,$mday,$mon,$year) = $self->localtime ($timet);
104             my $zone_offset = 0; # $timet - timegm($sec,$min,$hour,$mday,$mon,$year);
105             return (sprintf ('%04d-%02d-%02dT%02d:%02d:%02dZ',
106             $year+1900, $mon+1, $mday,
107             $hour, $min, $sec,
108             int($zone_offset / 60), abs($zone_offset) % 60));
109             }
110              
111              
112             # =item $tz->iso_date_time ($timet)
113             #
114             # Return two values C<($isodate, $isotime)> which is the given time_t value
115             # (as from the C<time()> func) as an ISO date and time like C<2008-06-08> and
116             # C<10:55:00>, in C<$tz>. Eg.
117             #
118             # my ($isodate, $isotime) = $tz->iso_date_time (time());
119             #
120             sub iso_date_time {
121             my ($self, $timet) = @_;
122             my ($sec,$min,$hour,$mday,$mon,$year) = $self->localtime ($timet);
123             return (sprintf ('%04d-%02d-%02d', $year+1900, $mon+1, $mday),
124             sprintf ('%02d:%02d:%02d', $hour, $min, $sec));
125             }
126              
127             # =item C<$tm = $tz-E<gt>tm ()>
128             #
129             # =item C<$tm = $tz-E<gt>tm ($time_t)>
130             #
131             # Call C<Time::localtime::localtime()> in the given C<$tz> timezone.
132             # C<$time_t> is a value from C<time()>, or defaults to the current C<time()>.
133             # The return is a C<Time::tm> object (see L<Time::localtime>).
134             #
135             # my $tm = $tz->tm;
136             #
137             # =item C<$tz-E<gt>iso_date ()>
138             #
139             # =item C<$tz-E<gt>iso_date ($timet)>
140             #
141             # Return today's date in C<$tz> as an ISO format string like
142             # "2007-12-31".
143             #
144             # my $str = $tz->iso_date;
145              
146              
147              
148             #------------------------------------------------------------------------------
149              
150             # sub new {
151             # my ($class, $name, @choices) = @_;
152             # return $class->SUPER::new (name => $name,
153             # choose => \@choices,
154             # defer => 1);
155             # }
156              
157             sub validate {
158             my ($obj) = @_;
159             (Scalar::Util::blessed ($obj) && $obj->isa (__PACKAGE__))
160             or croak 'Not a '.__PACKAGE__.' object';
161             }
162              
163             #------------------------------------------------------------------------------
164              
165             {
166             my $local_TZ = $ENV{'TZ'}; # its value at startup
167             use constant::defer loco => sub {
168             my ($class) = @_;
169             return bless { name => __('Local time'),
170             tz => $local_TZ }, $class;
171             };
172             }
173              
174             use constant::defer chicago => sub {
175             return App::Chart::TZ->new (name => __('Chicago'),
176             choose => [ 'America/Chicago' ],
177             fallback => 'CST+6');
178             };
179             use constant::defer london => sub {
180             return App::Chart::TZ->new (name => __('London'),
181             choose => [ 'Europe/London' ],
182             fallback => 'GMT');
183             };
184             use constant::defer newyork => sub {
185             return App::Chart::TZ->new (name => __('New York'),
186             choose => [ 'America/New_York' ],
187             fallback => 'EST+5');
188             };
189             use constant::defer sydney => sub {
190             return App::Chart::TZ->new (name => __('Sydney'),
191             choose => [ 'Australia/Sydney' ],
192             fallback => 'EST-10');
193             };
194             use constant::defer tokyo => sub {
195             return App::Chart::TZ->new (name => __('Tokyo'),
196             choose => [ 'Asia/Tokyo' ],
197             fallback => 'JST-9');
198             };
199              
200             #------------------------------------------------------------------------------
201              
202             my @sympred_timezone_list = ();
203              
204             sub for_symbol {
205             my ($class, $symbol) = @_;
206             if ($symbol) {
207             App::Chart::symbol_setups ($symbol);
208             foreach my $elem (@sympred_timezone_list) {
209             if ($elem->[0]->match ($symbol)) {
210             return $elem->[1];
211             }
212             }
213             }
214             return $class->loco;
215             }
216              
217             sub setup_for_symbol {
218             my ($timezone, $sympred) = @_;
219             push @sympred_timezone_list, [$sympred,$timezone];
220             }
221              
222              
223             #------------------------------------------------------------------------------
224              
225             1;
226             __END__
227              
228             =for stopwords TZs
229              
230             =head1 NAME
231              
232             App::Chart::TZ -- timezone object
233              
234             =head1 SYNOPSIS
235              
236             use App::Chart::TZ;
237             my $timezone = App::Chart::TZ->new (name => 'Some Where',
238             choose => [ 'abc','def', ]);
239              
240             print $timezone->name(),"\n";
241              
242             =head1 DESCRIPTION
243              
244             A C<App::Chart::TZ> object represents a certain timezone. It has a
245             place name and is implemented as a C<TZ> environment variable setting to be
246             used, with a set of TZs to try.
247              
248             Stock and commodity symbols have an associated timezones, setup by their
249             handler code and then looked up here.
250              
251             =head1 FUNCTIONS
252              
253             =over 4
254              
255             =cut
256              
257             =item App::Chart::TZ::validate ($obj)
258              
259             Check that C<$obj> is a C<App::Chart::TZ> object, throw an error if
260             not.
261              
262             =item C<< App::Chart::TZ->loco >>
263              
264             Return a timezone object representing the local timezone (which means
265             leaving C<TZ> at its initial setting).
266              
267             =item C<< App::Chart::TZ->chicago >>
268              
269             =item C<< App::Chart::TZ->london >>
270              
271             =item C<< App::Chart::TZ->newyork >>
272              
273             =item C<< App::Chart::TZ->sydney >>
274              
275             =item C<< App::Chart::TZ->tokyo >>
276              
277             Timezone objects for these respective places.
278              
279             =back
280              
281             =head1 TIMEZONES FOR SYMBOLS
282              
283             =over 4
284              
285             =item App::Chart::TZ->for_symbol ($symbol)
286              
287             Return the timezone associated with C<$symbol>.
288              
289             =item $timezone->setup_for_symbol ($sympred)
290              
291             Record C<$timezone> as the timezone for symbols matched by the
292             C<App::Chart::Sympred> object C<$sympred>.
293              
294             =back