File Coverage

blib/lib/Devel/Deprecations/Environmental/MicroDateTime.pm
Criterion Covered Total %
statement 43 43 100.0
branch 12 14 85.7
condition 8 9 88.8
subroutine 13 13 100.0
pod 0 5 0.0
total 76 84 90.4


line stmt bran cond sub pod time code
1             package # hah! take that PAUSE
2             Devel::Deprecations::Environmental::MicroDateTime;
3              
4 7     7   45 use strict;
  7         16  
  7         193  
5 7     7   36 use warnings;
  7         13  
  7         320  
6              
7             use overload (
8             '<=>' => '_spaceship',
9 36     36   91 bool => sub { 1 },
10 7         59 fallback => 1,
11 7     7   8480 );
  7         7224  
12              
13             our $VERSION = '1.101';
14              
15             sub _spaceship {
16 39     39   98 my($self, $other, $swap) = @_;
17 39 50       98 ($other, $self) = ($self, $other) if($swap);
18 39         90 $self->epoch() <=> $other->epoch();
19             }
20              
21             sub from_epoch {
22 46     46 0 292 my($class, %args) = @_;
23 46         280 return bless({ %args }, $class);
24             }
25              
26             # This exists only because Windows is a brain-dead piece of shit
27             # whose POSIX::strftime seems to not support %s to turn a list
28             # of second/minute/hour/day/month-1/year-1900 into epoch seconds
29             sub _to_epoch {
30 18     18   72 my($class, $year, $month, $day, $hour, $minute, $second) = @_;
31 18 50       67 die("Ancient history! $year\n") if($year < 1970);
32              
33 18         39 my $epoch = 0;
34 18         65 foreach my $this_year (1970 .. $year) {
35 124         296 my @month_days = (0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
36 124 100       226 $month_days[2] += 1 if($class->_is_leap($this_year));
37 124 100       439 $epoch += $class->_sum(0, @month_days[0 .. ($this_year < $year ? 12 : $month - 1)])
38             * 24 * 60 * 60;
39             }
40 18         56 $epoch += ($day - 1) * 24 * 60 * 60;
41 18         41 $epoch += $second + 60 * $minute + 60 * 60 * $hour;
42 18         75 return $epoch;
43             }
44              
45             sub _is_leap {
46 124     124   233 my($class, $year) = @_;
47 124 100 66     523 $year % 400 == 0 || ( $year % 4 == 0 && !($year % 100 == 0) );
48             }
49              
50             sub _sum {
51 1398     1398   2703 my($class, $head, @tail) = @_;
52 1398         2054 $head += shift(@tail);
53 1398 100       3539 return !@tail ? $head : $class->_sum($head, @tail);
54             }
55              
56             sub parse_datetime {
57 19     19 0 56 my($class, $dt_string) = @_;
58              
59 19 100       153 if($dt_string =~ /^
60             (\d{4}) -
61             (\d{2}) -
62             (\d{2})
63             (?:
64             (?:
65             T | \x20 # T or literal space
66             )
67             (\d{2}) :
68             (\d{2}) :
69             (\d{2})
70             )?
71             $/x) {
72 18         114 my($year, $month, $day, $hour, $minute, $second) = ($1, $2, $3, $4, $5, $6);
73 18   100     92 $hour ||= 0;
74 18   100     78 $minute ||= 0;
75 18   100     92 $second ||= 0;
76 18         67 return $class->from_epoch(epoch => $class->_to_epoch(
77             $year, $month, $day, $hour, $minute, $second
78             ));
79             }
80 1         22 die("'$dt_string' isn't a valid date/time");
81             }
82              
83 25     25 0 92 sub now { shift->from_epoch(epoch => time); }
84              
85             sub iso8601 {
86 3     3 0 2365 my $self = shift;
87              
88 3         58 my @time_components = (gmtime($self->{epoch}))[5, 4, 3, 2, 1, 0];
89 3         41 return sprintf(
90             "%04s-%02s-%02sT%02s:%02s:%02s",
91             $time_components[0] + 1900,
92             $time_components[1] + 1,
93             @time_components[2..5]
94             );
95             }
96              
97 78     78 0 285 sub epoch { shift->{epoch} }
98              
99             1;