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, 2017 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   586 use 5.010;
  1         5  
21 1     1   8 use strict;
  1         3  
  1         26  
22 1     1   8 use warnings;
  1         2  
  1         39  
23 1     1   9 use Carp;
  1         3  
  1         69  
24 1     1   8 use List::Util;
  1         4  
  1         56  
25 1     1   8 use POSIX ();
  1         2  
  1         23  
26 1     1   7 use Scalar::Util;
  1         3  
  1         48  
27 1     1   451 use Locale::TextDomain ('App-Chart');
  1         16799  
  1         8  
28              
29 1     1   9225 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::Local::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, $timet) = @_;
99             return sprintf '%04d-%02d-%02d', $self->ymd($timet);
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             # sub new {
150             # my ($class, $name, @choices) = @_;
151             # return $class->SUPER::new (name => $name,
152             # choose => \@choices,
153             # defer => 1);
154             # }
155              
156             sub validate {
157             my ($obj) = @_;
158             (Scalar::Util::blessed ($obj) && $obj->isa (__PACKAGE__))
159             or croak 'Not a '.__PACKAGE__.' object';
160             }
161              
162             #------------------------------------------------------------------------------
163              
164             {
165             my $local_TZ = $ENV{'TZ'}; # its value at startup
166             use constant::defer loco => sub {
167             my ($class) = @_;
168             return bless { name => __('Local time'),
169             tz => $local_TZ }, $class;
170             };
171             }
172              
173             use constant::defer chicago => sub {
174             return App::Chart::TZ->new (name => __('Chicago'),
175             choose => [ 'America/Chicago' ],
176             fallback => 'CST+6');
177             };
178             use constant::defer london => sub {
179             return App::Chart::TZ->new (name => __('London'),
180             choose => [ 'Europe/London' ],
181             fallback => 'GMT');
182             };
183             use constant::defer newyork => sub {
184             return App::Chart::TZ->new (name => __('New York'),
185             choose => [ 'America/New_York' ],
186             fallback => 'EST+5');
187             };
188             use constant::defer sydney => sub {
189             return App::Chart::TZ->new (name => __('Sydney'),
190             choose => [ 'Australia/Sydney' ],
191             fallback => 'EST-10');
192             };
193             use constant::defer tokyo => sub {
194             return App::Chart::TZ->new (name => __('Tokyo'),
195             choose => [ 'Asia/Tokyo' ],
196             fallback => 'JST-9');
197             };
198              
199             #------------------------------------------------------------------------------
200              
201             my @sympred_timezone_list = ();
202              
203             sub for_symbol {
204             my ($class, $symbol) = @_;
205             if ($symbol) {
206             App::Chart::symbol_setups ($symbol);
207             foreach my $elem (@sympred_timezone_list) {
208             if ($elem->[0]->match ($symbol)) {
209             return $elem->[1];
210             }
211             }
212             }
213             return $class->loco;
214             }
215              
216             sub setup_for_symbol {
217             my ($timezone, $sympred) = @_;
218             push @sympred_timezone_list, [$sympred,$timezone];
219             }
220              
221              
222             #------------------------------------------------------------------------------
223              
224             1;
225             __END__
226              
227             =for stopwords TZs
228              
229             =head1 NAME
230              
231             App::Chart::TZ -- timezone object
232              
233             =head1 SYNOPSIS
234              
235             use App::Chart::TZ;
236             my $timezone = App::Chart::TZ->new (name => 'Some Where',
237             choose => [ 'abc','def', ]);
238              
239             print $timezone->name(),"\n";
240              
241             =head1 DESCRIPTION
242              
243             A C<App::Chart::TZ> object represents a certain timezone. It has a
244             place name and is implemented as a C<TZ> environment variable setting to be
245             used, with a set of TZs to try.
246              
247             Stock and commodity symbols have an associated timezones, setup by their
248             handler code and then looked up here.
249              
250             =head1 FUNCTIONS
251              
252             =over 4
253              
254             =cut
255              
256             =item App::Chart::TZ::validate ($obj)
257              
258             Check that C<$obj> is a C<App::Chart::TZ> object, throw an error if
259             not.
260              
261             =item C<< App::Chart::TZ->loco >>
262              
263             Return a timezone object representing the local timezone (which means
264             leaving C<TZ> at its initial setting).
265              
266             =item C<< App::Chart::TZ->chicago >>
267              
268             =item C<< App::Chart::TZ->london >>
269              
270             =item C<< App::Chart::TZ->newyork >>
271              
272             =item C<< App::Chart::TZ->sydney >>
273              
274             =item C<< App::Chart::TZ->tokyo >>
275              
276             Timezone objects for these respective places.
277              
278             =back
279              
280             =head1 TIMEZONES FOR SYMBOLS
281              
282             =over 4
283              
284             =item App::Chart::TZ->for_symbol ($symbol)
285              
286             Return the timezone associated with C<$symbol>.
287              
288             =item $timezone->setup_for_symbol ($sympred)
289              
290             Record C<$timezone> as the timezone for symbols matched by the
291             C<App::Chart::Sympred> object C<$sympred>.
292              
293             =back