File Coverage

blib/lib/Month/Simple.pm
Criterion Covered Total %
statement 23 62 37.1
branch 0 10 0.0
condition 0 12 0.0
subroutine 8 22 36.3
pod 9 10 90.0
total 40 116 34.4


line stmt bran cond sub pod time code
1             package Month::Simple;
2              
3 1     1   20722 use 5.010;
  1         2  
4 1     1   4 use strict;
  1         1  
  1         15  
5 1     1   3 use warnings;
  1         4  
  1         28  
6 1     1   458 use Date::Simple qw/ymd/;
  1         5076  
  1         43  
7 1     1   438 use Time::Local qw/timelocal/;
  1         1100  
  1         48  
8 1     1   4 use Carp qw/croak/;
  1         1  
  1         30  
9              
10 1     1   564 use Data::Dumper;
  1         4631  
  1         141  
11              
12             our $VERSION = '0.04';
13              
14             use overload
15 0     0     q[""] => sub { my $d = shift->first_day; return substr "$d", 0, 7 },
  0            
16 0     0     '+' => sub { $_->[0]->delta($_[1]) },
17 0     0     '-' => sub { $_->[0]->delta(-$_[1]) },
18 0     0     cmp => sub { $_[0]->first_day cmp __PACKAGE__->new($_[1])->first_day },
19 1     1   5 ;
  1         1  
  1         9  
20              
21             sub new {
22 0     0 1   my ($class, $str) = @_;
23 0   0       $class = ref($class) || $class;
24 0 0 0       if (ref($str) && $str->isa('Date::Simple')) {
    0 0        
    0 0        
    0          
25 0           return bless { day => ymd($str->year, $str->month, 1) }, $class;
26             }
27             elsif ($str && $str =~ /^(\d{4})-?(\d{2})(?:-\d\d)?$/) {
28 0           return bless { day => ymd($1, $2, 1) }, $class;
29             }
30             elsif ($str && $str eq 'timestamp') {
31 0           my ($mon, $year) = (localtime $_[2])[4, 5];
32 0           return bless { day => ymd($year + 1900, $mon + 1, 1) }, $class;
33             }
34             elsif ($str) {
35 0           croak "Invalid month '$str' (valid: YYYY-MM, YYYYMM, YYYY-MM-DD)";
36             }
37             else {
38 0           my ($mon, $year) = (localtime $^T)[4, 5];
39 0           return bless { day => ymd($year + 1900, $mon + 1, 1) }, $class;
40             }
41             }
42              
43             sub first_day {
44 0     0 1   shift->{day};
45             }
46              
47             sub last_day {
48 0     0 0   shift->delta(1)->first_day - 1;
49             }
50              
51             sub delta {
52 0     0 1   my ($self, $delta) = @_;
53 0           $delta = int $delta;
54 0 0         return $self unless $delta;
55 0           my $d = $self->first_day;
56 0           while ($delta > 0) {
57             # there's no way we can advance more than one month
58             # when starting from the first of a month
59 0           $d += 31;
60 0           $d = ymd($d->year, $d->month, 1);
61             }
62             continue {
63 0           $delta--;
64             }
65 0           while ($delta < 0) {
66 0           $d--;
67 0           $d = ymd($d->year, $d->month, 1);
68             }
69             continue {
70 0           $delta++
71             }
72 0           return $self->new($d);
73             }
74              
75             sub first_second {
76 0     0 1   my $self = shift;
77 0           my $d = $self->first_day;
78 0           return timelocal(0, 0, 0, 1, $d->month - 1, $d->year - 1900);
79             }
80              
81             sub last_second {
82 0     0 1   my $self = shift;
83 0           $self->next->first_second - 1;
84             }
85              
86 0     0 1   sub month { shift->{day}->month }
87 0     0 1   sub year { shift->{day}->year }
88              
89 0     0 1   sub prev { shift->delta(-1) };
90 0     0 1   sub next { shift->delta(1) };
91              
92             =head1 NAME
93              
94             Month::Simple - Simple month-based date arithmetics
95              
96             =head1 VERSION
97              
98             Version 0.03
99              
100             =head1 SYNOPSIS
101              
102             use Month::Simple;
103              
104             my $month = Month::Simple->new();
105             my $prev = $month->prev;
106             my $stamp = $prev->first_second;
107             my $in_yr = $month->delta(12);
108              
109             =head1 METHODS
110              
111             =head2 new
112              
113             Month::Simple->new(); # current month, using $^T as base
114             Month::Simple->new('2011-01');
115             Month::Simple->new('2011-01-02'); # day is ignored
116             Month::Simple->new(timestamp => time); # extract month from UNIX timestamp
117              
118             Creates a new C object. If no argument is provided, the current
119             month (based on the startup of the script, i.e. based on C<$^T>) is returned.
120              
121             The argument can be a date in format C, C, C
122             or a L object. Days are ignored.
123              
124             =head2 prev
125              
126             Returns a new C object for the month before the invocant month.
127              
128             =head2 next
129              
130             Returns a new C object for the month after the invocant month.
131              
132             =head2 delta(N)
133              
134             Returns a new C object. For positive C, it goes forward C
135             months, and backwards for negative C.
136              
137             =head2 first_second
138              
139             Returns a UNIX timestamp for the first second of the month.
140              
141             =head2 last_second
142              
143             Returns a UNIX timestamp for the last second of the month.
144              
145             =head2 month
146              
147             Returns the month as an integer between 1 and 12.
148              
149             say Month::Simple->new(201602)->month; 2
150              
151             =head2 year
152              
153             Returns the year as an integer.
154              
155             say Month::Simple->new(201602)->year; 2016
156              
157             =head2 first_day
158              
159             Returns a L object for the first day of the month.
160              
161             =head1 State of this module
162              
163             This module has been in production usage for quite some time, and is
164             considered complete in the sense that no more features are planned.
165              
166             =head1 AUTHOR
167              
168             Moritz Lenz, C<< >> for the noris network AG.
169              
170             =head1 BUGS
171              
172             Please report any bugs or feature requests to C, or through
173             the web interface at L. I will be notified, and then you'll
174             automatically be notified of progress on your bug as I make changes.
175              
176              
177             =head1 SUPPORT
178              
179             You can find documentation for this module with the perldoc command.
180              
181             perldoc Month::Simple
182              
183              
184             You can also look for information at:
185              
186             =over 4
187              
188             =item * RT: CPAN's request tracker (report bugs here)
189              
190             L
191              
192             =item * AnnoCPAN: Annotated CPAN documentation
193              
194             L
195              
196             =item * CPAN Ratings
197              
198             L
199              
200             =item * Search CPAN
201              
202             L
203              
204             =back
205              
206             =head1 LICENSE AND COPYRIGHT
207              
208             Copyright 2013 Moritz Lenz.
209              
210             This program is free software; you can redistribute it and/or modify it
211             under the terms of either: the GNU General Public License as published
212             by the Free Software Foundation; or the Artistic License.
213              
214             See L for more information.
215              
216              
217             =cut
218              
219             1; # End of Month::Simple