File Coverage

blib/lib/DateTime/Format/RFC3339.pm
Criterion Covered Total %
statement 55 57 96.4
branch 16 26 61.5
condition 2 6 33.3
subroutine 11 11 100.0
pod 2 3 66.6
total 86 103 83.5


line stmt bran cond sub pod time code
1              
2             package DateTime::Format::RFC3339;
3              
4 3     3   350458 use strict;
  3         7  
  3         76  
5 3     3   15 use warnings;
  3         6  
  3         80  
6              
7 3     3   2107 use version; our $VERSION = qv('v1.2.0');
  3         6194  
  3         18  
8              
9 3     3   253 use Carp qw( croak );
  3         5  
  3         181  
10 3     3   1317 use DateTime qw( );
  3         168905  
  3         73  
11              
12              
13 3     3   19 use constant FIRST_IDX => 0;
  3         7  
  3         209  
14 3     3   15 use constant IDX_UC_ONLY => FIRST_IDX + 0;
  3         6  
  3         144  
15 3     3   15 use constant NEXT_IDX => FIRST_IDX + 1;
  3         6  
  3         2016  
16              
17              
18             sub new {
19 2     2 0 5 my ($class, %opts) = @_;
20              
21 2         4 my $uc_only = delete( $opts{uc_only} );
22              
23 2         8 return bless([
24             $uc_only, # IDX_UC_ONLY
25             ], $class);
26             }
27              
28              
29             sub parse_datetime {
30 2     2 1 2097 my ($self, $str) = @_;
31              
32 2 50       10 $self = $self->new()
33             if !ref($self);
34              
35 2 50       13 $str = uc($str)
36             if !$self->[IDX_UC_ONLY];
37              
38 2 50 33     29 my ($Y,$M,$D) = $str =~ s/^(\d{4})-(\d{2})-(\d{2})// && (0+$1,0+$2,0+$3)
39             or croak("Incorrectly formatted date");
40              
41 2 50       10 $str =~ s/^T//
42             or croak("Incorrectly formatted datetime");
43              
44 2 50 33     17 my ($h,$m,$s) = $str =~ s/^(\d{2}):(\d{2}):(\d{2})// && (0+$1,0+$2,0+$3)
45             or croak("Incorrectly formatted time");
46              
47 2 100       10 my $ns = $str =~ s/^\.(\d{1,9})\d*// ? 0+substr($1.('0'x8),0,9) : 0;
48              
49 2         5 my $tz;
50 2 50       7 if ( $str =~ s/^Z// ) { $tz = 'UTC'; }
  2 0       4  
51 0         0 elsif ( $str =~ s/^([+-])(\d{2}):(\d{2})// ) { $tz = "$1$2$3"; }
52 0         0 else { croak("Missing time zone"); }
53              
54 2 50       7 $str =~ /^\z/ or croak("Incorrectly formatted datetime");
55              
56 2         10 return DateTime->new(
57             year => $Y,
58             month => $M,
59             day => $D,
60             hour => $h,
61             minute => $m,
62             second => $s,
63             nanosecond => $ns,
64             time_zone => $tz,
65             formatter => $self,
66             );
67             }
68              
69              
70             sub format_datetime {
71 5     5 1 3139 my ($self, $dt) = @_;
72              
73 5         9 my $tz;
74 5 100       19 if ($dt->time_zone()->is_utc()) {
75 1         17 $tz = 'Z';
76             } else {
77 4         57 my $secs = $dt->offset();
78 4 100       416 my $sign = $secs < 0 ? '-' : '+'; $secs = abs($secs);
  4         6  
79 4         9 my $mins = int($secs / 60); $secs %= 60;
  4         6  
80 4         7 my $hours = int($mins / 60); $mins %= 60;
  4         4  
81 4 100       12 if ($secs) {
82 1         6 ( $dt = $dt->clone() )
83             ->set_time_zone('UTC');
84 1         269 $tz = 'Z';
85             } else {
86 3         15 $tz = sprintf('%s%02d:%02d', $sign, $hours, $mins);
87             }
88             }
89              
90             return
91 5 50       20 $dt->strftime(
92             ($dt->nanosecond()
93             ? '%Y-%m-%dT%H:%M:%S.%9N'
94             : '%Y-%m-%dT%H:%M:%S'
95             )
96             ).$tz;
97             }
98              
99              
100             1;
101              
102              
103             __END__