File Coverage

blib/lib/Astro/App/Satpass2/FormatTime/DateTime.pm
Criterion Covered Total %
statement 18 20 90.0
branch n/a
condition n/a
subroutine 7 7 100.0
pod n/a
total 25 27 92.5


line stmt bran cond sub pod time code
1             package Astro::App::Satpass2::FormatTime::DateTime;
2              
3 20     20   10115 use 5.008;
  20         80  
4              
5 20     20   124 use strict;
  20         48  
  20         466  
6 20     20   122 use warnings;
  20         44  
  20         699  
7              
8 20         241 use parent qw{
9             Astro::App::Satpass2::FormatTime
10 20     20   166 };
  20         52  
11              
12 20         2587 use Astro::App::Satpass2::Utils qw{
13             back_end __back_end_class_name_of_record
14             has_method load_package
15             __parse_class_and_args
16             @CARP_NOT
17 20     20   1553 };
  20         70  
18 20     20   152 use Astro::App::Satpass2::Locale qw{ __preferred };
  20         61  
  20         1086  
19 20     20   3826 use DateTime;
  0            
  0            
20             use DateTime::TimeZone;
21              
22             our $VERSION = '0.051_01';
23              
24             sub attribute_names {
25             my ( $self ) = @_;
26             return ( qw{ back_end }, $self->SUPER::attribute_names() );
27             }
28              
29             sub _dt_class_and_args {
30             my ( $self ) = @_;
31             if ( $self->{_back_end} ) {
32             return (
33             $self->{_back_end}{class},
34             $self->{_back_end}{arg},
35             );
36             } else {
37             return ( 'DateTime', [] );
38             }
39             }
40              
41             sub class_name_of_record {
42             my ( $self ) = @_;
43             return $self->__back_end_class_name_of_record(
44             $self->SUPER::class_name_of_record() );
45             }
46              
47             sub format_datetime {
48             my ( $self, $tplt, $time, $gmt ) = @_;
49             $time = $self->__round_time_value( $time );
50             if ( has_method( $time, $self->METHOD_USED() ) ) {
51             return $self->__format_datetime( $time, $tplt );
52             } else {
53             ref $time
54             and $self->wail( 'Unsupported time specification' );
55             my ( $class, $dt_arg ) = $self->_dt_class_and_args();
56             my $dt = $class->from_epoch(
57             epoch => $time,
58             time_zone => $self->_get_zone( $gmt ),
59             locale => scalar __preferred(),
60             @{ $dt_arg },
61             );
62             return $self->__format_datetime( $dt, $tplt );
63             }
64             }
65              
66             sub init {
67             my ( $self, %arg ) = @_;
68             exists $arg{back_end}
69             or $arg{back_end} = undef;
70             return $self->SUPER::init( %arg );
71             }
72              
73             {
74              
75             my $zone_gmt;
76             my $zone_local;
77              
78             sub tz {
79             my ( $self, @args ) = @_;
80              
81             if ( @args ) {
82             my $zone = $args[0];
83             if ( defined $zone and $zone ne '' ) {
84             if ( ! DateTime::TimeZone->is_valid_name( $zone ) ) {
85             my $zed = uc $zone;
86             DateTime::TimeZone->is_valid_name( $zed )
87             or $self->wail(
88             "'$zone' is not a valid time zone name" );
89             $zone = $zed;
90             }
91             $self->{_tz_obj} = DateTime::TimeZone->new(
92             name => $zone );
93             } else {
94             $self->{_tz_obj} = $zone_local ||=
95             DateTime::TimeZone->new( name => 'local' );
96             }
97             return $self->SUPER::tz( $zone );
98              
99             } else {
100             return $self->SUPER::tz();
101             }
102             }
103              
104             sub _get_zone {
105             my ( $self, $gmt ) = @_;
106             defined $gmt
107             or $gmt = $self->gmt();
108              
109             $gmt and return ( $zone_gmt ||= DateTime::TimeZone->new(
110             name => 'UTC' ) );
111              
112             $self->{_tz_obj} and return $self->{_tz_obj};
113              
114             my $tz = $self->tz();
115             if ( defined $tz && $tz ne '' ) {
116             return ( $self->{_tz_obj} = DateTime::TimeZone->new(
117             name => $tz ) );
118             } else {
119             return ( $self->{_tz_obj} = $zone_local ||=
120             DateTime::TimeZone->new( name => 'local' ) );
121             }
122              
123             }
124              
125             }
126              
127             sub __format_datetime_width_adjust_object {
128             my ( $self, $obj, $name, $val, $gmt ) = @_;
129              
130             if ( $obj ) {
131             $obj->set( $name => $val );
132             } else {
133             my ( $class, $dt_arg ) = $self->_dt_class_and_args();
134             $obj = $class->new(
135             time_zone => $self->_get_zone( $gmt ),
136             locale => scalar __preferred(),
137             $name => $val,
138             ( 'year' eq $name ? () : ( year => 2020 ) ),
139             @{ $dt_arg },
140             );
141             }
142              
143             return $obj;
144             }
145              
146             # my $mod_fmt = $self->__preprocess_strftime_format( $dt_obj, $fmt )
147             # Preprocess out all the extensions to the strftime format.
148             # What we're handling here is things of the form %{name:modifiers},
149             # where the colon and modifiers are optional.
150             # The modifier is a series of single-character flags followed by a field
151             # width. The flags are:
152             # '-' - left-justify
153             # '0' - zero-pad (ineffective if '-' specified)
154             # 't' - truncate to field width
155             sub __preprocess_strftime_format {
156             my ( $self, $dt_obj, $fmt ) = @_;
157             caller->isa( __PACKAGE__ )
158             or $self->weep(
159             '__preprocess_strftime_format() is private to Astro-App-Satpass2' );
160             $fmt =~ s< ( % [{] ( \w+ | % ) (?: : ( [-0t]* ) ( [0-9]+ ) )? [}] ) >
161             < _expand_strftime_format( $dt_obj, $1, $2, $3, $4 ) >smxge;
162             return $fmt;
163             }
164              
165             use constant CALENDAR_GREGORIAN => 'Gregorian';
166             use constant CALENDAR_JULIAN => 'Julian';
167              
168             {
169             my %special = (
170             '%' => sub { return '%' },
171             calendar_name => sub {
172             my ( $dt_obj ) = @_;
173             my $code;
174             $code = $dt_obj->can( 'calendar_name' )
175             and return $code->( $dt_obj );
176             $code = $dt_obj->can( 'is_julian' )
177             and return $code->( $dt_obj ) ?
178             CALENDAR_JULIAN :
179             CALENDAR_GREGORIAN;
180             ( ref $dt_obj ) =~ m/ \A DateTime:: (?: \w+ :: )* ( \w+ ) \z /smx
181             and return "$1";
182             return CALENDAR_GREGORIAN;
183             },
184             );
185              
186             sub _expand_strftime_format {
187             my ( $dt_obj, $all, $name, $flags, $width ) = @_;
188             my $code = $special{$name} || $dt_obj->can( $name )
189             or return $all;
190             my $rslt = $code->( $dt_obj );
191             my %flg = map { $_ => 1 } split qr{}, defined $flags ? $flags : '';
192             if ( $width ) {
193             my $tplt = '%';
194             foreach my $f ( qw{ - 0 } ) {
195             $flg{$f}
196             and $tplt .= $f;
197             }
198             $tplt .= '*s';
199             $rslt = sprintf $tplt, $width, $rslt;
200             $flg{t}
201             and length $rslt > $width
202             and substr $rslt, $width, length $rslt, '';
203             }
204             return $rslt;
205             }
206             }
207              
208             sub __back_end_default {
209             my ( undef, $cls ) = @_; # Invocant ($self) unused
210             return defined $cls ? $cls : 'DateTime';
211             }
212              
213             sub __back_end_validate {
214             my ( undef, $cls, @arg ) = @_; # Invocant ($self) unused
215             $cls->now( @arg );
216             return;
217             }
218              
219             1;
220              
221             __END__