File Coverage

lib/Time/Date.pm
Criterion Covered Total %
statement 45 114 39.4
branch 6 62 9.6
condition 6 26 23.0
subroutine 10 14 71.4
pod 9 9 100.0
total 76 225 33.7


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