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   51 use strict;
  7         15  
  7         197  
5 7     7   41 use warnings;
  7         25  
  7         341  
6              
7             use overload (
8             '<=>' => '_spaceship',
9 36     36   88 bool => sub { 1 },
10 7         61 fallback => 1,
11 7     7   8789 );
  7         7141  
12              
13             our $VERSION = '1.000';
14              
15             sub _spaceship {
16 39     39   95 my($self, $other, $swap) = @_;
17 39 50       107 ($other, $self) = ($self, $other) if($swap);
18 39         90 $self->epoch() <=> $other->epoch();
19             }
20              
21             sub from_epoch {
22 46     46 0 329 my($class, %args) = @_;
23 46         283 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   70 my($class, $year, $month, $day, $hour, $minute, $second) = @_;
31 18 50       102 die("Ancient history! $year\n") if($year < 1970);
32              
33 18         41 my $epoch = 0;
34 18         63 foreach my $this_year (1970 .. $year) {
35 124         299 my @month_days = (0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
36 124 100       250 $month_days[2] += 1 if($class->_is_leap($this_year));
37 124 100       443 $epoch += $class->_sum(0, @month_days[0 .. ($this_year < $year ? 12 : $month - 1)])
38             * 24 * 60 * 60;
39             }
40 18         53 $epoch += ($day - 1) * 24 * 60 * 60;
41 18         38 $epoch += $second + 60 * $minute + 60 * 60 * $hour;
42 18         66 return $epoch;
43             }
44              
45             sub _is_leap {
46 124     124   264 my($class, $year) = @_;
47 124 100 66     496 $year % 400 == 0 || ( $year % 4 == 0 && !($year % 100 == 0) );
48             }
49              
50             sub _sum {
51 1398     1398   2675 my($class, $head, @tail) = @_;
52 1398         2124 $head += shift(@tail);
53 1398 100       3767 return !@tail ? $head : $class->_sum($head, @tail);
54             }
55              
56             sub parse_datetime {
57 19     19 0 55 my($class, $dt_string) = @_;
58              
59 19 100       156 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         115 my($year, $month, $day, $hour, $minute, $second) = ($1, $2, $3, $4, $5, $6);
73 18   100     93 $hour //= 0;
74 18   100     119 $minute //= 0;
75 18   100     90 $second //= 0;
76 18         121 return $class->from_epoch(epoch => $class->_to_epoch(
77             $year, $month, $day, $hour, $minute, $second
78             ));
79             }
80 1         13 die("'$dt_string' isn't a valid date/time");
81             }
82              
83 25     25 0 78 sub now { shift->from_epoch(epoch => time); }
84              
85             sub iso8601 {
86 3     3 0 2511 my $self = shift;
87              
88 3         64 my @time_components = (gmtime($self->{epoch}))[5, 4, 3, 2, 1, 0];
89 3         43 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 281 sub epoch { shift->{epoch} }
98              
99             1;