File Coverage

blib/lib/DBR/Config/Trans/UnixTime.pm
Criterion Covered Total %
statement 66 129 51.1
branch 13 50 26.0
condition 1 6 16.6
subroutine 19 29 65.5
pod 0 4 0.0
total 99 218 45.4


line stmt bran cond sub pod time code
1             # the contents of this file are Copyright (c) 2009-2011 Daniel Norman
2             # This program is free software; you can redistribute it and/or
3             # modify it under the terms of the GNU General Public License as
4             # published by the Free Software Foundation.
5              
6             package DBR::Config::Trans::UnixTime;
7              
8 18     18   110 use strict;
  18         44  
  18         702  
9 18     18   351 use base 'DBR::Config::Trans';
  18         37  
  18         2166  
10 18     18   103 use strict;
  18         36  
  18         585  
11             #use Date::Parse ();
12 18     18   22892 use Time::ParseDate ();
  18         407225  
  18         627  
13 18     18   38474 use POSIX qw(strftime tzset);
  18         199936  
  18         160  
14              
15 0     0 0 0 sub new { die "Should not get here" }
16              
17             sub init {
18 22     22 0 57 my $self = shift;
19 22 50       309 $self->{tzref} = $self->{session}->timezone_ref or return $self->_error('failed to get timezone ref');
20 22         82 return 1;
21             }
22              
23             sub forward{
24 14     14 0 38 my $self = shift;
25 14         31 my $unixtime = shift;
26 14         132 return bless( [$unixtime,$self->{tzref}] , 'DBR::_UXTIME');
27             }
28              
29             sub backward{
30 13     13 0 39 my $self = shift;
31 13         27 my $value = shift;
32              
33 13 50 33     117 return undef unless defined($value) && length($value);
34              
35 13 50       121 if(ref($value) eq 'DBR::_UXTIME'){ #ahh... I know what this is
    50          
36 0         0 return $value->unixtime;
37              
38             }elsif($value =~ /^\d+$/){ # smells like a unixtime
39 0         0 return $value;
40              
41             }else{
42 13         24 local($ENV{TZ}) = ${$self->{tzref}}; tzset(); # Date::Parse doesn't accept timezone in the way we want to specify it. Lame.
  13         199  
  13         10687  
43              
44             # Ok... so Date::Parse is kinda cool and all, except for the fact that it breaks horribly on
45             # Non DST-specific timezone prefixes, like PT, MT, CT, ET. Treats them all like GMT.
46             # Even strptime freaks out on it. What gives Graham?
47             # P.S. glass house here throwing stones, but try adding a comment or two.
48              
49             #my $uxtime = Date::Parse::str2time($value);
50 13         111 my $uxtime = Time::ParseDate::parsedate($value);
51              
52 13 50       9008 unless($uxtime){
53 0         0 $self->_error("Invalid time '$value'");
54 0         0 return ();
55             }
56              
57 13         103 return $uxtime;
58             }
59              
60             }
61              
62             package DBR::_UXTIME;
63              
64 18     18   50221 use strict;
  18         51  
  18         1480  
65 18     18   133 use POSIX qw(strftime tzset);
  18         45  
  18         104  
66 18     18   1500 use Carp;
  18         41  
  18         4358  
67             use overload
68             #values
69 14     14   5560 '""' => sub { $_[0]->datetime },
70 54     54   19430 '0+' => sub { $_[0]->unixtime },
71              
72             #operators
73 6 50   6   2522 '+' => sub { $_[0]->_manip( $_[1], 'add' ) || croak "Invalid date manipulation '$_[1]'" },
74 0 0   0   0 '-' => sub { $_[0]->_manip( $_[1], 'subtract' ) || croak "Invalid date manipulation '$_[1]'" },
75              
76             # Some ideas:
77             #
78              
79 18         657 'fallback' => 1,
80             #'nomethod' => sub {croak "UnixTime object: Invalid operation '$_[3]' The ways in which you can use UnixTime objects is restricted"}
81 18     18   142 ;
  18         63  
