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.07'; |
4
|
3
|
|
|
3
|
|
180209
|
use 5.006; |
|
3
|
|
|
|
|
25
|
|
5
|
3
|
|
|
3
|
|
14
|
use strict; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
86
|
|
6
|
3
|
|
|
3
|
|
13
|
use warnings; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
76
|
|
7
|
3
|
|
|
3
|
|
1284
|
use parent 'Exporter'; |
|
3
|
|
|
|
|
803
|
|
|
3
|
|
|
|
|
15
|
|
8
|
3
|
|
|
3
|
|
143
|
use Carp; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
192
|
|
9
|
3
|
|
|
3
|
|
16
|
use Scalar::Util qw/ reftype /; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
1447
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
our @EXPORT_OK = qw(iso_week_number cpan_week_number); |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
sub iso_week_number |
14
|
|
|
|
|
|
|
{ |
15
|
24
|
|
|
24
|
1
|
9761
|
my $date = _dwim_date(@_); |
16
|
|
|
|
|
|
|
|
17
|
16
|
|
|
|
|
523
|
require Date::Calc; |
18
|
|
|
|
|
|
|
|
19
|
16
|
|
|
|
|
5466
|
my ($week, $year) = Date::Calc::Week_of_Year($date->{year}, $date->{month}, $date->{day}); |
20
|
|
|
|
|
|
|
|
21
|
16
|
|
|
|
|
87
|
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
|
12882
|
my $date = _dwim_date(@_); |
30
|
|
|
|
|
|
|
|
31
|
24
|
|
|
|
|
646
|
require POSIX; |
32
|
|
|
|
|
|
|
my $week_number = POSIX::strftime('%U', 0, 0, 12, |
33
|
|
|
|
|
|
|
$date->{day}, |
34
|
|
|
|
|
|
|
$date->{month}-1, |
35
|
24
|
|
|
|
|
6048
|
$date->{year}-1900); |
36
|
24
|
100
|
|
|
|
101
|
if ($week_number == 0) { |
37
|
6
|
|
|
|
|
20
|
$date->{year}--; |
38
|
6
|
|
|
|
|
121
|
$week_number = POSIX::strftime('%U', 0, 0, 12, 31, 11, $date->{year}-1900); |
39
|
|
|
|
|
|
|
} |
40
|
24
|
|
|
|
|
147
|
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
|
|
|
294
|
if (reftype($param) && reftype($param) eq 'HASH') { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
49
|
|
|
|
|
|
|
return $param if exists($param->{year}) |
50
|
|
|
|
|
|
|
&& exists($param->{month}) |
51
|
8
|
100
|
100
|
|
|
44
|
&& exists($param->{day}); |
|
|
|
100
|
|
|
|
|
52
|
6
|
|
|
|
|
648
|
croak "you must specify year, month and day\n"; |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
elsif (reftype($param)) { |
55
|
2
|
|
|
|
|
167
|
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
|
|
|
|
|
153
|
return { year => $1, month => $2, day => $3 }; |
59
|
|
|
|
|
|
|
} |
60
|
|
|
|
|
|
|
|
61
|
2
|
|
|
|
|
49
|
my @tm = gmtime($param); |
62
|
2
|
|
|
|
|
26
|
return { year => $tm[5] + 1900, month => $tm[4]+1, day => $tm[3] }; |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
elsif (@_ == 3) { |
66
|
2
|
|
|
|
|
6
|
my ($year, $month, $day) = @_; |
67
|
2
|
|
|
|
|
8
|
return { year => $year, month => $month, day => $day }; |
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
elsif (@_ == 6) { |
70
|
8
|
|
|
|
|
65
|
my $hashref = { @_ }; |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
return $hashref if exists($hashref->{year}) |
73
|
|
|
|
|
|
|
&& exists($hashref->{month}) |
74
|
8
|
100
|
100
|
|
|
50
|
&& exists($hashref->{day}); |
|
|
|
100
|
|
|
|
|
75
|
6
|
|
|
|
|
565
|
croak "you must specify year, month and day\n"; |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
else { |
78
|
2
|
|
|
|
|
162
|
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 2014-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
|
|
|
|
|
|
|
|