File Coverage

lib/App/MtAws/DateTime.pm
Criterion Covered Total %
statement 42 61 68.8
branch 8 20 40.0
condition 6 26 23.0
subroutine 12 14 85.7
pod 0 4 0.0
total 68 125 54.4


line stmt bran cond sub pod time code
1             # mt-aws-glacier - Amazon Glacier sync client
2             # Copyright (C) 2012-2014 Victor Efimov
3             # http://mt-aws.com (also http://vs-dev.com) vs@vs-dev.com
4             # License: GPLv3
5             #
6             # This file is part of "mt-aws-glacier"
7             #
8             # mt-aws-glacier is free software: you can redistribute it and/or modify
9             # it under the terms of the GNU General Public License as published by
10             # the Free Software Foundation, either version 3 of the License, or
11             # (at your option) any later version.
12             #
13             # mt-aws-glacier is distributed in the hope that it will be useful,
14             # but WITHOUT ANY WARRANTY; without even the implied warranty of
15             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16             # GNU General Public License for more details.
17             #
18             # You should have received a copy of the GNU General Public License
19             # along with this program. If not, see <http://www.gnu.org/licenses/>.
20              
21             package App::MtAws::DateTime;
22              
23             our $VERSION = '1.114_2';
24              
25 25     25   19625 use strict;
  25         32  
  25         722  
26 25     25   98 use warnings;
  25         39  
  25         716  
27 25     25   98 use utf8;
  25         32  
  25         134  
28              
29 25     25   919 use POSIX;
  25         5338  
  25         161  
30 25     25   34643 use Time::Local;
  25         35  
  25         1011  
31 25     25   113 use App::MtAws::Utils;
  25         20  
  25         4001  
32              
33 25     25   94 use Exporter 'import';
  25         31  
  25         1224  
34              
35             our @EXPORT = qw/epoch_to_iso8601 iso8601_to_epoch/;
36              
37             #
38             # Implementing this as I don't want to have non-core dependencies
39             #
40              
41 25     25   171 use constant SEC_PER_DAY => 86400;
  25         28  
  25         1801  
42 25     25   140 use constant YEARS_PER_CENTURY => 100;
  25         28  
  25         968  
43 25     25   92 use constant DAYS_PER_YEAR => 365;
  25         29  
  25         13194  
44              
45             sub is_leap
46             {
47 0 0 0 0 0 0 ($_[0] % 400 ==0) || ( ($_[0] % 100 != 0) && ($_[0] % 4 == 0) )
48             }
49              
50             our %_leap_cache;
51              
52             sub number_of_leap_years
53             {
54 0     0 0 0 my ($y1, $y2, $m) = @_;
55 0 0 0     0 $_leap_cache{$y1,$y2, ($m < 3 ? '0' : '1') } ||= do {
56 0         0 my $cnt = 0;
57 0         0 for ($y1+1..$y2-1) {
58 0 0       0 $cnt++ if is_leap($_);
59             }
60 0 0 0     0 $cnt++ if ($m < 3 ) && is_leap($y1);
61 0 0 0     0 $cnt++ if ($m >= 3) && is_leap($y2);
62 0         0 $cnt;
63             }
64             }
65              
66             # allowed range Y1000 - Y9999
67             # should work with Y2038 dates if underlying OS supports 64bit time (otherwise we don't need such conversion in
68             # mt-aws-glacier)
69             sub epoch_to_iso8601
70             {
71 24157     24157 0 74003 my ($time) = @_;
72 24157 100 100     88778 return if $time < -30610224000 || $time > 253402300799;
73 24155         1308893 strftime("%Y%m%dT%H%M%SZ", gmtime($time));
74             }
75              
76             our %_year_month_shift;
77              
78             # allowed range Y1000 - Y9999
79             # should work with Y2038 dates always
80             sub iso8601_to_epoch
81             {
82 26255     26255 0 386469 my ($str) = @_;
83             # only _some_ iso8601 format support for now
84 26255         40967 utf8::downgrade($str); # ascii regexps below
85 26255 100       178982 my ($year, $month, $day, $hour, $min, $sec) =
86             $str =~ /^\s*(\d{4})[\-\s]*(\d{2})[\-\s]*(\d{2})\s*T\s*(\d{2})[\:\s]*(\d{2})[\:\s]*(\d{2})[\,\.\d]{0,10}\s*Z\s*$/i or
87             return;
88 26250 100       65982 return if $year < 1000;
89 26249         25970 my ($leap, $delta) = (0, 0);
90 26249 100 66     94124 $leap = $sec - 59, $sec = 59 if ($sec == 60 || $sec == 61);
91              
92             # some Y2038 bugs in timegm, workaround it. we need consistency across platforms and perl versions when parsing vault metadata
93 26249 0 0     55597 if (!is_y2038_supported && (($year <= 1901) || ($year >= 2038)) ) {
      33        
94 0   0     0 ($year, $delta) = @{ $_year_month_shift{$year,$month} ||= [ do {
  0         0  
95 0         0 my ($d, $y) = (0, $year);
96 0         0 while ($y <= 1901) {
97 0         0 $d -= number_of_leap_years($y, $y + YEARS_PER_CENTURY, $month)*SEC_PER_DAY + YEARS_PER_CENTURY*SEC_PER_DAY*DAYS_PER_YEAR;
98 0         0 $y += YEARS_PER_CENTURY;
99             }
100 0         0 while ($y >= 2038) {
101 0         0 $d += number_of_leap_years($y - YEARS_PER_CENTURY, $y, $month)*SEC_PER_DAY + YEARS_PER_CENTURY*SEC_PER_DAY*DAYS_PER_YEAR;
102 0         0 $y -= YEARS_PER_CENTURY;
103             }
104 0         0 ($y, $d);
105             } ] };
106             }
107 26249         32912 eval { timegm($sec,$min,$hour,$day,$month - 1,$year) + $leap + $delta };
  26249         67880  
108             }
109              
110             1;
111              
112             __END__