82              
83             *TO_JSON = \&datetime;
84              
85 66 50   66   5926 sub unixtime { $_[0][0] || '' };
86              
87             # Using $ENV{TZ} and the posix functions is ugly... and about 60x faster than the alternative in benchmarks
88              
89             sub date {
90 0 0   0   0 return '' unless defined($_[0][0]);
91 0         0 local($ENV{TZ}) = ${$_[0][1]}; tzset();
  0         0  
  0         0  
92 0         0 return strftime ("%D", localtime($_[0][0]));
93             }
94              
95             sub time {
96 0 0   0   0 return '' unless defined($_[0][0]);
97 0         0 local($ENV{TZ}) = ${$_[0][1]}; tzset();
  0         0  
  0         0  
98 0         0 return strftime ("%H:%M:%S %Z", localtime($_[0][0]));
99             }
100              
101             sub datetime {
102 14 50   14   54 return '' unless defined($_[0][0]);
103 14         19 local($ENV{TZ}) = ${$_[0][1]}; tzset();
  14         223  
  14         1235  
104 14         503 return strftime ("%D %H:%M:%S %Z", localtime($_[0][0]));
105             }
106              
107             sub fancytime {
108 0 0   0   0 return '' unless defined($_[0][0]);
109 0         0 local($ENV{TZ}) = ${$_[0][1]}; tzset();
  0         0  
  0         0  
110 0         0 return strftime ("%I:%M:%S %p %Z", localtime($_[0][0]));
111             }
112              
113             sub fancydatetime {
114 0 0   0   0 return '' unless defined($_[0][0]);
115 0         0 local($ENV{TZ}) = ${$_[0][1]}; tzset();
  0         0  
  0         0  
116 0         0 my $v = strftime ("%A %B %e %l:%M%p %Y", localtime($_[0][0]));
117 0         0 $v =~ s/\s+/ /g;
118 0         0 $v =~ s/(AM|PM)/lc($1)/e;
  0         0  
119 0         0 return $v;
120             }
121              
122             sub fancydate {
123 0 0   0   0 return '' unless defined($_[0][0]);
124 0         0 local($ENV{TZ}) = ${$_[0][1]}; tzset();
  0         0  
  0         0  
125 0         0 return strftime ("%A %B %e, %Y", localtime($_[0][0]));
126             }
127              
128             #format takes a strftime format string as an argument
129             sub format {
130 0 0 0 0   0 return '' unless defined($_[0][0]) && length($_[1]);
131 0         0 local($ENV{TZ}) = ${$_[0][1]}; tzset();
  0         0  
  0         0  
132 0         0 return strftime ($_[1], localtime($_[0][0]));
133             }
134              
135             sub midnight{
136 0     0   0 my $self = shift;
137              
138 0 0       0 return '' unless defined($self->[0]);
139 0         0 local($ENV{TZ}) = ${$self->[1]}; tzset();
  0         0  
  0         0  
140 0         0 my ($sec,$min,$hour) = localtime($self->[0]);
141              
142 0         0 my $midnight = $self->[0] - ($sec + ($min * 60) + ($hour * 3600) ); # rewind!
143 0         0 return $self->new($midnight);
144              
145             }
146              
147             sub endofday{
148 0     0   0 my $self = shift;
149              
150 0 0       0 return '' unless defined($self->[0]);
151              
152 0         0 local($ENV{TZ}) = ${$self->[1]}; tzset();
  0         0  
  0         0  
153 0         0 my ($sec,$min,$hour) = localtime($self->[0]);
154              
155 0         0 my $endofday = $self->[0] + 86399 - ($sec + ($min * 60) + ($hour * 3600) ) ; # rewind!
156 0         0 return $self->new($endofday);
157             }
158              
159             sub _manip{
160 6     6   14 my $self = shift;
161 6         14 my $manip = shift;
162 6         14 my $mode = shift;
163              
164 6         38 $manip =~ s/^\s+|\s+$//g;
165 6 50       20 return undef unless $manip;
166              
167 6         50 my ($number, $unit) = $manip =~ /^(\d+)\s+([A-Za-z]+?)s?$/;
168 6         21 $unit = lc($unit);
169              
170 6         29 my $unixtime = $self->unixtime;
171              
172             # This isn't actually the correct way to do this, on account of DST nd leap year and so on,
173             # just a proof of concept. Should probably just farm it out to Date::Manip
174              
175 6         10 my $diff;
176 6 50       40 if($unit eq 'second'){
    50          
    50          
    0          
    0          
177 0         0 $diff = $number
178             }elsif($unit eq 'minute'){
179 0         0 $diff = $number * 60;
180             }elsif($unit eq 'hour'){
181 6         21 $diff = $number * 3600;
182             }elsif($unit eq 'day'){
183 0         0 $diff = $number * 86400;
184             }elsif($unit eq 'year'){
185 0         0 $diff = $number * 31536000;
186             }else{
187 0         0 return undef;
188             }
189              
190 6 50       20 if ($mode eq 'add'){
    0          
191 6         30 return $self->new( $unixtime + $diff );
192             }elsif($mode eq 'subtract'){
193 0         0 return $self->new( $unixtime - $diff );
194             }
195              
196 0         0 return undef;
197              
198             }
199              
200             # uxtime , tzref
201 6     6   55 sub new{ bless([ $_[1], $_[0][1] ],'DBR::_UXTIME') }
202              
203             1;