File Coverage

blib/lib/Date/WeekNumber.pm
Criterion Covered Total %
statement 43 43 100.0
branch 18 18 100.0
condition 15 15 100.0
subroutine 9 9 100.0
pod 2 2 100.0
total 87 87 100.0


line stmt bran cond sub pod time code
1             package Date::WeekNumber;
2             # ABSTRACT: calculate week of the year (ISO 8601 weeks, or 'CPAN weeks')
3             $Date::WeekNumber::VERSION = '0.08';
4 3     3   173736 use 5.006;
  3         26  
5 3     3   16 use strict;
  3         6  
  3         51  
6 3     3   11 use warnings;
  3         4  
  3         58  
7 3     3   1170 use parent 'Exporter';
  3         819  
  3         17  
8 3     3   136 use Carp;
  3         9  
  3         187  
9 3     3   17 use Scalar::Util qw/ reftype /;
  3         4  
  3         1453  
10              
11             our @EXPORT_OK = qw(iso_week_number cpan_week_number);
12              
13             sub iso_week_number
14             {
15 24     24 1 9617 my $date = _dwim_date(@_);
16              
17 16         457 require Date::Calc;
18              
19 16         5171 my ($week, $year) = Date::Calc::Week_of_Year($date->{year}, $date->{month}, $date->{day});
20              
21 16         76 return sprintf('%.4d-W%.2d', $year, $week);
22             }
23              
24             # If %U returns a week number of 0, it means the day
25             # is actually in the final week of the year before.
26             # And by definition that's the same week number as 31st December
27             sub cpan_week_number
28             {
29 32     32 1 12964 my $date = _dwim_date(@_);
30              
31 24         537 require POSIX;
32             my $week_number = POSIX::strftime('%U', 0, 0, 12,
33             $date->{day},
34             $date->{month}-1,
35 24         6149 $date->{year}-1900);
36 24 100       90 if ($week_number == 0) {
37 6         19 $date->{year}--;
38 6         127 $week_number = POSIX::strftime('%U', 0, 0, 12, 31, 11, $date->{year}-1900);
39             }
40 24         148 return sprintf('%.4d-W%.2d', $date->{year}, $week_number);
41             }
42              
43             sub _dwim_date
44             {
45 56 100   56   148 if (@_ == 1) {
    100          
    100          
46 44         66 my $param = shift;
47              
48 44 100 100     295 if (reftype($param) && reftype($param) eq 'HASH') {
    100          
    100          
49             return $param if exists($param->{year})
50             && exists($param->{month})
51 8 100 100     39 && exists($param->{day});
      100        
52 6         582 croak "you must specify year, month and day\n";
53             }
54             elsif (reftype($param)) {
55 2         163 croak "you can't pass a reference of type ".reftype($param);
56             }
57             elsif ($param =~ /^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$/) {
58 32         142 return { year => $1, month => $2, day => $3 };
59             }
60              
61 2         42 my @tm = gmtime($param);
62 2         24 return { year => $tm[5] + 1900, month => $tm[4]+1, day => $tm[3] };
63              
64             }
65             elsif (@_ == 3) {
66 2         5 my ($year, $month, $day) = @_;
67 2         8 return { year => $year, month => $month, day => $day };
68             }
69             elsif (@_ == 6) {
70 8         20 my $hashref = { @_ };
71              
72             return $hashref if exists($hashref->{year})
73             && exists($hashref->{month})
74 8 100 100     48 && exists($hashref->{day});
      100        
75 6         603 croak "you must specify year, month and day\n";
76             }
77             else {
78 2         173 croak "invalid arguments\n";
79             }
80             }
81              
82             1;
83              
84             =head1 NAME
85              
86             Date::WeekNumber - calculate week of the year (ISO 8601 weeks, or 'CPAN weeks')
87              
88             =head1 SYNOPSIS
89              
90             use Date::WeekNumber qw/ cpan_week_number /;
91            
92             $week = cpan_week_number('2013-12-31'); # '2014-W01'
93             $week = cpan_week_number(time());
94             $week = cpan_week_number({ year => 2012, month => 12, day => 31});
95              
96             Or to get weeks according to ISO 8601:
97              
98             use Date::WeekNumber qw/ iso_week_number /;
99            
100             # pass parameters as for cpan_week_number() above
101              
102             =head1 DESCRIPTION
103              
104             The two functions provided by this module
105             can be used to generate the week number
106             in the year of a given date. For example:
107              
108             print "Today is in week ", iso_week_number(time()), "\n";
109              
110             Which at the time I'm writing this will print:
111              
112             Today is in week 2014-W09
113              
114             There are two functions provided: C returns the week number
115             according to ISO 8601, where the weeks run from Monday through Sunday,
116             and C, where the weeks run from Sunday through Saturday.
117             A more complete definition of the week naming schemes is given below.
118              
119             The CPAN week number is the definition used by Chris Madsen's
120             L contest,
121             and my L page.
122              
123             There are a number of modules that can be used to calculate the week
124             number, but I wanted a minimalist interface that returned a string format,
125             rather than the year and week number separately. Plus I sometimes have
126             an epoch and sometimes a date string, so I decided to experiment with
127             a DWIMish interface (Do What I Mean), where you could pass the date
128             in whatever format you have it available, and it'll be handled.
129              
130             =head1 Week numbering scheme
131              
132             =head2 iso_week_number
133              
134             The C function returns a string with the week number
135             according to ISO 8601.
136              
137             ISO 8601 defines week 01 as being the week with the first Thursday in it.
138             The first day of the week is Monday. Consider the transition from 2013 to 2014:
139              
140             December 2013 January 2014
141             Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
142             1 2 3 4 5 6 7 1 2 3 4
143             8 9 10 11 12 13 14 5 6 7 8 9 10 11
144             15 16 17 18 19 20 21 12 13 14 15 16 17 18
145             22 23 24 25 26 27 28 19 20 21 22 23 24 25
146             29 30 31 26 27 28 29 30 31
147              
148             So 2014-W01 runs from 30th December 2013 to 5th January 2014.
149              
150             Similarly, consider the transition from 2009 to 2010:
151              
152             December 2009 January 2010
153             Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
154             1 2 3 4 5 1 2
155             6 7 8 9 10 11 12 3 4 5 6 7 8 9
156             13 14 15 16 17 18 19 10 11 12 13 14 15 16
157             20 21 22 23 24 25 26 17 18 19 20 21 22 23
158             27 28 29 30 31 24 25 26 27 28 29 30
159             31
160              
161             In this case 2009-W52 runs runs 28th December 2009 through 3rd January 2010,
162             and 2010-W01 starts on Monday 4th January 2010.
163              
164             =head2 cpan_week_number
165              
166             The C function returns a string with the week number
167             according to 'CPAN Weeks'.
168              
169             CPAN Weeks run from Sunday to Saturday, with week 01 of the year being
170             the week containing the first Sunday in January. Consider the transition
171             from 2011 to 2012:
172              
173             December 2011 January 2012
174             Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
175             1 2 3 1 2 3 4 5 6 7
176             4 5 6 7 8 9 10 8 9 10 11 12 13 14
177             11 12 13 14 15 16 17 15 16 17 18 19 20 21
178             18 19 20 21 22 23 24 22 23 24 25 26 27 28
179             25 26 27 28 29 30 31 29 30 31
180              
181             Week 2012-W01 runs from Sunday 1st January to Saturday 7th January.
182              
183             Now look at the transition from 2006 to 2007:
184              
185             December 2006 January 2007
186             Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
187             1 2 1 2 3 4 5 6
188             3 4 5 6 7 8 9 7 8 9 10 11 12 13
189             10 11 12 13 14 15 16 14 15 16 17 18 19 20
190             17 18 19 20 21 22 23 21 22 23 24 25 26 27
191             24 25 26 27 28 29 30 28 29 30 31
192             31
193              
194             Week 2006-W53 runs from Sunday 31st December 2006 to Saturday 6th January 2007,
195             and 2007-W01 runs from Sunday 7th January to Saturday 13th January.
196              
197             =head1 SEE ALSO
198              
199             L provides a C function,
200             which returns the week number and associated year.
201             As of version 1.05 this return the ISO 8601 week number,
202             prior to that it returned something slightly different;
203             you can still request the old week numbering scheme.
204             Version 1.06 provided a mode for giving the output in the same
205             format as this module.
206              
207             L contains the C function,
208             which is used by Date::WeekNumber.
209              
210             L provides a C method, which returns
211             the ISO week number and associated year for a DateTime instance.
212             It also provides C.
213              
214             L provides C, which returns
215             the ISO week number and associated year.
216              
217             L provides a function C
218             which returns a week number between 0 and 53.
219             Zero means it's a week in the previous year,
220             and 53 I be in the following year.
221              
222             L provides a number of functions for converting
223             dates according to ISO 8601.
224              
225             L can be used to produce an ISO week number,
226             using the C and C methods.
227              
228             =head1 REPOSITORY
229              
230             L
231              
232             =head1 AUTHOR
233              
234             Neil Bowers Eneilb@cpan.orgE
235              
236             =head1 LICENSE AND COPYRIGHT
237              
238             This software is copyright (c) 2014 by Neil Bowers .
239              
240             This is free software; you can redistribute it and/or modify it under
241             the same terms as the Perl 5 programming language system itself.
242