File Coverage

lib/Time/Date.pm
Criterion Covered Total %
statement 69 112 61.6
branch 8 64 12.5
condition 6 26 23.0
subroutine 10 13 76.9
pod 8 8 100.0
total 101 223 45.2


line stmt bran cond sub pod time code
1             package Time::Date;
2              
3 1     1   20109 use 5.006;
  1         4  
4 1     1   4 use strict;
  1         2  
  1         19  
5 1     1   4 use warnings;
  1         6  
  1         35  
6 1     1   733 use POSIX ();
  1         7392  
  1         31  
7              
8 1     1   1327 use overload '""' => \&str;
  1         940  
  1         6  
9              
10             our $VERSION = "0.03";
11              
12             sub new {
13 1     1 1 21 my ($class, $str) = @_;
14 1 50       4 return undef if !$str;
15 1         12 $str =~ /^(\d{4})(-(\d+)(-(\d+)((\s+|T)(\d+)(:(\d+)(:(\d+)(\.(\d+))?)?)?)?)?)?(.*)$/;
16 1         3 my $year = $1;
17 1   50     5 my $mon = $3 || 1;
18 1   50     5 my $mday = $5 || 1;
19 1   50     4 my $hour = $8 || 0;
20 1   50     5 my $min = $10 || 0;
21 1   50     7 my $sec = $12 || 0;
22 1   50     5 my $msec = $14 || 0;
23 1         2 my $ampm = $15;
24 1 50       4 return undef if !defined $year;
25 1 50       7 if ($ampm =~ /^\s*am?$/i) {
    0          
    0          
26 1 50       5 $hour -= 12 if $hour == 12;
27             }
28             elsif ($ampm =~ /^\s*pm?$/i) {
29 0 0       0 $hour += 12 if $hour != 12;
30             }
31             elsif ($ampm !~ /^\s*$/) {
32 0         0 return undef;
33             }
34 1         2 $mon -= 1;
35 1         1 $year -= 1900;
36 1         14629 my $epoch = POSIX::mktime($sec, $min, $hour, $mday, $mon, $year, 0, 0, -1);
37 1 50       25 return undef if !defined $epoch;
38 1         15 my $self = bless {epoch => $epoch}, $class;
39 1         16 return $self;
40             }
41              
42             sub mktime {
43 0     0 1 0 my ($class, $year, $mon, $mday, $hour, $min, $sec, $wday, $yday, $isdst) = @_;
44 0   0     0 $sec ||= 0;
45 0   0     0 $min ||= 0;
46 0   0     0 $hour ||= 0;
47 0 0       0 $mday = defined $mday ? $mday : 1;
48 0   0     0 $mon ||= 0;
49 0   0     0 $year ||= 0;
50 0   0     0 $wday ||= 0;
51 0   0     0 $yday ||= 0;
52 0 0       0 $isdst = defined $isdst ? $isdst : -1;
53 0         0 my $epoch = POSIX::mktime($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst);
54 0 0       0 return undef if !defined $epoch;
55 0         0 my $self = bless {epoch => $epoch}, $class;
56 0         0 return $self;
57             }
58              
59             sub new_epoch {
60 1     1 1 282 my ($class, $epoch) = @_;
61 1         10 my $self = bless {epoch => $epoch}, $class;
62 1         4 return $self;
63             }
64              
65             sub now {
66 1     1 1 4 my ($class) = @_;
67 1         6 my $self = bless {epoch => time}, $class;
68 1         4 return $self;
69             }
70              
71             sub str {
72 3     3 1 881 my ($self) = @_;
73 3         4166 my $str = POSIX::strftime("%Y-%m-%d %H:%M:%S", localtime($self->{epoch}));
74 3         66 return $str;
75             }
76              
77             sub strftime {
78 0     0 1 0 my ($self, $fmt) = @_;
79 0         0 my $str = POSIX::strftime($fmt, localtime($self->{epoch}));
80 0         0 return $str;
81             }
82              
83             my $now;
84             sub natural {
85 0     0 1 0 my ($self) = @_;
86 0 0       0 $now = time if !$now;
87 0         0 my $delta = $now - $self->{epoch};
88 0 0       0 if ($delta < -32 * 24 * 60 * 60) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
89 0         0 return POSIX::strftime("%b %Y", localtime($self->{epoch}));
90             }
91             elsif ($delta < -2 * 24 * 60 * 60) {
92 0         0 return "in " . int(-$delta / (24 * 60 * 60)) . " days";
93             }
94             elsif ($delta < -24 * 60 * 60) {
95 0         0 return "in 1 day";
96             }
97             elsif ($delta < -2 * 60 * 60) {
98 0         0 return "in " . int(-$delta / (60 * 60)) . " hours";
99             }
100             elsif ($delta < -60 * 60) {
101 0         0 return "in 1 hour";
102             }
103             elsif ($delta < -2 * 60) {
104 0         0 return "in " . int(-$delta / 60) . " minutes";
105             }
106             elsif ($delta < -60) {
107 0         0 return "in 1 minute";
108             }
109             elsif ($delta < -1) {
110 0         0 return "in $delta seconds";
111             }
112             elsif ($delta < 0) {
113 0         0 return "in 1 second";
114             }
115             elsif ($delta < 1) {
116 0         0 return "right now";
117             }
118             elsif ($delta < 2) {
119 0         0 return "1 second ago";
120             }
121 0 0       0 if ($delta < 60) {
    0          
    0          
    0          
    0          
    0          
    0          
122 0         0 return "$delta seconds ago";
123             }
124             elsif ($delta < 2 * 60) {
125 0         0 return "1 minute ago";
126             }
127             elsif ($delta < 60 * 60) {
128 0         0 return int($delta / 60) . " minutes ago";
129             }
130             elsif ($delta < 2 * 60 * 60) {
131 0         0 return "1 hour ago";
132             }
133             elsif ($delta < 24 * 60 * 60) {
134 0         0 return int($delta / (60 * 60)) . " hours ago";
135             }
136             elsif ($delta < 2 * 24 * 60 * 60) {
137 0         0 return "1 day ago";
138             }
139             elsif ($delta < 32 * 24 * 60 * 60) {
140 0         0 return int($delta / (24 * 60 * 60)) . " days ago";
141             }
142             else {
143 0         0 return POSIX::strftime("%b %Y", localtime($self->{epoch}));
144             }
145             }
146              
147             sub time_zones {
148 1     1 1 3 my %time_zones;
149 1 50       102 open my $fh, "<", "/usr/share/zoneinfo/zone.tab" or return [];
150 1         812 while (my $line = <$fh>) {
151 440 100       1724 $line =~ m{^[A-Z]{2}\s+\S+\s+(\w+)/(\S+)} or next;
152 416         629 my $region = $1;
153 416         668 my $name = $2;
154 416         761 my $zone = "$region/$name";
155 416         581 $name =~ s{_}{ }g;
156 416         586 $name =~ s{/}{ - }g;
157 416         482 push @{$time_zones{$region}}, {zone => $zone, name => $name};
  416         2351  
158             }
159 1         13 close $fh;
160 1         3 my @time_zones;
161 1         4 push @time_zones, {name => "Local", zone => ""};
162 1         2 my $i = 0;
163 1         14 for my $region (sort keys %time_zones) {
164 10         37 push @time_zones, {region => $region, i => $i};
165 10         12 $i++;
166 10         14 my @zones = sort {$a->{name} cmp $b->{name}} @{$time_zones{$region}};
  2014         2961  
  10         60  
167 10         91 push @time_zones, @zones;
168             }
169 1         5 push @time_zones, {region => "UTC", i => $i};
170 1         5 for my $offset (qw{
171             -12 -11:30 -11 -10:30 -10 -9:30 -8:30 -8 -7:30 -7 -6:30 -6 -5:30
172             -5 -4:30 -4 -3:30 -3 -2:30 -2 -1:30 -1 -0:30 +0 +0:30 +1 +1:30
173             +2 +2:30 +3 +3:30 +4 +4:30 +5 +5:30 +6 +6:30 +7 +7:30 +8 +8:30
174             +9 +9:30 +10 +10:30 +11 +11:30 +12}) {
175 48         172 push @time_zones, {zone => "UTC$offset", name => "UTC$offset"};
176             }
177 1         22 return \@time_zones;
178             }
179              
180             1;
181              
182             __END__